diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 06939361e..000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Ignore list
-/*
-
-# Do not ignore these folders:
-!__tests__/
-!src/
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 293128e6e..000000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
-module.exports = {
- extends: [
- 'eslint:recommended',
- 'plugin:@typescript-eslint/recommended',
- 'plugin:eslint-plugin-jest/recommended',
- 'eslint-config-prettier'
- ],
- parser: '@typescript-eslint/parser',
- plugins: ['@typescript-eslint', 'eslint-plugin-node', 'eslint-plugin-jest'],
- rules: {
- '@typescript-eslint/no-require-imports': 'error',
- '@typescript-eslint/no-non-null-assertion': 'off',
- '@typescript-eslint/no-explicit-any': 'off',
- '@typescript-eslint/no-empty-function': 'off',
- '@typescript-eslint/ban-ts-comment': [
- 'error',
- {
- 'ts-ignore': 'allow-with-description'
- }
- ],
- 'no-console': 'error',
- 'yoda': 'error',
- 'prefer-const': [
- 'error',
- {
- destructuring: 'all'
- }
- ],
- 'no-control-regex': 'off',
- 'no-constant-condition': ['error', {checkLoops: false}],
- 'node/no-extraneous-import': 'error'
- },
- overrides: [
- {
- files: ['**/*{test,spec}.ts'],
- rules: {
- '@typescript-eslint/no-unused-vars': 'off',
- 'jest/no-standalone-expect': 'off',
- 'jest/no-conditional-expect': 'off',
- 'no-console': 'off',
-
- }
- }
- ],
- env: {
- node: true,
- es6: true,
- 'jest/globals': true
- }
-};
diff --git a/.github/ISSUE_TEMPLATE/new_distribution_request.md b/.github/ISSUE_TEMPLATE/new_distribution_request.md
new file mode 100644
index 000000000..f5d7c7faf
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/new_distribution_request.md
@@ -0,0 +1,22 @@
+---
+name: New Java distribution template
+about: Suggest a new Java distribution
+title: ''
+labels: feature request, needs triage
+assignees: ''
+---
+
+**Description:**
+Describe your proposal.
+
+**Justification:**
+Justification or a use case for your proposal.
+
+**Download URL:**
+Download URL for the new distribution.
+
+**License:**
+Link to the license for the new distribution.
+
+**Are you willing to submit a PR?**
+
\ No newline at end of file
diff --git a/.github/PULL_REQUEST_TEMPLATE/new_distribution_pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/new_distribution_pull_request_template.md
new file mode 100644
index 000000000..4e3b44372
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/new_distribution_pull_request_template.md
@@ -0,0 +1,16 @@
+**Description:**
+Describe your changes.
+
+**Related issue:**
+Add link to the related issue.
+
+**Download URL:**
+Download URL for the new distribution.
+
+**License:**
+Link to the license for the new distribution.
+
+**Check list:**
+- [ ] Mark if documentation changes are required.
+- [ ] Mark if tests were added or updated to cover the changes.
+- [ ] Mark if new distribution is being added.
\ No newline at end of file
diff --git a/.github/java.json b/.github/java.json
index eda1b0cd4..5e52ab819 100644
--- a/.github/java.json
+++ b/.github/java.json
@@ -9,6 +9,31 @@
"message": 3
}
]
+ },
+ {
+ "owner": "javac",
+ "pattern": [
+ {
+ "regexp": "^([^:]+):(\\d+): (warning|error): (.+?)$",
+ "file": 1,
+ "line": 2,
+ "severity": 3,
+ "message": 4
+ }
+ ]
+ },
+ {
+ "owner": "maven-javac",
+ "pattern": [
+ {
+ "regexp": "^\\[(WARNING|ERROR)\\]\\s+(.+?\\.java):\\[(\\d+),(\\d+)\\]\\s+(.+)$",
+ "severity": 1,
+ "file": 2,
+ "line": 3,
+ "column": 4,
+ "message": 5
+ }
+ ]
}
]
-}
\ No newline at end of file
+}
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ef54acadd..dcf4beaaf 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -5,5 +5,6 @@ Describe your changes.
Add link to the related issue.
**Check list:**
+- [ ] Ran `npm run check` locally (format, lint, build, test) and all checks pass.
- [ ] Mark if documentation changes are required.
- [ ] Mark if tests were added or updated to cover the changes.
\ No newline at end of file
diff --git a/.github/workflows/basic-validation.yml b/.github/workflows/basic-validation.yml
index e93e58009..ea70e0577 100644
--- a/.github/workflows/basic-validation.yml
+++ b/.github/workflows/basic-validation.yml
@@ -11,6 +11,9 @@ on:
paths-ignore:
- '**.md'
+permissions:
+ contents: read
+
jobs:
call-basic-validation:
name: Basic validation
diff --git a/.github/workflows/benchmark-cache-restore.yml b/.github/workflows/benchmark-cache-restore.yml
new file mode 100644
index 000000000..e79d76dbd
--- /dev/null
+++ b/.github/workflows/benchmark-cache-restore.yml
@@ -0,0 +1,209 @@
+name: Benchmark cache restore
+
+on:
+ workflow_dispatch:
+ inputs:
+ baseline-ref:
+ description: Git ref containing the sequential restore implementation
+ required: true
+ default: main
+ type: string
+ candidate-ref:
+ description: Git ref containing the concurrent restore implementation (defaults to the dispatched ref)
+ required: false
+ type: string
+
+permissions:
+ contents: read
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ warm-caches:
+ name: Warm ${{ matrix.tool }} ${{ matrix.profile }} caches (${{ matrix.os }})
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
+ tool: [maven, gradle]
+ profile: [small, large]
+ steps:
+ - name: Checkout benchmark workflow
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Checkout baseline
+ uses: actions/checkout@v7
+ with:
+ path: baseline
+ persist-credentials: false
+ ref: ${{ inputs.baseline-ref }}
+ - name: Checkout candidate
+ uses: actions/checkout@v7
+ with:
+ path: candidate
+ persist-credentials: false
+ ref: ${{ inputs.candidate-ref || github.ref }}
+ - name: Prepare benchmark inputs
+ run: bash __tests__/benchmark-cache-restore.sh prepare "${{ matrix.tool }}" "${{ matrix.profile }}"
+ - name: Prepare cache save
+ uses: ./candidate
+ with:
+ distribution: temurin
+ java-version: '17'
+ cache: ${{ matrix.tool }}
+ cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
+ - name: Populate benchmark caches
+ run: |
+ bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
+ bash __tests__/benchmark-cache-restore.sh populate "${{ matrix.tool }}" "${{ matrix.profile }}"
+
+ benchmark:
+ name: Benchmark ${{ matrix.tool }} ${{ matrix.profile }} (${{ matrix.os }})
+ needs: warm-caches
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
+ tool: [maven, gradle]
+ profile: [small, large]
+ steps:
+ - name: Checkout benchmark workflow
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Checkout baseline
+ uses: actions/checkout@v7
+ with:
+ path: baseline
+ persist-credentials: false
+ ref: ${{ inputs.baseline-ref }}
+ - name: Checkout candidate
+ uses: actions/checkout@v7
+ with:
+ path: candidate
+ persist-credentials: false
+ ref: ${{ inputs.candidate-ref || github.ref }}
+ - name: Prepare benchmark inputs
+ run: bash __tests__/benchmark-cache-restore.sh prepare "${{ matrix.tool }}" "${{ matrix.profile }}"
+
+ - name: Reset caches for baseline iteration 1
+ run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
+ - name: Start baseline iteration 1 timer
+ run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
+ - name: Restore with baseline iteration 1
+ id: baseline-1
+ uses: ./baseline
+ with:
+ distribution: temurin
+ java-version: '17'
+ cache: ${{ matrix.tool }}
+ cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
+ cache-read-only: true
+ - name: Record baseline iteration 1
+ env:
+ CACHE_HIT: ${{ steps.baseline-1.outputs.cache-hit }}
+ run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" baseline 1 "$CACHE_HIT"
+
+ - name: Reset caches for candidate iteration 1
+ run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
+ - name: Start candidate iteration 1 timer
+ run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
+ - name: Restore with candidate iteration 1
+ id: candidate-1
+ uses: ./candidate
+ with:
+ distribution: temurin
+ java-version: '17'
+ cache: ${{ matrix.tool }}
+ cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
+ cache-read-only: true
+ - name: Record candidate iteration 1
+ env:
+ CACHE_HIT: ${{ steps.candidate-1.outputs.cache-hit }}
+ run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" candidate 1 "$CACHE_HIT"
+
+ - name: Reset caches for candidate iteration 2
+ run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
+ - name: Start candidate iteration 2 timer
+ run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
+ - name: Restore with candidate iteration 2
+ id: candidate-2
+ uses: ./candidate
+ with:
+ distribution: temurin
+ java-version: '17'
+ cache: ${{ matrix.tool }}
+ cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
+ cache-read-only: true
+ - name: Record candidate iteration 2
+ env:
+ CACHE_HIT: ${{ steps.candidate-2.outputs.cache-hit }}
+ run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" candidate 2 "$CACHE_HIT"
+
+ - name: Reset caches for baseline iteration 2
+ run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
+ - name: Start baseline iteration 2 timer
+ run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
+ - name: Restore with baseline iteration 2
+ id: baseline-2
+ uses: ./baseline
+ with:
+ distribution: temurin
+ java-version: '17'
+ cache: ${{ matrix.tool }}
+ cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
+ cache-read-only: true
+ - name: Record baseline iteration 2
+ env:
+ CACHE_HIT: ${{ steps.baseline-2.outputs.cache-hit }}
+ run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" baseline 2 "$CACHE_HIT"
+
+ - name: Reset caches for baseline iteration 3
+ run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
+ - name: Start baseline iteration 3 timer
+ run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
+ - name: Restore with baseline iteration 3
+ id: baseline-3
+ uses: ./baseline
+ with:
+ distribution: temurin
+ java-version: '17'
+ cache: ${{ matrix.tool }}
+ cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
+ cache-read-only: true
+ - name: Record baseline iteration 3
+ env:
+ CACHE_HIT: ${{ steps.baseline-3.outputs.cache-hit }}
+ run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" baseline 3 "$CACHE_HIT"
+
+ - name: Reset caches for candidate iteration 3
+ run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
+ - name: Start candidate iteration 3 timer
+ run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
+ - name: Restore with candidate iteration 3
+ id: candidate-3
+ uses: ./candidate
+ with:
+ distribution: temurin
+ java-version: '17'
+ cache: ${{ matrix.tool }}
+ cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
+ cache-read-only: true
+ - name: Record candidate iteration 3
+ env:
+ CACHE_HIT: ${{ steps.candidate-3.outputs.cache-hit }}
+ run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" candidate 3 "$CACHE_HIT"
+
+ - name: Summarize benchmark
+ run: bash __tests__/benchmark-cache-restore.sh summarize "${{ matrix.tool }}" "$GITHUB_STEP_SUMMARY"
+ - name: Upload raw timings
+ uses: actions/upload-artifact@v7
+ with:
+ name: cache-restore-${{ matrix.os }}-${{ matrix.tool }}-${{ matrix.profile }}
+ path: .benchmark-results/timings.csv
+ if-no-files-found: error
diff --git a/.github/workflows/check-dist.yml b/.github/workflows/check-dist.yml
index 90ef986ad..5592249e7 100644
--- a/.github/workflows/check-dist.yml
+++ b/.github/workflows/check-dist.yml
@@ -11,6 +11,9 @@ on:
- '**.md'
workflow_dispatch:
+permissions:
+ contents: read
+
jobs:
call-check-dist:
name: Check dist/
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 7a8261238..598f7de5d 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -8,7 +8,13 @@ on:
schedule:
- cron: '0 3 * * 0'
+permissions: {}
+
jobs:
call-codeQL-analysis:
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
name: CodeQL analysis
uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main
diff --git a/.github/workflows/e2e-cache-dependency-path.yml b/.github/workflows/e2e-cache-dependency-path.yml
deleted file mode 100644
index 6d926299b..000000000
--- a/.github/workflows/e2e-cache-dependency-path.yml
+++ /dev/null
@@ -1,93 +0,0 @@
-name: Validate cache with cache-dependency-path option
-
-on:
- push:
- branches:
- - main
- - releases/*
- paths-ignore:
- - '**.md'
- pull_request:
- paths-ignore:
- - '**.md'
-
-defaults:
- run:
- shell: bash
-
-jobs:
- gradle1-save:
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- steps:
- - name: Checkout
- uses: actions/checkout@v5
- - name: Run setup-java with the cache for gradle
- uses: ./
- id: setup-java
- with:
- distribution: 'adopt'
- java-version: '17'
- cache: gradle
- cache-dependency-path: __tests__/cache/gradle1/*.gradle*
- - name: Create files to cache
- # Need to avoid using Gradle daemon to stabilize the save process on Windows
- # https://github.com/actions/cache/issues/454#issuecomment-840493935
- run: |
- gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
- if [ ! -d ~/.gradle/caches ]; then
- echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
- exit 1
- fi
- gradle1-restore:
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- needs: gradle1-save
- steps:
- - name: Checkout
- uses: actions/checkout@v5
- - name: Run setup-java with the cache for gradle
- uses: ./
- id: setup-java
- with:
- distribution: 'adopt'
- java-version: '11'
- cache: gradle
- cache-dependency-path: __tests__/cache/gradle1/*.gradle*
- - name: Confirm that ~/.gradle/caches directory has been made
- run: |
- if [ ! -d ~/.gradle/caches ]; then
- echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
- exit 1
- fi
- ls ~/.gradle/caches/
- gradle2-restore:
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- needs: gradle1-save
- steps:
- - name: Checkout
- uses: actions/checkout@v5
- - name: Run setup-java with the cache for gradle
- uses: ./
- id: setup-java
- with:
- distribution: 'adopt'
- java-version: '11'
- cache: gradle
- cache-dependency-path: __tests__/cache/gradle2/*.gradle*
- - name: Confirm that ~/.gradle/caches directory has not been made
- run: |
- if [ -d ~/.gradle/caches ]; then
- echo "::error::The ~/.gradle/caches directory exists unexpectedly"
- exit 1
- fi
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index e4fd46c19..394a8bccd 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -11,6 +11,9 @@ on:
paths-ignore:
- '**.md'
+permissions:
+ contents: read
+
defaults:
run:
shell: bash
@@ -21,15 +24,17 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-latest]
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '17'
cache: gradle
- name: Create files to cache
@@ -37,81 +42,83 @@ jobs:
# https://github.com/actions/cache/issues/454#issuecomment-840493935
run: |
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
- if [ ! -d ~/.gradle/caches ]; then
- echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
- exit 1
- fi
+ mkdir -p "$HOME/.gradle/wrapper/dists/setup-java-e2e"
+ echo "gradle wrapper cache" > "$HOME/.gradle/wrapper/dists/setup-java-e2e/payload"
+ bash __tests__/check-dir.sh "$HOME/.gradle/caches"
+ bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
gradle-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-latest]
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
needs: gradle-save
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
cache: gradle
+ cache-read-only: true
- name: Confirm that ~/.gradle/caches directory has been made
- run: |
- if [ ! -d ~/.gradle/caches ]; then
- echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
- exit 1
- fi
- ls ~/.gradle/caches/
+ run: bash __tests__/check-dir.sh "$HOME/.gradle/caches"
+ - name: Confirm that the Gradle Wrapper cache has been restored
+ run: bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
maven-save:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-latest]
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Run setup-java with the cache for maven
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
cache: maven
- name: Create files to cache
run: |
mvn verify -f __tests__/cache/maven/pom.xml
- if [ ! -d ~/.m2/repository ]; then
- echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
- exit 1
- fi
+ mkdir -p "$HOME/.m2/wrapper/dists/setup-java-e2e"
+ echo "maven wrapper cache" > "$HOME/.m2/wrapper/dists/setup-java-e2e/payload"
+ bash __tests__/check-dir.sh "$HOME/.m2/repository"
+ bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
maven-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-latest]
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
needs: maven-save
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Run setup-java with the cache for maven
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
cache: maven
+ cache-read-only: true
- name: Confirm that ~/.m2/repository directory has been made
- run: |
- if [ ! -d ~/.m2/repository ]; then
- echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
- exit 1
- fi
- ls ~/.m2/repository
+ run: bash __tests__/check-dir.sh "$HOME/.m2/repository"
+ - name: Confirm that the Maven Wrapper cache has been restored
+ run: bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
sbt-save:
runs-on: ${{ matrix.os }}
defaults:
@@ -121,19 +128,21 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-22.04]
+ os: [macos-15-intel, windows-latest, ubuntu-22.04]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Run setup-java with the cache for sbt
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
cache: sbt
- name: Setup SBT
- if: matrix.os == 'macos-13'
+ if: matrix.os == 'macos-15-intel'
run: |
echo ""Installing SBT...""
brew install sbt
@@ -141,26 +150,14 @@ jobs:
run: sbt update
- name: Check files to cache on macos-latest
- if: matrix.os == 'macos-13'
- run: |
- if [ ! -d ~/Library/Caches/Coursier ]; then
- echo "::error::The ~/Library/Caches/Coursier directory does not exist unexpectedly"
- exit 1
- fi
+ if: matrix.os == 'macos-15-intel'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
- name: Check files to cache on windows-latest
if: matrix.os == 'windows-latest'
- run: |
- if [ ! -d ~/AppData/Local/Coursier/Cache ]; then
- echo "::error::The ~/AppData/Local/Coursier/Cache directory does not exist unexpectedly"
- exit 1
- fi
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
- name: Check files to cache on ubuntu-latest
- if: matrix.os == 'ubuntu-latest'
- run: |
- if [ ! -d ~/.cache/coursier ]; then
- echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
- exit 1
- fi
+ if: matrix.os == 'ubuntu-22.04'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
sbt-restore:
runs-on: ${{ matrix.os }}
defaults:
@@ -170,40 +167,331 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-22.04]
+ os: [macos-15-intel, windows-latest, ubuntu-22.04]
needs: sbt-save
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Run setup-java with the cache for sbt
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
cache: sbt
+ cache-read-only: true
- name: Confirm that ~/Library/Caches/Coursier directory has been made
- if: matrix.os == 'macos-13'
- run: |
- if [ ! -d ~/Library/Caches/Coursier ]; then
- echo "::error::The ~/Library/Caches/Coursier directory does not exist unexpectedly"
- exit 1
- fi
- ls ~/Library/Caches/Coursier
+ if: matrix.os == 'macos-15-intel'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
if: matrix.os == 'windows-latest'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
+ - name: Confirm that ~/.cache/coursier directory has been made
+ if: matrix.os == 'ubuntu-22.04'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
+ gradle1-save:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-latest, windows-latest, ubuntu-latest]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for gradle
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '17'
+ cache: gradle
+ cache-dependency-path: __tests__/cache/gradle1/*.gradle*
+ - name: Create files to cache
+ # Need to avoid using Gradle daemon to stabilize the save process on Windows
+ # https://github.com/actions/cache/issues/454#issuecomment-840493935
+ run: |
+ gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
+ mkdir -p "$HOME/.gradle/wrapper/dists/setup-java-e2e-gradle1"
+ echo "gradle wrapper cache gradle1" > "$HOME/.gradle/wrapper/dists/setup-java-e2e-gradle1/payload"
+ bash __tests__/check-dir.sh "$HOME/.gradle/caches"
+ bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
+ gradle1-restore:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-latest, windows-latest, ubuntu-latest]
+ needs: gradle1-save
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for gradle
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: gradle
+ cache-dependency-path: __tests__/cache/gradle1/*.gradle*
+ - name: Confirm that ~/.gradle/caches directory has been made
+ run: bash __tests__/check-dir.sh "$HOME/.gradle/caches"
+ - name: Confirm that the Gradle Wrapper cache has been restored
+ run: bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
+ gradle2-restore:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-latest, windows-latest, ubuntu-latest]
+ needs: gradle1-save
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for gradle
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: gradle
+ cache-dependency-path: __tests__/cache/gradle2/*.gradle*
+ - name: Confirm that ~/.gradle/caches directory has not been made
+ run: bash __tests__/check-dir.sh "$HOME/.gradle/caches" absent
+ maven1-save:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for maven
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: maven
+ cache-dependency-path: __tests__/cache/maven/pom.xml
+ - name: Create files to cache
+ run: |
+ mvn verify -f __tests__/cache/maven/pom.xml
+ mkdir -p "$HOME/.m2/wrapper/dists/setup-java-e2e-maven1"
+ echo "maven wrapper cache maven1" > "$HOME/.m2/wrapper/dists/setup-java-e2e-maven1/payload"
+ bash __tests__/check-dir.sh "$HOME/.m2/repository"
+ bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
+ maven1-restore:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
+ needs: maven1-save
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for maven
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: maven
+ cache-dependency-path: __tests__/cache/maven/pom.xml
+ - name: Confirm that ~/.m2/repository directory has been made
+ run: bash __tests__/check-dir.sh "$HOME/.m2/repository"
+ - name: Confirm that the Maven Wrapper cache has been restored
+ run: bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
+ maven2-restore:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
+ needs: maven1-save
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for maven
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: maven
+ cache-dependency-path: |
+ __tests__/cache/maven2/pom.xml
+ README.md
+ - name: Confirm that ~/.m2/repository directory has not been made
+ run: bash __tests__/check-dir.sh "$HOME/.m2/repository" absent
+ sbt1-save:
+ runs-on: ${{ matrix.os }}
+ defaults:
+ run:
+ shell: bash
+ working-directory: __tests__/cache/sbt
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-22.04]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for sbt
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: sbt
+ cache-dependency-path: __tests__/cache/sbt/*.sbt
+ - name: Setup SBT
+ if: matrix.os == 'macos-15-intel'
run: |
- if [ ! -d ~/AppData/Local/Coursier/Cache ]; then
- echo "::error::The ~/AppData/Local/Coursier/Cache directory does not exist unexpectedly"
- exit 1
- fi
- ls ~/AppData/Local/Coursier/Cache
+ echo ""Installing SBT...""
+ brew install sbt
+ - name: Create files to cache
+ run: sbt update
+
+ - name: Check files to cache on macos-latest
+ if: matrix.os == 'macos-15-intel'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
+ - name: Check files to cache on windows-latest
+ if: matrix.os == 'windows-latest'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
+ - name: Check files to cache on ubuntu-latest
+ if: matrix.os == 'ubuntu-22.04'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
+ sbt1-restore:
+ runs-on: ${{ matrix.os }}
+ defaults:
+ run:
+ shell: bash
+ working-directory: __tests__/cache/sbt
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-22.04]
+ needs: sbt1-save
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for sbt
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: sbt
+ cache-dependency-path: __tests__/cache/sbt/*.sbt
+
+ - name: Confirm that ~/Library/Caches/Coursier directory has been made
+ if: matrix.os == 'macos-15-intel'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
+ - name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
+ if: matrix.os == 'windows-latest'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
- name: Confirm that ~/.cache/coursier directory has been made
- if: matrix.os == 'ubuntu-latest'
+ if: matrix.os == 'ubuntu-22.04'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
+ sbt2-restore:
+ runs-on: ${{ matrix.os }}
+ defaults:
+ run:
+ shell: bash
+ working-directory: __tests__/cache/sbt2
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-15-intel, windows-latest, ubuntu-22.04]
+ needs: sbt1-save
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with the cache for sbt
+ uses: ./
+ id: setup-java
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: sbt
+ cache-dependency-path: __tests__/cache/sbt2/*.sbt
+
+ - name: Confirm that ~/Library/Caches/Coursier directory has not been made
+ if: matrix.os == 'macos-15-intel'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier" absent
+ - name: Confirm that ~/AppData/Local/Coursier/Cache directory has not been made
+ if: matrix.os == 'windows-latest'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache" absent
+ - name: Confirm that ~/.cache/coursier directory has not been made
+ if: matrix.os == 'ubuntu-22.04'
+ run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier" absent
+ custom-maven-path-save:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with a custom Maven cache path
+ uses: ./
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: maven
+ cache-dependency-path: |
+ __tests__/cache/maven2/pom.xml
+ .github/workflows/e2e-cache.yml
+ cache-path: |
+ ${{ runner.temp }}/setup-java-custom-maven-repository
+ !${{ runner.temp }}/setup-java-custom-maven-repository/**/*.lastUpdated
+ - name: Populate the custom Maven repository
run: |
- if [ ! -d ~/.cache/coursier ]; then
- echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
- exit 1
- fi
- ls ~/.cache/coursier
+ mvn -Dmaven.repo.local="$RUNNER_TEMP/setup-java-custom-maven-repository" verify -f __tests__/cache/maven2/pom.xml
+ touch "$RUNNER_TEMP/setup-java-custom-maven-repository/setup-java-cache-path-marker"
+ bash __tests__/check-dir.sh "$RUNNER_TEMP/setup-java-custom-maven-repository"
+ custom-maven-path-restore:
+ runs-on: ubuntu-latest
+ needs: custom-maven-path-save
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: Run setup-java with a custom Maven cache path
+ uses: ./
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ cache: maven
+ cache-dependency-path: |
+ __tests__/cache/maven2/pom.xml
+ .github/workflows/e2e-cache.yml
+ cache-path: |
+ ${{ runner.temp }}/setup-java-custom-maven-repository
+ !${{ runner.temp }}/setup-java-custom-maven-repository/**/*.lastUpdated
+ cache-read-only: true
+ - name: Confirm that the custom Maven repository has been restored
+ run: test -f "$RUNNER_TEMP/setup-java-custom-maven-repository/setup-java-cache-path-marker"
diff --git a/.github/workflows/e2e-local-file.yml b/.github/workflows/e2e-local-file.yml
index 45d7912d3..657334ce0 100644
--- a/.github/workflows/e2e-local-file.yml
+++ b/.github/workflows/e2e-local-file.yml
@@ -11,44 +11,10 @@ on:
paths-ignore:
- '**.md'
-jobs:
- setup-java-local-file-adopt:
- name: Validate installation from local file Adopt
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- steps:
- - name: Checkout
- uses: actions/checkout@v5
- - name: Download Adopt OpenJDK file
- run: |
- if ($IsLinux) {
- $downloadUrl = "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz"
- $localFilename = "java_package.tar.gz"
- } elseif ($IsMacOS) {
- $downloadUrl = "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz"
- $localFilename = "java_package.tar.gz"
- } elseif ($IsWindows) {
- $downloadUrl = "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_windows_hotspot_11.0.10_9.zip"
- $localFilename = "java_package.zip"
- }
- echo "LocalFilename=$localFilename" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- (New-Object System.Net.WebClient).DownloadFile($downloadUrl, "$env:RUNNER_TEMP/$localFilename")
- shell: pwsh
- - name: setup-java
- uses: ./
- id: setup-java
- with:
- distribution: 'jdkfile'
- jdkFile: ${{ runner.temp }}/${{ env.LocalFilename }}
- java-version: '11.0.0-ea'
- architecture: x64
- - name: Verify Java version
- run: bash __tests__/verify-java.sh "11.0.10" "${{ steps.setup-java.outputs.path }}"
- shell: bash
+permissions:
+ contents: read
+jobs:
setup-java-local-file-zulu:
name: Validate installation from local file Zulu
runs-on: ${{ matrix.os }}
@@ -58,7 +24,9 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Download Zulu OpenJDK file
run: |
if ($IsLinux) {
@@ -79,11 +47,13 @@ jobs:
id: setup-java
with:
distribution: 'jdkfile'
- jdkFile: ${{ runner.temp }}/${{ env.LocalFilename }}
+ jdk-file: ${{ runner.temp }}/${{ env.LocalFilename }}
java-version: '11.0.0-ea'
architecture: x64
- name: Verify Java version
- run: bash __tests__/verify-java.sh "11.0" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "11.0" "$JAVA_PATH"
shell: bash
setup-java-local-file-temurin:
@@ -95,7 +65,9 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Download Eclipse Temurin file
run: |
if ($IsLinux) {
@@ -116,9 +88,12 @@ jobs:
id: setup-java
with:
distribution: 'jdkfile'
+ # Intentionally uses the deprecated `jdkFile` alias to keep it covered.
jdkFile: ${{ runner.temp }}/${{ env.LocalFilename }}
java-version: '11.0.0-ea'
architecture: x64
- name: Verify Java version
- run: bash __tests__/verify-java.sh "11.0.12" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "11.0.12" "$JAVA_PATH"
shell: bash
diff --git a/.github/workflows/e2e-publishing.yml b/.github/workflows/e2e-publishing.yml
index d3163a92f..4dcab4117 100644
--- a/.github/workflows/e2e-publishing.yml
+++ b/.github/workflows/e2e-publishing.yml
@@ -11,6 +11,9 @@ on:
paths-ignore:
- '**.md'
+permissions:
+ contents: read
+
defaults:
run:
shell: pwsh
@@ -25,29 +28,43 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: setup-java
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
server-id: maven
- server-username: MAVEN_USERNAME
- server-password: MAVEN_CENTRAL_TOKEN
- gpg-passphrase: MAVEN_GPG_PASSPHRASE
+ server-username-env-var: MAVEN_USERNAME
+ server-password-env-var: MAVEN_CENTRAL_TOKEN
+ gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
- name: Validate settings.xml
run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
Get-Content $xmlPath | ForEach-Object { Write-Host $_ }
- [xml]$xml = Get-Content $xmlPath
- $servers = $xml.settings.servers.server
- if (($servers[0].id -ne 'maven') -or ($servers[0].username -ne '${env.MAVEN_USERNAME}') -or ($servers[0].password -ne '${env.MAVEN_CENTRAL_TOKEN}')) {
- throw "Generated XML file is incorrect"
- }
+ $content = [System.IO.File]::ReadAllText($xmlPath)
+ $expected = @(
+ ''
+ ' false'
+ ' '
+ ' '
+ ' maven'
+ ' ${env.MAVEN_USERNAME}'
+ ' ${env.MAVEN_CENTRAL_TOKEN}'
+ ' '
+ ' '
+ ''
+ ) -join "`n"
- if (($servers[1].id -ne 'gpg.passphrase') -or ($servers[1].passphrase -ne '${env.MAVEN_GPG_PASSPHRASE}')) {
+ if ($content -ne $expected) {
+ Write-Host "Expected settings.xml:"
+ $expected -split "`n" | ForEach-Object { Write-Host $_ }
throw "Generated XML file is incorrect"
}
@@ -60,7 +77,9 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Create fake settings.xml
run: |
$xmlDirectory = Join-Path $HOME ".m2"
@@ -71,12 +90,12 @@ jobs:
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
server-id: maven
- server-username: MAVEN_USERNAME
- server-password: MAVEN_CENTRAL_TOKEN
- gpg-passphrase: MAVEN_GPG_PASSPHRASE
+ server-username-env-var: MAVEN_USERNAME
+ server-password-env-var: MAVEN_CENTRAL_TOKEN
+ gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
- name: Validate settings.xml is overwritten
run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
@@ -96,7 +115,9 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Create fake settings.xml
run: |
$xmlDirectory = Join-Path $HOME ".m2"
@@ -107,13 +128,13 @@ jobs:
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
server-id: maven
- server-username: MAVEN_USERNAME
- server-password: MAVEN_CENTRAL_TOKEN
+ server-username-env-var: MAVEN_USERNAME
+ server-password-env-var: MAVEN_CENTRAL_TOKEN
overwrite-settings: false
- gpg-passphrase: MAVEN_GPG_PASSPHRASE
+ gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
- name: Validate that settings.xml is not overwritten
run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
@@ -133,17 +154,19 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: setup-java
uses: ./
id: setup-java
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '11'
server-id: maven
- server-username: MAVEN_USERNAME
- server-password: MAVEN_CENTRAL_TOKEN
- gpg-passphrase: MAVEN_GPG_PASSPHRASE
+ server-username-env-var: MAVEN_USERNAME
+ server-password-env-var: MAVEN_CENTRAL_TOKEN
+ gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
settings-path: ${{ runner.temp }}
- name: Validate settings.xml location
run: |
diff --git a/.github/workflows/e2e-smoke.yml b/.github/workflows/e2e-smoke.yml
new file mode 100644
index 000000000..fed3adf72
--- /dev/null
+++ b/.github/workflows/e2e-smoke.yml
@@ -0,0 +1,87 @@
+name: Validate Java e2e smoke
+
+on:
+ push:
+ branches:
+ - main
+ paths-ignore:
+ - '**.md'
+ pull_request:
+ paths-ignore:
+ - '**.md'
+
+permissions:
+ contents: read
+
+jobs:
+ setup-java:
+ name: ${{ matrix.distribution }} ${{ matrix.version }} (${{ matrix.java-package }}) - ${{ matrix.os }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - os: macos-latest
+ distribution: temurin
+ version: '11'
+ java-package: jdk
+ - os: windows-latest
+ distribution: temurin
+ version: '17'
+ java-package: jdk
+ - os: ubuntu-latest
+ distribution: temurin
+ version: '21'
+ java-package: jdk
+ - os: macos-latest
+ distribution: temurin
+ version: '25'
+ java-package: jdk
+ - os: windows-latest
+ distribution: temurin
+ version: '25'
+ java-package: jdk
+ - os: ubuntu-latest
+ distribution: temurin
+ version: '25'
+ java-package: jdk
+ - os: macos-latest
+ distribution: microsoft
+ version: '25'
+ java-package: jdk
+ - os: windows-latest
+ distribution: microsoft
+ version: '25'
+ java-package: jdk
+ - os: ubuntu-latest
+ distribution: microsoft
+ version: '25'
+ java-package: jdk
+ - os: ubuntu-latest
+ distribution: zulu
+ version: '17'
+ java-package: jre
+ - os: ubuntu-latest
+ distribution: liberica
+ version: '21'
+ java-package: jdk+fx
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+ - name: setup-java
+ uses: ./
+ id: setup-java
+ with:
+ java-version: ${{ matrix.version }}
+ java-package: ${{ matrix.java-package }}
+ distribution: ${{ matrix.distribution }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Verify Java
+ env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
+ shell: bash
diff --git a/.github/workflows/e2e-versions.yml b/.github/workflows/e2e-versions.yml
index 67238ee9d..2d38d55d1 100644
--- a/.github/workflows/e2e-versions.yml
+++ b/.github/workflows/e2e-versions.yml
@@ -3,28 +3,27 @@ name: Validate Java e2e
on:
push:
branches:
- - main
- releases/*
paths-ignore:
- '**.md'
- pull_request:
- paths-ignore:
- - '**.md'
schedule:
- cron: '0 */12 * * *'
workflow_dispatch:
+
+permissions:
+ contents: read
+
jobs:
setup-java-major-versions:
- name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
+ name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-latest]
- distribution: [
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
+ distribution:
+ [
'temurin',
- 'adopt',
- 'adopt-openj9',
'zulu',
'liberica',
'microsoft',
@@ -32,17 +31,46 @@ jobs:
'corretto',
'dragonwell',
'sapmachine',
- 'jetbrains'
- ] # internally 'adopt-hotspot' is the same as 'adopt'
+ 'jetbrains',
+ 'kona',
+ 'liberica-nik'
+ ]
version: ['21', '11', '17']
exclude:
- distribution: microsoft
version: 8
- distribution: dragonwell
- os: macos-13
+ os: macos-15-intel
include:
+ - distribution: microsoft
+ os: windows-latest
+ version: 25
+ - distribution: microsoft
+ os: ubuntu-latest
+ version: 25
+ - distribution: microsoft
+ os: macos-latest
+ version: 25
+ - distribution: kona
+ os: windows-latest
+ version: 25
+ - distribution: kona
+ os: ubuntu-latest
+ version: 25
+ - distribution: kona
+ os: macos-latest
+ version: 25
+ - distribution: liberica-nik
+ os: windows-latest
+ version: 25
+ - distribution: liberica-nik
+ os: ubuntu-latest
+ version: 25
+ - distribution: liberica-nik
+ os: macos-latest
+ version: 25
- distribution: oracle
- os: macos-13
+ os: macos-15-intel
version: 17
- distribution: oracle
os: windows-latest
@@ -50,6 +78,15 @@ jobs:
- distribution: oracle
os: ubuntu-latest
version: 21
+ - distribution: oracle-openjdk
+ os: macos-15-intel
+ version: 21
+ - distribution: oracle-openjdk
+ os: windows-latest
+ version: 21
+ - distribution: oracle-openjdk
+ os: ubuntu-latest
+ version: 21
- distribution: graalvm
os: macos-latest
version: 17.0.12
@@ -63,8 +100,11 @@ jobs:
os: ubuntu-latest
version: '24-ea'
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - &checkout_step
+ name: Checkout
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: setup-java
uses: ./
id: setup-java
@@ -74,17 +114,69 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ SETUP_JAVA_VERSION: ${{ steps.setup-java.outputs.version }}
+ REQUIRE_CONCRETE_VERSION: ${{ (matrix.distribution == 'oracle' || matrix.distribution == 'graalvm') && !contains(matrix.version, '.') && !contains(matrix.version, '-ea') }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH" "$SETUP_JAVA_VERSION" "$REQUIRE_CONCRETE_VERSION"
+ shell: bash
+
+ setup-java-checksum-verification:
+ name: Corretto checksum verification - ubuntu-latest
+ runs-on: ubuntu-latest
+ steps:
+ - *checkout_step
+ - name: setup-java with forced download
+ uses: ./
+ id: setup-java
+ with:
+ java-version: '21'
+ distribution: corretto
+ force-download: true
+ - name: Verify Java
+ env:
+ JAVA_VERSION: '21'
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
+ shell: bash
+
+ setup-java-alpine-linux:
+ name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - alpine-linux - ${{ matrix.os }}
+ runs-on: ${{ matrix.os }}
+ container:
+ image: alpine:3.21
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest]
+ distribution: ['temurin', 'sapmachine']
+ version: ['21', '17']
+ steps:
+ - *checkout_step
+ - name: Install bash
+ run: apk add --no-cache bash
+ - name: setup-java
+ uses: ./
+ id: setup-java
+ with:
+ java-version: ${{ matrix.version }}
+ distribution: ${{ matrix.distribution }}
+ - name: Verify Java
+ env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
setup-java-major-minor-versions:
- name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
+ name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
needs: setup-java-major-versions
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
+ os: &default_os [macos-latest, windows-latest, ubuntu-latest]
distribution: ['temurin', 'zulu', 'liberica']
version:
- '11.0'
@@ -113,8 +205,7 @@ jobs:
os: ubuntu-latest
version: '17.0.7'
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: setup-java
uses: ./
id: setup-java
@@ -122,10 +213,12 @@ jobs:
java-version: ${{ matrix.version }}
distribution: ${{ matrix.distribution }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
- shell: bash
env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
+ shell: bash
setup-java-check-latest:
name: ${{ matrix.distribution }} ${{ matrix.version }} - check-latest flag - ${{ matrix.os }}
@@ -134,7 +227,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
+ os: *default_os
distribution:
[
'temurin',
@@ -148,8 +241,7 @@ jobs:
- distribution: dragonwell
os: macos-latest
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: setup-java
uses: ./
id: setup-java
@@ -160,7 +252,9 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "11" "$JAVA_PATH"
shell: bash
setup-java-multiple-jdks:
@@ -170,7 +264,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
+ os: *default_os
distribution:
[
'temurin',
@@ -184,8 +278,7 @@ jobs:
- distribution: dragonwell
os: macos-latest
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: setup-java
uses: ./
id: setup-java
@@ -198,10 +291,11 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify Java env variables
run: |
+ $javaArch = if ($env:RUNNER_ARCH -eq "ARM64") { "AARCH64" } else { $env:RUNNER_ARCH }
$versionsArr = "11","17"
foreach ($version in $versionsArr)
{
- $envName = "JAVA_HOME_${version}_${env:RUNNER_ARCH}"
+ $envName = "JAVA_HOME_${version}_${javaArch}"
$JavaVersionPath = [Environment]::GetEnvironmentVariable($envName)
if (-not (Test-Path "$JavaVersionPath")) {
Write-Host "$envName is not found"
@@ -210,73 +304,73 @@ jobs:
}
shell: pwsh
- name: Verify Java
- run: bash __tests__/verify-java.sh "17" "${{ steps.setup-java.outputs.path }}"
- shell: bash
-
- setup-java-ea-versions-zulu:
- name: zulu ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
- needs: setup-java-major-minor-versions
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [macos-13, windows-latest, ubuntu-latest]
- version: ['17-ea', '15.0.0-ea.14']
- steps:
- - name: Checkout
- uses: actions/checkout@v5
- - name: setup-java
- uses: ./
- id: setup-java
- with:
- java-version: ${{ matrix.version }}
- distribution: zulu
- - name: Verify Java
- run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "17" "$JAVA_PATH"
shell: bash
- setup-java-ea-versions-temurin:
- name: temurin ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
+ setup-java-ea-versions:
+ name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- version: ['17-ea']
+ include:
+ - {os: macos-15-intel, version: '17-ea', distribution: zulu}
+ - {os: windows-latest, version: '17-ea', distribution: zulu}
+ - {os: ubuntu-latest, version: '17-ea', distribution: zulu}
+ - {os: macos-15-intel, version: '15.0.0-ea.14', distribution: zulu}
+ - {os: windows-latest, version: '15.0.0-ea.14', distribution: zulu}
+ - {os: ubuntu-latest, version: '15.0.0-ea.14', distribution: zulu}
+ - {os: macos-latest, version: '17-ea', distribution: temurin}
+ - {os: windows-latest, version: '17-ea', distribution: temurin}
+ - {os: ubuntu-latest, version: '17-ea', distribution: temurin}
+ - {os: macos-latest, version: '17-ea', distribution: sapmachine}
+ - {os: windows-latest, version: '17-ea', distribution: sapmachine}
+ - {os: ubuntu-latest, version: '17-ea', distribution: sapmachine}
+ - {os: macos-latest, version: '21-ea', distribution: sapmachine}
+ - {os: windows-latest, version: '21-ea', distribution: sapmachine}
+ - {os: ubuntu-latest, version: '21-ea', distribution: sapmachine}
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: setup-java
uses: ./
id: setup-java
with:
java-version: ${{ matrix.version }}
- distribution: temurin
+ distribution: ${{ matrix.distribution }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
- setup-java-ea-versions-sapmachine:
- name: sapmachine ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
+ setup-java-signature-verification:
+ name: ${{ matrix.distribution }} ${{ matrix.version }} signature verification - ${{ matrix.os }}
needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- version: ['17-ea', '21-ea']
+ os: *default_os
+ version: ['21', '17']
+ distribution: [temurin, microsoft]
steps:
- - name: Checkout
- uses: actions/checkout@v5
- - name: setup-java
+ - *checkout_step
+ - name: setup-java with signature verification
uses: ./
id: setup-java
with:
java-version: ${{ matrix.version }}
- distribution: sapmachine
+ distribution: ${{ matrix.distribution }}
+ verify-signature: true
- name: Verify Java
- run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
setup-java-custom-package-type:
@@ -286,7 +380,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-13, windows-latest, ubuntu-latest]
+ os: [macos-15-intel, windows-latest, ubuntu-latest]
distribution:
['temurin', 'zulu', 'liberica', 'semeru', 'sapmachine', 'jetbrains']
java-package: ['jre']
@@ -308,6 +402,10 @@ jobs:
java-package: jre+fx
version: '11'
os: ubuntu-latest
+ - distribution: 'liberica-nik'
+ java-package: jdk+fx
+ version: '21'
+ os: ubuntu-latest
- distribution: 'corretto'
java-package: jre
version: '8'
@@ -354,8 +452,7 @@ jobs:
os: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: setup-java
uses: ./
id: setup-java
@@ -366,7 +463,10 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
# Only Liberica and Zulu provide x86
@@ -382,8 +482,7 @@ jobs:
distribution: ['liberica', 'zulu', 'corretto']
version: ['11']
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: setup-java
uses: ./
id: setup-java
@@ -392,21 +491,42 @@ jobs:
java-version: ${{ matrix.version }}
architecture: 'x86'
- name: Verify Java
- run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_VERSION: ${{ matrix.version }}
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
+ setup-java-unsupported-platform:
+ name: Reject unsupported Oracle x86 on Linux
+ runs-on: ubuntu-latest
+ steps:
+ - *checkout_step
+ - name: Attempt unsupported setup
+ id: unsupported-setup
+ continue-on-error: true
+ uses: ./
+ with:
+ distribution: oracle
+ java-version: '21'
+ architecture: x86
+ - name: Verify setup was rejected
+ if: always()
+ env:
+ SETUP_OUTCOME: ${{ steps.unsupported-setup.outcome }}
+ run: test "$SETUP_OUTCOME" = failure
+
setup-java-version-both-version-inputs-presents:
name: ${{ matrix.distribution }} version (should be from input) - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
+ os: *default_os
distribution: ['temurin', 'microsoft', 'corretto']
java-version-file: ['.java-version', '.tool-versions']
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: Create .java-version file
shell: bash
run: echo "17" > .java-version
@@ -421,7 +541,9 @@ jobs:
java-version: 11
java-version-file: ${{matrix.java-version-file }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "11" "$JAVA_PATH"
shell: bash
setup-java-version-from-file-major-notation:
@@ -430,12 +552,11 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
+ os: *default_os
distribution: ['temurin', 'zulu', 'liberica', 'microsoft', 'corretto']
java-version-file: ['.java-version', '.tool-versions']
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: Create .java-version file
shell: bash
run: echo "11" > .java-version
@@ -449,7 +570,9 @@ jobs:
distribution: ${{ matrix.distribution }}
java-version-file: ${{matrix.java-version-file }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "11" "$JAVA_PATH"
shell: bash
setup-java-version-from-file-major-minor-patch-notation:
@@ -458,12 +581,11 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- distribution: ['adopt', 'adopt-openj9', 'zulu']
+ os: *default_os
+ distribution: ['temurin', 'zulu']
java-version-file: ['.java-version', '.tool-versions']
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: Create .java-version file
shell: bash
run: echo "17.0.10" > .java-version
@@ -477,27 +599,31 @@ jobs:
distribution: ${{ matrix.distribution }}
java-version-file: ${{matrix.java-version-file }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "17.0.10" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "17.0.10" "$JAVA_PATH"
shell: bash
setup-java-version-from-file-major-minor-patch-with-dist:
- name: ${{ matrix.distribution }} version from file 'openjdk64-17.0.10' - ${{ matrix.os }}
+ name: ${{ matrix.distribution }} version from file '${{ matrix.java-version-file }}' - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os: [macos-latest, windows-latest, ubuntu-latest]
- distribution: ['adopt', 'zulu', 'liberica']
- java-version-file: ['.java-version', '.tool-versions']
+ os: *default_os
+ distribution: ['temurin', 'zulu', 'liberica']
+ java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc']
steps:
- - name: Checkout
- uses: actions/checkout@v5
+ - *checkout_step
- name: Create .java-version file
shell: bash
run: echo "openjdk64-17.0.10" > .java-version
- name: Create .tool-versions file
shell: bash
run: echo "java openjdk64-17.0.10" > .tool-versions
+ - name: Create .sdkmanrc file
+ shell: bash
+ run: echo "java=17.0.10-tem" > .sdkmanrc
- name: setup-java
uses: ./
id: setup-java
@@ -505,5 +631,86 @@ jobs:
distribution: ${{ matrix.distribution }}
java-version-file: ${{matrix.java-version-file }}
- name: Verify Java
- run: bash __tests__/verify-java.sh "17.0.10" "${{ steps.setup-java.outputs.path }}"
+ env:
+ JAVA_PATH: ${{ steps.setup-java.outputs.path }}
+ run: bash __tests__/verify-java.sh "17.0.10" "$JAVA_PATH"
+ shell: bash
+
+ setup-java-set-default:
+ name: set-default option - ${{ matrix.os }}
+ needs: setup-java-major-versions
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: *default_os
+ steps:
+ - *checkout_step
+ - name: Setup Java 17 as default
+ uses: ./
+ id: setup-java-17
+ with:
+ distribution: 'temurin'
+ java-version: '17'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Setup Java 21 without setting as default
+ uses: ./
+ id: setup-java-21
+ with:
+ distribution: 'temurin'
+ java-version: '21'
+ set-default: false
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Verify JAVA_HOME still points to Java 17
+ env:
+ JAVA_17_PATH: ${{ steps.setup-java-17.outputs.path }}
+ run: |
+ echo "JAVA_HOME=$JAVA_HOME"
+ echo "Java 17 path=$JAVA_17_PATH"
+ if [ "$JAVA_HOME" != "$JAVA_17_PATH" ]; then
+ echo "JAVA_HOME should still point to Java 17"
+ exit 1
+ fi
+ shell: bash
+ - name: Verify java -version reports Java 17
+ run: |
+ JAVA_VERSION=$(java -version 2>&1 | head -1)
+ echo "java -version: $JAVA_VERSION"
+ if ! echo "$JAVA_VERSION" | grep -q "17"; then
+ echo "Default java should still be version 17"
+ exit 1
+ fi
+ shell: bash
+ - name: Verify JAVA_HOME_21 env var is set
+ run: |
+ $javaArch = if ($env:RUNNER_ARCH -eq "ARM64") { "AARCH64" } else { $env:RUNNER_ARCH }
+ $envName = "JAVA_HOME_21_${javaArch}"
+ $JavaVersionPath = [Environment]::GetEnvironmentVariable($envName)
+ if (-not $JavaVersionPath) {
+ Write-Host "$envName is not set"
+ exit 1
+ }
+ if (-not (Test-Path "$JavaVersionPath")) {
+ Write-Host "$envName path does not exist: $JavaVersionPath"
+ exit 1
+ }
+ Write-Host "$envName=$JavaVersionPath"
+ shell: pwsh
+ - name: Verify Java 21 outputs are set
+ env:
+ JAVA_21_PATH: ${{ steps.setup-java-21.outputs.path }}
+ JAVA_21_VERSION: ${{ steps.setup-java-21.outputs.version }}
+ run: |
+ echo "Java 21 path=$JAVA_21_PATH"
+ echo "Java 21 version=$JAVA_21_VERSION"
+ if [ -z "$JAVA_21_PATH" ]; then
+ echo "Java 21 path output should be set"
+ exit 1
+ fi
+ if [ -z "$JAVA_21_VERSION" ]; then
+ echo "Java 21 version output should be set"
+ exit 1
+ fi
shell: bash
diff --git a/.github/workflows/licensed.yml b/.github/workflows/licensed.yml
index 37f1560c3..b5d009cb5 100644
--- a/.github/workflows/licensed.yml
+++ b/.github/workflows/licensed.yml
@@ -9,6 +9,9 @@ on:
- main
workflow_dispatch:
+permissions:
+ contents: read
+
jobs:
call-licensed:
name: Licensed
diff --git a/.github/workflows/publish-immutable-actions.yml b/.github/workflows/publish-immutable-actions.yml
index ba3ffdee3..3888f9a85 100644
--- a/.github/workflows/publish-immutable-actions.yml
+++ b/.github/workflows/publish-immutable-actions.yml
@@ -5,6 +5,8 @@ on:
types: [released]
workflow_dispatch:
+permissions: {}
+
jobs:
publish:
runs-on: ubuntu-latest
@@ -15,7 +17,9 @@ jobs:
steps:
- name: Checking out
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: Publish
id: publish
uses: actions/publish-immutable-action@v0.0.4
diff --git a/.github/workflows/release-new-action-version.yml b/.github/workflows/release-new-action-version.yml
index e58e9063f..25192b640 100644
--- a/.github/workflows/release-new-action-version.yml
+++ b/.github/workflows/release-new-action-version.yml
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Update the ${{ env.TAG_NAME }} tag
id: update-major-tag
- uses: actions/publish-action@v0.3.0
+ uses: actions/publish-action@v0.4.0
with:
source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
diff --git a/.github/workflows/update-config-files.yml b/.github/workflows/update-config-files.yml
index 87af50042..bacdc74ec 100644
--- a/.github/workflows/update-config-files.yml
+++ b/.github/workflows/update-config-files.yml
@@ -5,7 +5,12 @@ on:
- cron: '0 3 * * 0'
workflow_dispatch:
+permissions: {}
+
jobs:
call-update-configuration-files:
name: Update configuration files
+ permissions:
+ contents: write # to push the branch with updated configuration files
+ pull-requests: write # to open/update the configuration update PR
uses: actions/reusable-workflows/.github/workflows/update-config-files.yml@main
diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml
new file mode 100644
index 000000000..2009e6e70
--- /dev/null
+++ b/.github/workflows/zizmor.yml
@@ -0,0 +1,48 @@
+name: Security analysis with zizmor
+
+on:
+ push:
+ branches:
+ - main
+ - releases/*
+ paths-ignore:
+ - '**.md'
+ pull_request:
+ paths-ignore:
+ - '**.md'
+ workflow_dispatch:
+
+permissions: {}
+
+jobs:
+ zizmor:
+ name: Analyze workflows with zizmor
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ security-events: write # to upload SARIF results to code scanning
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
+
+ - name: Set up Python
+ uses: actions/setup-python@v7
+ with:
+ python-version: '3.x'
+
+ - name: Install zizmor
+ run: pip install zizmor
+
+ - name: Run zizmor
+ run: zizmor --format sarif .github/workflows/ > zizmor.sarif
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Upload SARIF results to code scanning
+ if: always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
+ uses: github/codeql-action/upload-sarif@v4
+ with:
+ sarif_file: zizmor.sarif
+ category: zizmor
diff --git a/.github/zizmor.yml b/.github/zizmor.yml
new file mode 100644
index 000000000..38309ec47
--- /dev/null
+++ b/.github/zizmor.yml
@@ -0,0 +1,11 @@
+# Configuration for zizmor (https://docs.zizmor.sh)
+rules:
+ unpinned-uses:
+ config:
+ # First-party GitHub-maintained actions are trusted and referenced by
+ # major-version tags (the convention used across the actions org).
+ # Any third-party action must be pinned to a full commit SHA.
+ policies:
+ actions/*: ref-pin
+ github/*: ref-pin
+ '*': hash-pin
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100755
index 000000000..2312dc587
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1 @@
+npx lint-staged
diff --git a/.husky/pre-push b/.husky/pre-push
new file mode 100755
index 000000000..192cb67eb
--- /dev/null
+++ b/.husky/pre-push
@@ -0,0 +1 @@
+npm run build && npm test
diff --git a/.licensed.yml b/.licensed.yml
index e97382c4d..7f17bb852 100644
--- a/.licensed.yml
+++ b/.licensed.yml
@@ -10,6 +10,11 @@ allowed:
- mit
- cc0-1.0
- unlicense
+ - blueoak-1.0.0
reviewed:
- npm:
\ No newline at end of file
+ npm:
+ - "@actions/http-client" # MIT (license text present), but detected as "other"
+ - "argparse" # Python Software Foundation License (PSF), but detected as "other"
+ - "balanced-match"
+ - "brace-expansion"
diff --git a/.licenses/npm/@actions/cache.dep.yml b/.licenses/npm/@actions/cache.dep.yml
index f70b140d2..9433ea0f0 100644
--- a/.licenses/npm/@actions/cache.dep.yml
+++ b/.licenses/npm/@actions/cache.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/cache"
-version: 4.0.3
+version: 6.2.0
type: npm
summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
diff --git a/.licenses/npm/@actions/core.dep.yml b/.licenses/npm/@actions/core.dep.yml
index 09e099f71..081715159 100644
--- a/.licenses/npm/@actions/core.dep.yml
+++ b/.licenses/npm/@actions/core.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/core"
-version: 1.11.1
+version: 3.0.1
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core
diff --git a/.licenses/npm/@actions/exec.dep.yml b/.licenses/npm/@actions/exec.dep.yml
index cbc5abd39..003562f8b 100644
--- a/.licenses/npm/@actions/exec.dep.yml
+++ b/.licenses/npm/@actions/exec.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/exec"
-version: 1.1.1
+version: 3.0.0
type: npm
summary: Actions exec lib
homepage: https://github.com/actions/toolkit/tree/main/packages/exec
diff --git a/.licenses/npm/@actions/glob-0.1.2.dep.yml b/.licenses/npm/@actions/glob-0.1.2.dep.yml
deleted file mode 100644
index becb37de2..000000000
--- a/.licenses/npm/@actions/glob-0.1.2.dep.yml
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: "@actions/glob"
-version: 0.1.2
-type: npm
-summary: Actions glob lib
-homepage: https://github.com/actions/toolkit/tree/main/packages/glob
-license: mit
-licenses:
-- sources: LICENSE.md
- text: |-
- The MIT License (MIT)
-
- Copyright 2019 GitHub
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-notices: []
diff --git a/.licenses/npm/@actions/glob-0.5.0.dep.yml b/.licenses/npm/@actions/glob.dep.yml
similarity index 98%
rename from .licenses/npm/@actions/glob-0.5.0.dep.yml
rename to .licenses/npm/@actions/glob.dep.yml
index f7bf0793a..24d3f6916 100644
--- a/.licenses/npm/@actions/glob-0.5.0.dep.yml
+++ b/.licenses/npm/@actions/glob.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/glob"
-version: 0.5.0
+version: 0.7.0
type: npm
summary: Actions glob lib
homepage: https://github.com/actions/toolkit/tree/main/packages/glob
diff --git a/.licenses/npm/@actions/http-client.dep.yml b/.licenses/npm/@actions/http-client.dep.yml
index 1bf161b7b..dc741537d 100644
--- a/.licenses/npm/@actions/http-client.dep.yml
+++ b/.licenses/npm/@actions/http-client.dep.yml
@@ -1,10 +1,10 @@
---
name: "@actions/http-client"
-version: 2.2.3
+version: 4.0.1
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
-license: mit
+license: other
licenses:
- sources: LICENSE
text: |
diff --git a/.licenses/npm/@actions/io.dep.yml b/.licenses/npm/@actions/io.dep.yml
index d28465403..dadddb4ed 100644
--- a/.licenses/npm/@actions/io.dep.yml
+++ b/.licenses/npm/@actions/io.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/io"
-version: 1.1.3
+version: 3.0.2
type: npm
summary: Actions io lib
homepage: https://github.com/actions/toolkit/tree/main/packages/io
diff --git a/.licenses/npm/@actions/tool-cache.dep.yml b/.licenses/npm/@actions/tool-cache.dep.yml
index fbf911fef..e7bf5bf0f 100644
--- a/.licenses/npm/@actions/tool-cache.dep.yml
+++ b/.licenses/npm/@actions/tool-cache.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/tool-cache"
-version: 2.0.1
+version: 4.0.0
type: npm
summary: Actions tool-cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/tool-cache
diff --git a/.licenses/npm/@azure/abort-controller.dep.yml b/.licenses/npm/@azure/abort-controller.dep.yml
index b19b8f7a4..32d238adf 100644
--- a/.licenses/npm/@azure/abort-controller.dep.yml
+++ b/.licenses/npm/@azure/abort-controller.dep.yml
@@ -1,6 +1,6 @@
---
name: "@azure/abort-controller"
-version: 1.1.0
+version: 2.2.0
type: npm
summary: Microsoft Azure SDK for JavaScript - Aborter
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/abort-controller/README.md
@@ -8,9 +8,9 @@ license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/@azure/core-auth.dep.yml b/.licenses/npm/@azure/core-auth.dep.yml
index 85f1bb89b..48b2844a8 100644
--- a/.licenses/npm/@azure/core-auth.dep.yml
+++ b/.licenses/npm/@azure/core-auth.dep.yml
@@ -1,17 +1,17 @@
---
name: "@azure/core-auth"
-version: 1.5.0
+version: 1.11.0
type: npm
summary: Provides low-level interfaces and helper methods for authentication in Azure
SDK
-homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-auth/README.md
+homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-auth/README.md
license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/@azure/core-http.dep.yml b/.licenses/npm/@azure/core-client.dep.yml
similarity index 78%
rename from .licenses/npm/@azure/core-http.dep.yml
rename to .licenses/npm/@azure/core-client.dep.yml
index 6a443e75c..567784af2 100644
--- a/.licenses/npm/@azure/core-http.dep.yml
+++ b/.licenses/npm/@azure/core-client.dep.yml
@@ -1,17 +1,16 @@
---
-name: "@azure/core-http"
-version: 3.0.4
+name: "@azure/core-client"
+version: 1.11.0
type: npm
-summary: Isomorphic client Runtime for Typescript/node.js/browser javascript client
- libraries generated using AutoRest
-homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-http/README.md
+summary: Core library for interfacing with AutoRest generated code
+homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client/
license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +22,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/@azure/core-http-compat.dep.yml b/.licenses/npm/@azure/core-http-compat.dep.yml
new file mode 100644
index 000000000..c25f52b53
--- /dev/null
+++ b/.licenses/npm/@azure/core-http-compat.dep.yml
@@ -0,0 +1,32 @@
+---
+name: "@azure/core-http-compat"
+version: 2.5.0
+type: npm
+summary: Core HTTP Compatibility Library to bridge the gap between Core V1 & V2 packages.
+homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-http-compat/
+license: mit
+licenses:
+- sources: LICENSE
+ text: |
+ Copyright (c) Microsoft Corporation.
+
+ MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+notices: []
diff --git a/.licenses/npm/@azure/core-lro.dep.yml b/.licenses/npm/@azure/core-lro.dep.yml
index 29683014c..46cbe6e51 100644
--- a/.licenses/npm/@azure/core-lro.dep.yml
+++ b/.licenses/npm/@azure/core-lro.dep.yml
@@ -1,6 +1,6 @@
---
name: "@azure/core-lro"
-version: 2.5.4
+version: 2.7.2
type: npm
summary: Isomorphic client library for supporting long-running operations in node.js
and browser.
diff --git a/.licenses/npm/@azure/core-paging.dep.yml b/.licenses/npm/@azure/core-paging.dep.yml
index dccc04820..09c56a260 100644
--- a/.licenses/npm/@azure/core-paging.dep.yml
+++ b/.licenses/npm/@azure/core-paging.dep.yml
@@ -1,6 +1,6 @@
---
name: "@azure/core-paging"
-version: 1.5.0
+version: 1.7.0
type: npm
summary: Core types for paging async iterable iterators
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-paging/README.md
@@ -8,9 +8,9 @@ license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/@azure/core-rest-pipeline.dep.yml b/.licenses/npm/@azure/core-rest-pipeline.dep.yml
new file mode 100644
index 000000000..663516957
--- /dev/null
+++ b/.licenses/npm/@azure/core-rest-pipeline.dep.yml
@@ -0,0 +1,32 @@
+---
+name: "@azure/core-rest-pipeline"
+version: 1.25.0
+type: npm
+summary: Isomorphic client library for making HTTP requests in node.js and browser.
+homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-rest-pipeline/README.md
+license: mit
+licenses:
+- sources: LICENSE
+ text: |
+ Copyright (c) Microsoft Corporation.
+
+ MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+notices: []
diff --git a/.licenses/npm/@azure/core-tracing.dep.yml b/.licenses/npm/@azure/core-tracing.dep.yml
index a4649e886..467ae44b8 100644
--- a/.licenses/npm/@azure/core-tracing.dep.yml
+++ b/.licenses/npm/@azure/core-tracing.dep.yml
@@ -1,6 +1,6 @@
---
name: "@azure/core-tracing"
-version: 1.0.0-preview.13
+version: 1.4.0
type: npm
summary: Provides low-level interfaces and helper methods for tracing in Azure SDK
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-tracing/README.md
@@ -8,9 +8,9 @@ license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/@azure/core-util.dep.yml b/.licenses/npm/@azure/core-util.dep.yml
index 75ffb250f..7a6451790 100644
--- a/.licenses/npm/@azure/core-util.dep.yml
+++ b/.licenses/npm/@azure/core-util.dep.yml
@@ -1,6 +1,6 @@
---
name: "@azure/core-util"
-version: 1.6.1
+version: 1.14.0
type: npm
summary: Core library for shared utility methods
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-util/
@@ -8,9 +8,9 @@ license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/@azure/core-xml.dep.yml b/.licenses/npm/@azure/core-xml.dep.yml
new file mode 100644
index 000000000..f501dd734
--- /dev/null
+++ b/.licenses/npm/@azure/core-xml.dep.yml
@@ -0,0 +1,32 @@
+---
+name: "@azure/core-xml"
+version: 1.6.0
+type: npm
+summary: Core library for interacting with XML payloads
+homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-xml/README.md
+license: mit
+licenses:
+- sources: LICENSE
+ text: |
+ Copyright (c) Microsoft Corporation.
+
+ MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+notices: []
diff --git a/.licenses/npm/@azure/logger.dep.yml b/.licenses/npm/@azure/logger.dep.yml
index 971ba001c..511d51b7a 100644
--- a/.licenses/npm/@azure/logger.dep.yml
+++ b/.licenses/npm/@azure/logger.dep.yml
@@ -1,6 +1,6 @@
---
name: "@azure/logger"
-version: 1.0.4
+version: 1.4.0
type: npm
summary: Microsoft Azure SDK for JavaScript - Logger
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger/README.md
@@ -8,9 +8,9 @@ license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/@azure/ms-rest-js.dep.yml b/.licenses/npm/@azure/ms-rest-js.dep.yml
deleted file mode 100644
index 762fcdb1e..000000000
--- a/.licenses/npm/@azure/ms-rest-js.dep.yml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-name: "@azure/ms-rest-js"
-version: 2.7.0
-type: npm
-summary: Isomorphic client Runtime for Typescript/node.js/browser javascript client
- libraries generated using AutoRest
-homepage: https://github.com/Azure/ms-rest-js
-license: mit
-licenses:
-- sources: LICENSE
- text: |2
- MIT License
-
- Copyright (c) Microsoft Corporation. All rights reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE
-notices: []
diff --git a/.licenses/npm/@azure/storage-blob.dep.yml b/.licenses/npm/@azure/storage-blob.dep.yml
index c1a125164..95136b476 100644
--- a/.licenses/npm/@azure/storage-blob.dep.yml
+++ b/.licenses/npm/@azure/storage-blob.dep.yml
@@ -1,16 +1,16 @@
---
name: "@azure/storage-blob"
-version: 12.17.0
+version: 12.33.0
type: npm
summary: Microsoft Azure Storage SDK for JavaScript - Blob
-homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-blob/
+homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/storage/storage-blob/README.md
license: mit
licenses:
- sources: LICENSE
text: |
- The MIT License (MIT)
+ Copyright (c) Microsoft Corporation.
- Copyright (c) 2020 Microsoft
+ MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
diff --git a/.licenses/npm/event-target-shim.dep.yml b/.licenses/npm/@azure/storage-common.dep.yml
similarity index 82%
rename from .licenses/npm/event-target-shim.dep.yml
rename to .licenses/npm/@azure/storage-common.dep.yml
index 7a3fc011b..0079d3bc0 100644
--- a/.licenses/npm/event-target-shim.dep.yml
+++ b/.licenses/npm/@azure/storage-common.dep.yml
@@ -1,16 +1,16 @@
---
-name: event-target-shim
-version: 5.0.1
+name: "@azure/storage-common"
+version: 12.4.1
type: npm
-summary: An implementation of WHATWG EventTarget interface.
-homepage: https://github.com/mysticatea/event-target-shim
+summary: Azure Storage Common Client Library for JavaScript
+homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/storage/storage-common/README.md
license: mit
licenses:
- sources: LICENSE
- text: |+
+ text: |-
The MIT License (MIT)
- Copyright (c) 2015 Toru Nagashima
+ Copyright (c) 2018 Microsoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -29,5 +29,4 @@ licenses:
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-
notices: []
diff --git a/.licenses/npm/@fastify/busboy.dep.yml b/.licenses/npm/@fastify/busboy.dep.yml
deleted file mode 100644
index 51267ac9f..000000000
--- a/.licenses/npm/@fastify/busboy.dep.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-name: "@fastify/busboy"
-version: 2.1.0
-type: npm
-summary: A streaming parser for HTML form data for node.js
-homepage:
-license: mit
-licenses:
-- sources: LICENSE
- text: |-
- Copyright Brian White. All rights reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to
- deal in the Software without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- IN THE SOFTWARE.
-notices: []
diff --git a/.licenses/npm/@nodable/entities.dep.yml b/.licenses/npm/@nodable/entities.dep.yml
new file mode 100644
index 000000000..b02eaad68
--- /dev/null
+++ b/.licenses/npm/@nodable/entities.dep.yml
@@ -0,0 +1,11 @@
+---
+name: "@nodable/entities"
+version: 3.0.0
+type: npm
+summary: Entity parser for XML, HTML, External entites with security and NCR control
+homepage:
+license: mit
+licenses:
+- sources: README.md
+ text: MIT
+notices: []
diff --git a/.licenses/npm/@opentelemetry/api.dep.yml b/.licenses/npm/@opentelemetry/api.dep.yml
deleted file mode 100644
index 74c3159ad..000000000
--- a/.licenses/npm/@opentelemetry/api.dep.yml
+++ /dev/null
@@ -1,223 +0,0 @@
----
-name: "@opentelemetry/api"
-version: 1.7.0
-type: npm
-summary: Public API for OpenTelemetry
-homepage: https://github.com/open-telemetry/opentelemetry-js/tree/main/api
-license: apache-2.0
-licenses:
-- sources: LICENSE
- text: |2
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-- sources: README.md
- text: |-
- Apache 2.0 - See [LICENSE][license-url] for more information.
-
- [opentelemetry-js]: https://github.com/open-telemetry/opentelemetry-js
-
- [discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions
- [license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/api/LICENSE
- [license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
- [docs-tracing]: https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/tracing.md
- [docs-sdk-registration]: https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/sdk-registration.md
-notices: []
diff --git a/.licenses/npm/@protobuf-ts/plugin-framework.dep.yml b/.licenses/npm/@protobuf-ts/plugin-framework.dep.yml
deleted file mode 100644
index cbb1501e0..000000000
--- a/.licenses/npm/@protobuf-ts/plugin-framework.dep.yml
+++ /dev/null
@@ -1,185 +0,0 @@
----
-name: "@protobuf-ts/plugin-framework"
-version: 2.9.5
-type: npm
-summary: framework to create protoc plugins
-homepage: https://github.com/timostamm/protobuf-ts
-license: apache-2.0
-licenses:
-- sources: LICENSE
- text: |2
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-notices: []
diff --git a/.licenses/npm/@protobuf-ts/plugin.dep.yml b/.licenses/npm/@protobuf-ts/plugin.dep.yml
deleted file mode 100644
index 09e4667e2..000000000
--- a/.licenses/npm/@protobuf-ts/plugin.dep.yml
+++ /dev/null
@@ -1,186 +0,0 @@
----
-name: "@protobuf-ts/plugin"
-version: 2.9.5
-type: npm
-summary: The protocol buffer compiler plugin "protobuf-ts" generates TypeScript, gRPC-web,
- Twirp, and more.
-homepage: https://github.com/timostamm/protobuf-ts
-license: apache-2.0
-licenses:
-- sources: LICENSE
- text: |2
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-notices: []
diff --git a/.licenses/npm/@protobuf-ts/protoc.dep.yml b/.licenses/npm/@protobuf-ts/protoc.dep.yml
deleted file mode 100644
index dddaf18aa..000000000
--- a/.licenses/npm/@protobuf-ts/protoc.dep.yml
+++ /dev/null
@@ -1,207 +0,0 @@
----
-name: "@protobuf-ts/protoc"
-version: 2.9.5
-type: npm
-summary: Installs the protocol buffer compiler "protoc" for you.
-homepage: https://github.com/timostamm/protobuf-ts
-license: apache-2.0
-licenses:
-- sources: Auto-generated Apache-2.0 license text
- text: |2
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-notices: []
diff --git a/.licenses/npm/@protobuf-ts/runtime-rpc.dep.yml b/.licenses/npm/@protobuf-ts/runtime-rpc.dep.yml
index 3e52954e8..79644b5d7 100644
--- a/.licenses/npm/@protobuf-ts/runtime-rpc.dep.yml
+++ b/.licenses/npm/@protobuf-ts/runtime-rpc.dep.yml
@@ -1,6 +1,6 @@
---
name: "@protobuf-ts/runtime-rpc"
-version: 2.9.5
+version: 2.11.1
type: npm
summary: Runtime library for RPC clients generated by the protoc plugin "protobuf-ts"
homepage: https://github.com/timostamm/protobuf-ts
diff --git a/.licenses/npm/@protobuf-ts/runtime.dep.yml b/.licenses/npm/@protobuf-ts/runtime.dep.yml
index 66dbe2b11..7a210232d 100644
--- a/.licenses/npm/@protobuf-ts/runtime.dep.yml
+++ b/.licenses/npm/@protobuf-ts/runtime.dep.yml
@@ -1,6 +1,6 @@
---
name: "@protobuf-ts/runtime"
-version: 2.9.5
+version: 2.11.1
type: npm
summary: Runtime library for code generated by the protoc plugin "protobuf-ts"
homepage: https://github.com/timostamm/protobuf-ts
diff --git a/.licenses/npm/@types/node-fetch.dep.yml b/.licenses/npm/@types/node-fetch.dep.yml
deleted file mode 100644
index e335d29a1..000000000
--- a/.licenses/npm/@types/node-fetch.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: "@types/node-fetch"
-version: 2.6.9
-type: npm
-summary: TypeScript definitions for node-fetch
-homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node-fetch
-license: mit
-licenses:
-- sources: LICENSE
- text: |2
- MIT License
-
- Copyright (c) Microsoft Corporation.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE
-notices: []
diff --git a/.licenses/npm/@types/node.dep.yml b/.licenses/npm/@types/node.dep.yml
deleted file mode 100644
index 86544f488..000000000
--- a/.licenses/npm/@types/node.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: "@types/node"
-version: 24.1.0
-type: npm
-summary: TypeScript definitions for node
-homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node
-license: mit
-licenses:
-- sources: LICENSE
- text: |2
- MIT License
-
- Copyright (c) Microsoft Corporation.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE
-notices: []
diff --git a/.licenses/npm/@types/tunnel.dep.yml b/.licenses/npm/@types/tunnel.dep.yml
deleted file mode 100644
index b3636b02d..000000000
--- a/.licenses/npm/@types/tunnel.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: "@types/tunnel"
-version: 0.0.3
-type: npm
-summary: TypeScript definitions for tunnel
-homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/tunnel
-license: mit
-licenses:
-- sources: LICENSE
- text: |2
- MIT License
-
- Copyright (c) Microsoft Corporation.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE
-notices: []
diff --git a/.licenses/npm/@typespec/ts-http-runtime.dep.yml b/.licenses/npm/@typespec/ts-http-runtime.dep.yml
new file mode 100644
index 000000000..f521f3001
--- /dev/null
+++ b/.licenses/npm/@typespec/ts-http-runtime.dep.yml
@@ -0,0 +1,32 @@
+---
+name: "@typespec/ts-http-runtime"
+version: 0.3.7
+type: npm
+summary: Isomorphic client library for making HTTP requests in node.js and browser.
+homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/ts-http-runtime/README.md
+license: mit
+licenses:
+- sources: LICENSE
+ text: |
+ Copyright (c) Microsoft Corporation.
+
+ MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+notices: []
diff --git a/.licenses/npm/abort-controller.dep.yml b/.licenses/npm/abort-controller.dep.yml
deleted file mode 100644
index 492a609bb..000000000
--- a/.licenses/npm/abort-controller.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: abort-controller
-version: 3.0.0
-type: npm
-summary: An implementation of WHATWG AbortController interface.
-homepage: https://github.com/mysticatea/abort-controller#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2017 Toru Nagashima
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/process.dep.yml b/.licenses/npm/agent-base.dep.yml
similarity index 84%
rename from .licenses/npm/process.dep.yml
rename to .licenses/npm/agent-base.dep.yml
index 2bf50598a..54c324a34 100644
--- a/.licenses/npm/process.dep.yml
+++ b/.licenses/npm/agent-base.dep.yml
@@ -1,16 +1,16 @@
---
-name: process
-version: 0.11.10
+name: agent-base
+version: 7.1.4
type: npm
-summary: process information for node.js and browsers
-homepage: https://github.com/shtylman/node-process#readme
+summary: Turn a function into an `http.Agent` instance
+homepage:
license: mit
licenses:
- sources: LICENSE
- text: |
+ text: |-
(The MIT License)
- Copyright (c) 2013 Roman Shtylman
+ Copyright (c) 2013 Nathan Rajlich
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/.licenses/npm/dunder-proto.dep.yml b/.licenses/npm/anynum.dep.yml
similarity index 83%
rename from .licenses/npm/dunder-proto.dep.yml
rename to .licenses/npm/anynum.dep.yml
index 39542bfdc..891456f01 100644
--- a/.licenses/npm/dunder-proto.dep.yml
+++ b/.licenses/npm/anynum.dep.yml
@@ -1,16 +1,17 @@
---
-name: dunder-proto
+name: anynum
version: 1.0.1
type: npm
-summary: If available, the `Object.prototype.__proto__` accessor and mutator, call-bound
-homepage: https://github.com/es-shims/dunder-proto#readme
+summary: Normalize all Unicode decimal digits (Devanagari, Arabic, Thai, etc.) to
+ ASCII numerals. Zero dependencies, performance-first.
+homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
- Copyright (c) 2024 ECMAScript Shims
+ Copyright (c) 2026 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -29,4 +30,6 @@ licenses:
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+- sources: README.md
+ text: MIT
notices: []
diff --git a/.licenses/npm/argparse.dep.yml b/.licenses/npm/argparse.dep.yml
deleted file mode 100644
index 2cd2843cf..000000000
--- a/.licenses/npm/argparse.dep.yml
+++ /dev/null
@@ -1,38 +0,0 @@
----
-name: argparse
-version: 1.0.10
-type: npm
-summary: Very powerful CLI arguments parser. Native port of argparse - python's options
- parsing library
-homepage: https://github.com/nodeca/argparse#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- (The MIT License)
-
- Copyright (C) 2012 by Vitaly Puzrin
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-- sources: README.md
- text: |-
- Copyright (c) 2012 [Vitaly Puzrin](https://github.com/puzrin).
- Released under the MIT license. See
- [LICENSE](https://github.com/nodeca/argparse/blob/master/LICENSE) for details.
-notices: []
diff --git a/.licenses/npm/asynckit.dep.yml b/.licenses/npm/asynckit.dep.yml
deleted file mode 100644
index 905e0aaa9..000000000
--- a/.licenses/npm/asynckit.dep.yml
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: asynckit
-version: 0.4.0
-type: npm
-summary: Minimal async jobs utility library, with streams support
-homepage: https://github.com/alexindigo/asynckit#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- The MIT License (MIT)
-
- Copyright (c) 2016 Alex Indigo
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-- sources: README.md
- text: AsyncKit is licensed under the MIT license.
-notices: []
diff --git a/.licenses/npm/balanced-match.dep.yml b/.licenses/npm/balanced-match.dep.yml
index 36095592b..101c2c32b 100644
--- a/.licenses/npm/balanced-match.dep.yml
+++ b/.licenses/npm/balanced-match.dep.yml
@@ -1,39 +1,18 @@
---
name: balanced-match
-version: 1.0.2
+version: 4.0.4
type: npm
summary: Match balanced character pairs, like "{" and "}"
-homepage: https://github.com/juliangruber/balanced-match
+homepage:
license: mit
licenses:
- sources: LICENSE.md
text: |
(MIT)
- Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
+ Original code Copyright Julian Gruber
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-- sources: README.md
- text: |-
- (MIT)
-
- Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
+ Port to TypeScript Copyright Isaac Z. Schlueter
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/.licenses/npm/brace-expansion.dep.yml b/.licenses/npm/brace-expansion.dep.yml
index 95ca8eb1f..96e6211ba 100644
--- a/.licenses/npm/brace-expansion.dep.yml
+++ b/.licenses/npm/brace-expansion.dep.yml
@@ -1,16 +1,18 @@
---
name: brace-expansion
-version: 1.1.12
+version: 5.0.9
type: npm
summary: Brace expansion as known from sh/bash
-homepage: https://github.com/juliangruber/brace-expansion
+homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
- Copyright (c) 2013 Julian Gruber
+ Copyright Julian Gruber
+
+ TypeScript port Copyright Isaac Z. Schlueter
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -22,29 +24,6 @@ licenses:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-- sources: README.md
- text: |-
- (MIT)
-
- Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
diff --git a/.licenses/npm/call-bind-apply-helpers.dep.yml b/.licenses/npm/call-bind-apply-helpers.dep.yml
deleted file mode 100644
index bfd264f37..000000000
--- a/.licenses/npm/call-bind-apply-helpers.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: call-bind-apply-helpers
-version: 1.0.2
-type: npm
-summary: Helper functions around Function call/apply/bind, for use in `call-bind`
-homepage: https://github.com/ljharb/call-bind-apply-helpers#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2024 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/combined-stream.dep.yml b/.licenses/npm/combined-stream.dep.yml
deleted file mode 100644
index 2b392155d..000000000
--- a/.licenses/npm/combined-stream.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: combined-stream
-version: 1.0.8
-type: npm
-summary: A stream that emits multiple other streams one after another.
-homepage: https://github.com/felixge/node-combined-stream
-license: mit
-licenses:
-- sources: License
- text: |
- Copyright (c) 2011 Debuggable Limited
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-- sources: Readme.md
- text: combined-stream is licensed under the MIT license.
-notices: []
diff --git a/.licenses/npm/concat-map.dep.yml b/.licenses/npm/concat-map.dep.yml
deleted file mode 100644
index 20216b958..000000000
--- a/.licenses/npm/concat-map.dep.yml
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: concat-map
-version: 0.0.1
-type: npm
-summary: concatenative mapdashery
-homepage: https://github.com/substack/node-concat-map#readme
-license: other
-licenses:
-- sources: LICENSE
- text: |
- This software is released under the MIT license:
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- the Software, and to permit persons to whom the Software is furnished to do so,
- subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-- sources: README.markdown
- text: MIT
-notices: []
diff --git a/.licenses/npm/debug.dep.yml b/.licenses/npm/debug.dep.yml
new file mode 100644
index 000000000..b49c69e92
--- /dev/null
+++ b/.licenses/npm/debug.dep.yml
@@ -0,0 +1,56 @@
+---
+name: debug
+version: 4.4.3
+type: npm
+summary: Lightweight debugging utility for Node.js and the browser
+homepage:
+license: mit
+licenses:
+- sources: LICENSE
+ text: |+
+ (The MIT License)
+
+ Copyright (c) 2014-2017 TJ Holowaychuk
+ Copyright (c) 2018-2021 Josh Junon
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ and associated documentation files (the 'Software'), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+- sources: README.md
+ text: |-
+ (The MIT License)
+
+ Copyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>
+ Copyright (c) 2018-2021 Josh Junon
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ 'Software'), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+notices: []
diff --git a/.licenses/npm/delayed-stream.dep.yml b/.licenses/npm/delayed-stream.dep.yml
deleted file mode 100644
index 124012173..000000000
--- a/.licenses/npm/delayed-stream.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: delayed-stream
-version: 1.0.0
-type: npm
-summary: Buffers events from a stream until you are ready to handle them.
-homepage: https://github.com/felixge/node-delayed-stream
-license: mit
-licenses:
-- sources: License
- text: |
- Copyright (c) 2011 Debuggable Limited
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-- sources: Readme.md
- text: delayed-stream is licensed under the MIT license.
-notices: []
diff --git a/.licenses/npm/es-define-property.dep.yml b/.licenses/npm/es-define-property.dep.yml
deleted file mode 100644
index 7f1903728..000000000
--- a/.licenses/npm/es-define-property.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: es-define-property
-version: 1.0.1
-type: npm
-summary: "`Object.defineProperty`, but not IE 8's broken one."
-homepage: https://github.com/ljharb/es-define-property#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2024 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/es-errors.dep.yml b/.licenses/npm/es-errors.dep.yml
deleted file mode 100644
index a5827aac9..000000000
--- a/.licenses/npm/es-errors.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: es-errors
-version: 1.3.0
-type: npm
-summary: A simple cache for a few of the JS Error constructors.
-homepage: https://github.com/ljharb/es-errors#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2024 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/es-object-atoms.dep.yml b/.licenses/npm/es-object-atoms.dep.yml
deleted file mode 100644
index dc42eaae7..000000000
--- a/.licenses/npm/es-object-atoms.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: es-object-atoms
-version: 1.1.1
-type: npm
-summary: 'ES Object-related atoms: Object, ToObject, RequireObjectCoercible'
-homepage: https://github.com/ljharb/es-object-atoms#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2024 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/es-set-tostringtag.dep.yml b/.licenses/npm/es-set-tostringtag.dep.yml
deleted file mode 100644
index f4b673e27..000000000
--- a/.licenses/npm/es-set-tostringtag.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: es-set-tostringtag
-version: 2.1.0
-type: npm
-summary: A helper to optimistically set Symbol.toStringTag, when possible.
-homepage: https://github.com/es-shims/es-set-tostringtag#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2022 ECMAScript Shims
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/esprima.dep.yml b/.licenses/npm/esprima.dep.yml
deleted file mode 100644
index 538091c52..000000000
--- a/.licenses/npm/esprima.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: esprima
-version: 4.0.1
-type: npm
-summary: ECMAScript parsing infrastructure for multipurpose analysis
-homepage: http://esprima.org
-license: bsd-2-clause
-licenses:
-- sources: LICENSE.BSD
- text: |
- Copyright JS Foundation and other contributors, https://js.foundation/
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-notices: []
diff --git a/.licenses/npm/@oozcitak/util.dep.yml b/.licenses/npm/fast-xml-builder.dep.yml
similarity index 88%
rename from .licenses/npm/@oozcitak/util.dep.yml
rename to .licenses/npm/fast-xml-builder.dep.yml
index dcee45c0f..0045ee98d 100644
--- a/.licenses/npm/@oozcitak/util.dep.yml
+++ b/.licenses/npm/fast-xml-builder.dep.yml
@@ -1,16 +1,16 @@
---
-name: "@oozcitak/util"
-version: 8.3.8
+name: fast-xml-builder
+version: 1.3.0
type: npm
-summary: Utility functions
-homepage: http://github.com/oozcitak/util
+summary: Build XML from JSON without C/C++ based libraries
+homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
- Copyright (c) 2019 Ozgur Ozcitak
+ Copyright (c) 2026 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/.licenses/npm/hasown.dep.yml b/.licenses/npm/fast-xml-parser.dep.yml
similarity index 81%
rename from .licenses/npm/hasown.dep.yml
rename to .licenses/npm/fast-xml-parser.dep.yml
index 992639195..07fd88dd4 100644
--- a/.licenses/npm/hasown.dep.yml
+++ b/.licenses/npm/fast-xml-parser.dep.yml
@@ -1,16 +1,16 @@
---
-name: hasown
-version: 2.0.2
+name: fast-xml-parser
+version: 5.10.1
type: npm
-summary: A robust, ES3 compatible, "has own property" predicate.
-homepage: https://github.com/inspect-js/hasOwn#readme
+summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
+homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
- Copyright (c) Jordan Harband and contributors
+ Copyright (c) 2017 Amit Kumar Gupta
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -29,4 +29,9 @@ licenses:
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+- sources: README.md
+ text: |-
+ * MIT License
+
+ 
notices: []
diff --git a/.licenses/npm/form-data-2.5.5.dep.yml b/.licenses/npm/form-data-2.5.5.dep.yml
deleted file mode 100644
index a60d6b967..000000000
--- a/.licenses/npm/form-data-2.5.5.dep.yml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-name: form-data
-version: 2.5.5
-type: npm
-summary: A library to create readable "multipart/form-data" streams. Can be used to
- submit forms and file uploads to other web applications.
-homepage:
-license: mit
-licenses:
-- sources: License
- text: |
- Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-- sources: README.md
- text: Form-Data is released under the [MIT](License) license.
-notices: []
diff --git a/.licenses/npm/form-data-4.0.4.dep.yml b/.licenses/npm/form-data-4.0.4.dep.yml
deleted file mode 100644
index 5b3b5c1fc..000000000
--- a/.licenses/npm/form-data-4.0.4.dep.yml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-name: form-data
-version: 4.0.4
-type: npm
-summary: A library to create readable "multipart/form-data" streams. Can be used to
- submit forms and file uploads to other web applications.
-homepage:
-license: mit
-licenses:
-- sources: License
- text: |
- Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-- sources: README.md
- text: Form-Data is released under the [MIT](License) license.
-notices: []
diff --git a/.licenses/npm/function-bind.dep.yml b/.licenses/npm/function-bind.dep.yml
deleted file mode 100644
index 3ae18f3ec..000000000
--- a/.licenses/npm/function-bind.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: function-bind
-version: 1.1.2
-type: npm
-summary: Implementation of Function.prototype.bind
-homepage: https://github.com/Raynos/function-bind
-license: mit
-licenses:
-- sources: LICENSE
- text: |+
- Copyright (c) 2013 Raynos.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-
-notices: []
-...
diff --git a/.licenses/npm/get-intrinsic.dep.yml b/.licenses/npm/get-intrinsic.dep.yml
deleted file mode 100644
index c94509f44..000000000
--- a/.licenses/npm/get-intrinsic.dep.yml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-name: get-intrinsic
-version: 1.3.0
-type: npm
-summary: Get and robustly cache all JS language-level intrinsics at first require
- time
-homepage: https://github.com/ljharb/get-intrinsic#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2020 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/get-proto.dep.yml b/.licenses/npm/get-proto.dep.yml
deleted file mode 100644
index 1176a9536..000000000
--- a/.licenses/npm/get-proto.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: get-proto
-version: 1.0.1
-type: npm
-summary: Robustly get the [[Prototype]] of an object
-homepage: https://github.com/ljharb/get-proto#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2025 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/gopd.dep.yml b/.licenses/npm/gopd.dep.yml
deleted file mode 100644
index d3d28af9b..000000000
--- a/.licenses/npm/gopd.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: gopd
-version: 1.2.0
-type: npm
-summary: "`Object.getOwnPropertyDescriptor`, but accounts for IE's broken implementation."
-homepage: https://github.com/ljharb/gopd#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2022 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/has-symbols.dep.yml b/.licenses/npm/has-symbols.dep.yml
deleted file mode 100644
index 38b50f044..000000000
--- a/.licenses/npm/has-symbols.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: has-symbols
-version: 1.1.0
-type: npm
-summary: Determine if the JS environment has Symbol support. Supports spec, or shams.
-homepage: https://github.com/ljharb/has-symbols#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2016 Jordan Harband
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/has-tostringtag.dep.yml b/.licenses/npm/has-tostringtag.dep.yml
deleted file mode 100644
index efa5c5c1b..000000000
--- a/.licenses/npm/has-tostringtag.dep.yml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-name: has-tostringtag
-version: 1.0.2
-type: npm
-summary: Determine if the JS environment has `Symbol.toStringTag` support. Supports
- spec, or shams.
-homepage: https://github.com/inspect-js/has-tostringtag#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2021 Inspect JS
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/mime-db.dep.yml b/.licenses/npm/http-proxy-agent.dep.yml
similarity index 85%
rename from .licenses/npm/mime-db.dep.yml
rename to .licenses/npm/http-proxy-agent.dep.yml
index 660566950..bcd275739 100644
--- a/.licenses/npm/mime-db.dep.yml
+++ b/.licenses/npm/http-proxy-agent.dep.yml
@@ -1,8 +1,8 @@
---
-name: mime-db
-version: 1.52.0
+name: http-proxy-agent
+version: 7.0.2
type: npm
-summary: Media Type Database
+summary: An HTTP(s) proxy `http.Agent` implementation for HTTP
homepage:
license: mit
licenses:
@@ -10,8 +10,7 @@ licenses:
text: |
(The MIT License)
- Copyright (c) 2014 Jonathan Ong
- Copyright (c) 2015-2022 Douglas Christopher Wilson
+ Copyright (c) 2013 Nathan Rajlich
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/.licenses/npm/mime-types.dep.yml b/.licenses/npm/https-proxy-agent.dep.yml
similarity index 57%
rename from .licenses/npm/mime-types.dep.yml
rename to .licenses/npm/https-proxy-agent.dep.yml
index 832d2052d..7b6e176d7 100644
--- a/.licenses/npm/mime-types.dep.yml
+++ b/.licenses/npm/https-proxy-agent.dep.yml
@@ -1,17 +1,16 @@
---
-name: mime-types
-version: 2.1.35
+name: https-proxy-agent
+version: 7.0.6
type: npm
-summary: The ultimate javascript content-type utility.
+summary: An HTTP(s) proxy `http.Agent` implementation for HTTPS
homepage:
license: mit
licenses:
- sources: LICENSE
- text: |
+ text: |-
(The MIT License)
- Copyright (c) 2014 Jonathan Ong
- Copyright (c) 2015 Douglas Christopher Wilson
+ Copyright (c) 2013 Nathan Rajlich
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -31,17 +30,4 @@ licenses:
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-- sources: README.md
- text: |-
- [MIT](LICENSE)
-
- [ci-image]: https://badgen.net/github/checks/jshttp/mime-types/master?label=ci
- [ci-url]: https://github.com/jshttp/mime-types/actions/workflows/ci.yml
- [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-types/master
- [coveralls-url]: https://coveralls.io/r/jshttp/mime-types?branch=master
- [node-version-image]: https://badgen.net/npm/node/mime-types
- [node-version-url]: https://nodejs.org/en/download
- [npm-downloads-image]: https://badgen.net/npm/dm/mime-types
- [npm-url]: https://npmjs.org/package/mime-types
- [npm-version-image]: https://badgen.net/npm/v/mime-types
notices: []
diff --git a/.licenses/npm/is-unsafe.dep.yml b/.licenses/npm/is-unsafe.dep.yml
new file mode 100644
index 000000000..a0e275d48
--- /dev/null
+++ b/.licenses/npm/is-unsafe.dep.yml
@@ -0,0 +1,35 @@
+---
+name: is-unsafe
+version: 2.0.0
+type: npm
+summary: Zero-dependency, DOM-free, pure predicate for detecting unsafe strings across
+ HTML, XML, SVG, SQL, SHELL, and REGEX contexts
+homepage:
+license: mit
+licenses:
+- sources: LICENSE
+ text: |
+ MIT License
+
+ Copyright (c) 2026 Natural Intelligence
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+- sources: README.md
+ text: MIT
+notices: []
diff --git a/.licenses/npm/js-yaml.dep.yml b/.licenses/npm/js-yaml.dep.yml
deleted file mode 100644
index 3b8875d01..000000000
--- a/.licenses/npm/js-yaml.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: js-yaml
-version: 3.14.0
-type: npm
-summary: YAML 1.2 parser and serializer
-homepage: https://github.com/nodeca/js-yaml
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- (The MIT License)
-
- Copyright (C) 2011-2015 by Vitaly Puzrin
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-notices: []
diff --git a/.licenses/npm/math-intrinsics.dep.yml b/.licenses/npm/math-intrinsics.dep.yml
deleted file mode 100644
index 2f29af6f9..000000000
--- a/.licenses/npm/math-intrinsics.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: math-intrinsics
-version: 1.1.0
-type: npm
-summary: ES Math-related intrinsics and helpers, robustly cached.
-homepage: https://github.com/es-shims/math-intrinsics#readme
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) 2024 ECMAScript Shims
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/minimatch.dep.yml b/.licenses/npm/minimatch.dep.yml
index 869816f5f..d9010847c 100644
--- a/.licenses/npm/minimatch.dep.yml
+++ b/.licenses/npm/minimatch.dep.yml
@@ -1,26 +1,66 @@
---
name: minimatch
-version: 3.1.2
+version: 10.2.6
type: npm
summary: a glob matcher in javascript
-homepage: https://github.com/isaacs/minimatch#readme
-license: isc
+homepage:
+license: blueoak-1.0.0
licenses:
-- sources: LICENSE
+- sources: LICENSE.md
text: |
- The ISC License
+ # Blue Oak Model License
- Copyright (c) Isaac Z. Schlueter and Contributors
+ Version 1.0.0
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
+ ## Purpose
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ This license gives everyone as much permission to work with
+ this software as possible, while protecting contributors
+ from liability.
+
+ ## Acceptance
+
+ In order to receive this license, you must agree to its
+ rules. The rules of this license are both obligations
+ under that agreement and conditions to your license.
+ You must not do anything with this software that triggers
+ a rule that you cannot or will not follow.
+
+ ## Copyright
+
+ Each contributor licenses you to do everything with this
+ software that would otherwise infringe that contributor's
+ copyright in it.
+
+ ## Notices
+
+ You must ensure that everyone who gets a copy of
+ any part of this software from you, with or without
+ changes, also gets the text of this license or a link to
+ .
+
+ ## Excuse
+
+ If anyone notifies you in writing that you have not
+ complied with [Notices](#notices), you can keep your
+ license by taking all practical steps to comply within 30
+ days after the notice. If you do not do so, your license
+ ends immediately.
+
+ ## Patent
+
+ Each contributor licenses you to do everything with this
+ software that would otherwise infringe any patent claims
+ they can license or become able to license.
+
+ ## Reliability
+
+ No contributor can revoke this license.
+
+ ## No Liability
+
+ **_As far as the law allows, this software comes as is,
+ without any warranty or condition, and no contributor
+ will be liable to anyone for any damages related to this
+ software or this license, under any kind of legal claim._**
notices: []
diff --git a/.licenses/npm/@oozcitak/dom.dep.yml b/.licenses/npm/ms.dep.yml
similarity index 85%
rename from .licenses/npm/@oozcitak/dom.dep.yml
rename to .licenses/npm/ms.dep.yml
index a810093aa..5a303e4d6 100644
--- a/.licenses/npm/@oozcitak/dom.dep.yml
+++ b/.licenses/npm/ms.dep.yml
@@ -1,16 +1,16 @@
---
-name: "@oozcitak/dom"
-version: 1.15.8
+name: ms
+version: 2.1.3
type: npm
-summary: A modern DOM implementation
-homepage: http://github.com/oozcitak/dom
+summary: Tiny millisecond conversion utility
+homepage:
license: mit
licenses:
-- sources: LICENSE
+- sources: license.md
text: |
- MIT License
+ The MIT License (MIT)
- Copyright (c) 2019 Ozgur Ozcitak
+ Copyright (c) 2020 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/.licenses/npm/node-fetch.dep.yml b/.licenses/npm/node-fetch.dep.yml
deleted file mode 100644
index ec9a760d2..000000000
--- a/.licenses/npm/node-fetch.dep.yml
+++ /dev/null
@@ -1,56 +0,0 @@
----
-name: node-fetch
-version: 2.7.0
-type: npm
-summary: A light-weight module that brings window.fetch to node.js
-homepage: https://github.com/bitinn/node-fetch
-license: mit
-licenses:
-- sources: LICENSE.md
- text: |+
- The MIT License (MIT)
-
- Copyright (c) 2016 David Frank
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-
-- sources: README.md
- text: |-
- MIT
-
- [npm-image]: https://flat.badgen.net/npm/v/node-fetch
- [npm-url]: https://www.npmjs.com/package/node-fetch
- [travis-image]: https://flat.badgen.net/travis/bitinn/node-fetch
- [travis-url]: https://travis-ci.org/bitinn/node-fetch
- [codecov-image]: https://flat.badgen.net/codecov/c/github/bitinn/node-fetch/master
- [codecov-url]: https://codecov.io/gh/bitinn/node-fetch
- [install-size-image]: https://flat.badgen.net/packagephobia/install/node-fetch
- [install-size-url]: https://packagephobia.now.sh/result?p=node-fetch
- [discord-image]: https://img.shields.io/discord/619915844268326952?color=%237289DA&label=Discord&style=flat-square
- [discord-url]: https://discord.gg/Zxbndcm
- [opencollective-image]: https://opencollective.com/node-fetch/backers.svg
- [opencollective-url]: https://opencollective.com/node-fetch
- [whatwg-fetch]: https://fetch.spec.whatwg.org/
- [response-init]: https://fetch.spec.whatwg.org/#responseinit
- [node-readable]: https://nodejs.org/api/stream.html#stream_readable_streams
- [mdn-headers]: https://developer.mozilla.org/en-US/docs/Web/API/Headers
- [LIMITS.md]: https://github.com/bitinn/node-fetch/blob/master/LIMITS.md
- [ERROR-HANDLING.md]: https://github.com/bitinn/node-fetch/blob/master/ERROR-HANDLING.md
- [UPGRADE-GUIDE.md]: https://github.com/bitinn/node-fetch/blob/master/UPGRADE-GUIDE.md
-notices: []
diff --git a/.licenses/npm/@oozcitak/url.dep.yml b/.licenses/npm/path-expression-matcher.dep.yml
similarity index 84%
rename from .licenses/npm/@oozcitak/url.dep.yml
rename to .licenses/npm/path-expression-matcher.dep.yml
index 6f3ae3985..a671e7d7c 100644
--- a/.licenses/npm/@oozcitak/url.dep.yml
+++ b/.licenses/npm/path-expression-matcher.dep.yml
@@ -1,16 +1,16 @@
---
-name: "@oozcitak/url"
-version: 1.0.4
+name: path-expression-matcher
+version: 1.6.2
type: npm
-summary: An implementation of the URL Living Standard
-homepage: http://github.com/oozcitak/url
+summary: Efficient path tracking and pattern matching for XML/JSON parsers
+homepage: https://github.com/NaturalIntelligence/path-expression-matcher#readme
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
- Copyright (c) 2019 Ozgur Ozcitak
+ Copyright (c) 2024
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/.licenses/npm/safe-buffer.dep.yml b/.licenses/npm/safe-buffer.dep.yml
deleted file mode 100644
index a6499e34d..000000000
--- a/.licenses/npm/safe-buffer.dep.yml
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: safe-buffer
-version: 5.2.1
-type: npm
-summary: Safer Node.js Buffer API
-homepage: https://github.com/feross/safe-buffer
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- The MIT License (MIT)
-
- Copyright (c) Feross Aboukhadijeh
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-- sources: README.md
- text: MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org)
-notices: []
diff --git a/.licenses/npm/sax.dep.yml b/.licenses/npm/sax.dep.yml
deleted file mode 100644
index 20f6c4671..000000000
--- a/.licenses/npm/sax.dep.yml
+++ /dev/null
@@ -1,52 +0,0 @@
----
-name: sax
-version: 1.3.0
-type: npm
-summary: An evented streaming XML parser in JavaScript
-homepage:
-license: isc
-licenses:
-- sources: LICENSE
- text: |
- The ISC License
-
- Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ====
-
- `String.fromCodePoint` by Mathias Bynens used according to terms of MIT
- License, as follows:
-
- Copyright (c) 2010-2022 Mathias Bynens
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-notices: []
diff --git a/.licenses/npm/semver-6.3.1.dep.yml b/.licenses/npm/semver-6.3.1.dep.yml
deleted file mode 100644
index 248cb0301..000000000
--- a/.licenses/npm/semver-6.3.1.dep.yml
+++ /dev/null
@@ -1,26 +0,0 @@
----
-name: semver
-version: 6.3.1
-type: npm
-summary: The semantic version parser used by npm.
-homepage:
-license: isc
-licenses:
-- sources: LICENSE
- text: |
- The ISC License
-
- Copyright (c) Isaac Z. Schlueter and Contributors
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-notices: []
diff --git a/.licenses/npm/semver-7.7.1.dep.yml b/.licenses/npm/semver.dep.yml
similarity index 98%
rename from .licenses/npm/semver-7.7.1.dep.yml
rename to .licenses/npm/semver.dep.yml
index 3194cf4ae..c5813fabe 100644
--- a/.licenses/npm/semver-7.7.1.dep.yml
+++ b/.licenses/npm/semver.dep.yml
@@ -1,6 +1,6 @@
---
name: semver
-version: 7.7.1
+version: 7.8.5
type: npm
summary: The semantic version parser used by npm.
homepage:
diff --git a/.licenses/npm/sprintf-js.dep.yml b/.licenses/npm/sprintf-js.dep.yml
deleted file mode 100644
index e7157634f..000000000
--- a/.licenses/npm/sprintf-js.dep.yml
+++ /dev/null
@@ -1,37 +0,0 @@
----
-name: sprintf-js
-version: 1.0.3
-type: npm
-summary: JavaScript sprintf implementation
-homepage: https://github.com/alexei/sprintf.js#readme
-license: bsd-3-clause
-licenses:
-- sources: LICENSE
- text: |
- Copyright (c) 2007-2014, Alexandru Marasteanu
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of this software nor the names of its contributors may be
- used to endorse or promote products derived from this software without
- specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-- sources: README.md
- text: "**sprintf.js** is licensed under the terms of the 3-clause BSD license."
-notices: []
diff --git a/.licenses/npm/xmlbuilder2.dep.yml b/.licenses/npm/strnum.dep.yml
similarity index 89%
rename from .licenses/npm/xmlbuilder2.dep.yml
rename to .licenses/npm/strnum.dep.yml
index 378714677..c472ee048 100644
--- a/.licenses/npm/xmlbuilder2.dep.yml
+++ b/.licenses/npm/strnum.dep.yml
@@ -1,16 +1,16 @@
---
-name: xmlbuilder2
+name: strnum
version: 2.4.1
type: npm
-summary: An XML builder for node.js
-homepage: http://github.com/oozcitak/xmlbuilder2
+summary: Parse String to Number based on configuration
+homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
- Copyright (c) 2019 Ozgur Ozcitak
+ Copyright (c) 2021 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/.licenses/npm/tr46.dep.yml b/.licenses/npm/tr46.dep.yml
deleted file mode 100644
index 3bacc6ec4..000000000
--- a/.licenses/npm/tr46.dep.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-name: tr46
-version: 0.0.3
-type: npm
-summary: An implementation of the Unicode TR46 spec
-homepage: https://github.com/Sebmaster/tr46.js#readme
-license: mit
-licenses:
-- sources: Auto-generated MIT license text
- text: |
- MIT License
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/tslib-1.14.1.dep.yml b/.licenses/npm/tslib-1.14.1.dep.yml
deleted file mode 100644
index 10b2c2ac1..000000000
--- a/.licenses/npm/tslib-1.14.1.dep.yml
+++ /dev/null
@@ -1,35 +0,0 @@
----
-name: tslib
-version: 1.14.1
-type: npm
-summary: Runtime library for TypeScript helper functions
-homepage: https://www.typescriptlang.org/
-license: 0bsd
-licenses:
-- sources: LICENSE.txt
- text: |-
- Copyright (c) Microsoft Corporation.
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-notices:
-- sources: CopyrightNotice.txt
- text: "/*! *****************************************************************************\r\nCopyright
- (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute
- this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE
- SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS.
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR
- CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE,
- DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS
- ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS
- SOFTWARE.\r\n*****************************************************************************
- */"
diff --git a/.licenses/npm/tslib-2.6.2.dep.yml b/.licenses/npm/tslib.dep.yml
similarity index 98%
rename from .licenses/npm/tslib-2.6.2.dep.yml
rename to .licenses/npm/tslib.dep.yml
index 427097a71..4611137ca 100644
--- a/.licenses/npm/tslib-2.6.2.dep.yml
+++ b/.licenses/npm/tslib.dep.yml
@@ -1,6 +1,6 @@
---
name: tslib
-version: 2.6.2
+version: 2.8.1
type: npm
summary: Runtime library for TypeScript helper functions
homepage: https://www.typescriptlang.org/
diff --git a/.licenses/npm/typescript.dep.yml b/.licenses/npm/typescript.dep.yml
deleted file mode 100644
index 01cccafde..000000000
--- a/.licenses/npm/typescript.dep.yml
+++ /dev/null
@@ -1,239 +0,0 @@
----
-name: typescript
-version: 3.9.10
-type: npm
-summary: TypeScript is a language for application scale JavaScript development
-homepage: https://www.typescriptlang.org/
-license: apache-2.0
-licenses:
-- sources: LICENSE.txt
- text: "Apache License\n\nVersion 2.0, January 2004\n\nhttp://www.apache.org/licenses/
- \n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\"
- shall mean the terms and conditions for use, reproduction, and distribution as
- defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the
- copyright owner or entity authorized by the copyright owner that is granting the
- License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common control with
- that entity. For the purposes of this definition, \"control\" means (i) the power,
- direct or indirect, to cause the direction or management of such entity, whether
- by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of
- the outstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\"
- (or \"Your\") shall mean an individual or Legal Entity exercising permissions
- granted by this License.\n\n\"Source\" form shall mean the preferred form for
- making modifications, including but not limited to software source code, documentation
- source, and configuration files.\n\n\"Object\" form shall mean any form resulting
- from mechanical transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation, and conversions
- to other media types.\n\n\"Work\" shall mean the work of authorship, whether in
- Source or Object form, made available under the License, as indicated by a copyright
- notice that is included in or attached to the work (an example is provided in
- the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source
- or Object form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications represent,
- as a whole, an original work of authorship. For the purposes of this License,
- Derivative Works shall not include works that remain separable from, or merely
- link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\"
- shall mean any work of authorship, including the original version of the Work
- and any modifications or additions to that Work or Derivative Works thereof, that
- is intentionally submitted to Licensor for inclusion in the Work by the copyright
- owner or by an individual or Legal Entity authorized to submit on behalf of the
- copyright owner. For the purposes of this definition, \"submitted\" means any
- form of electronic, verbal, or written communication sent to the Licensor or its
- representatives, including but not limited to communication on electronic mailing
- lists, source code control systems, and issue tracking systems that are managed
- by, or on behalf of, the Licensor for the purpose of discussing and improving
- the Work, but excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as \"Not a Contribution.\"\n\n\"Contributor\"
- shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution
- has been received by Licensor and subsequently incorporated within the Work.\n\n2.
- Grant of Copyright License. Subject to the terms and conditions of this License,
- each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
- royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works
- of, publicly display, publicly perform, sublicense, and distribute the Work and
- such Derivative Works in Source or Object form.\n\n3. Grant of Patent License.
- Subject to the terms and conditions of this License, each Contributor hereby grants
- to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made, use, offer
- to sell, sell, import, and otherwise transfer the Work, where such license applies
- only to those patent claims licensable by such Contributor that are necessarily
- infringed by their Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You institute patent
- litigation against any entity (including a cross-claim or counterclaim in a lawsuit)
- alleging that the Work or a Contribution incorporated within the Work constitutes
- direct or contributory patent infringement, then any patent licenses granted to
- You under this License for that Work shall terminate as of the date such litigation
- is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without modifications,
- and in Source or Object form, provided that You meet the following conditions:\n\nYou
- must give any other recipients of the Work or Derivative Works a copy of this
- License; and\n\nYou must cause any modified files to carry prominent notices stating
- that You changed the files; and\n\nYou must retain, in the Source form of any
- Derivative Works that You distribute, all copyright, patent, trademark, and attribution
- notices from the Source form of the Work, excluding those notices that do not
- pertain to any part of the Derivative Works; and\n\nIf the Work includes a \"NOTICE\"
- text file as part of its distribution, then any Derivative Works that You distribute
- must include a readable copy of the attribution notices contained within such
- NOTICE file, excluding those notices that do not pertain to any part of the Derivative
- Works, in at least one of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or documentation, if provided
- along with the Derivative Works; or, within a display generated by the Derivative
- Works, if and wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and do not modify the License.
- You may add Your own attribution notices within Derivative Works that You distribute,
- alongside or as an addendum to the NOTICE text from the Work, provided that such
- additional attribution notices cannot be construed as modifying the License. You
- may add Your own copyright statement to Your modifications and may provide additional
- or different license terms and conditions for use, reproduction, or distribution
- of Your modifications, or for any such Derivative Works as a whole, provided Your
- use, reproduction, and distribution of the Work otherwise complies with the conditions
- stated in this License.\n\n5. Submission of Contributions. Unless You explicitly
- state otherwise, any Contribution intentionally submitted for inclusion in the
- Work by You to the Licensor shall be under the terms and conditions of this License,
- without any additional terms or conditions. Notwithstanding the above, nothing
- herein shall supersede or modify the terms of any separate license agreement you
- may have executed with Licensor regarding such Contributions.\n\n6. Trademarks.
- This License does not grant permission to use the trade names, trademarks, service
- marks, or product names of the Licensor, except as required for reasonable and
- customary use in describing the origin of the Work and reproducing the content
- of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable
- law or agreed to in writing, Licensor provides the Work (and each Contributor
- provides its Contributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS
- OF ANY KIND, either express or implied, including, without limitation, any warranties
- or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR
- PURPOSE. You are solely responsible for determining the appropriateness of using
- or redistributing the Work and assume any risks associated with Your exercise
- of permissions under this License.\n\n8. Limitation of Liability. In no event
- and under no legal theory, whether in tort (including negligence), contract, or
- otherwise, unless required by applicable law (such as deliberate and grossly negligent
- acts) or agreed to in writing, shall any Contributor be liable to You for damages,
- including any direct, indirect, special, incidental, or consequential damages
- of any character arising as a result of this License or out of the use or inability
- to use the Work (including but not limited to damages for loss of goodwill, work
- stoppage, computer failure or malfunction, or any and all other commercial damages
- or losses), even if such Contributor has been advised of the possibility of such
- damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer, and charge a fee
- for, acceptance of support, warranty, indemnity, or other liability obligations
- and/or rights consistent with this License. However, in accepting such obligations,
- You may act only on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify, defend, and hold
- each Contributor harmless for any liability incurred by, or claims asserted against,
- such Contributor by reason of your accepting any such warranty or additional liability.\n\nEND
- OF TERMS AND CONDITIONS\n"
-notices:
-- sources: AUTHORS.md
- text: "TypeScript is authored by:\r\n\r\n - 0verk1ll\r\n - Abubaker Bashir\r\n -
- Adam Freidin\r\n - Adam Postma\r\n - Adi Dahiya\r\n - Aditya Daflapurkar\r\n -
- Adnan Chowdhury\r\n - Adrian Leonhard\r\n - Adrien Gibrat\r\n - Ahmad Farid\r\n
- - Ajay Poshak\r\n - Alan Agius\r\n - Alan Pierce\r\n - Alessandro Vergani\r\n
- - Alex Chugaev\r\n - Alex Eagle\r\n - Alex Khomchenko\r\n - Alex Ryan\r\n - Alexander\r\n
- - Alexander Kuvaev\r\n - Alexander Rusakov\r\n - Alexander Tarasyuk\r\n - Ali
- Sabzevari\r\n - Aluan Haddad\r\n - amaksimovich2\r\n - Anatoly Ressin\r\n - Anders
- Hejlsberg\r\n - Anders Kaseorg\r\n - Andre Sutherland\r\n - Andreas Martin\r\n
- - Andrej Baran\r\n - Andrew\r\n - Andrew Branch\r\n - Andrew Casey\r\n - Andrew
- Faulkner\r\n - Andrew Ochsner\r\n - Andrew Stegmaier\r\n - Andrew Z Allen\r\n
- - Andrey Roenko\r\n - Andrii Dieiev\r\n - András Parditka\r\n - Andy Hanson\r\n
- - Anil Anar\r\n - Anix\r\n - Anton Khlynovskiy\r\n - Anton Tolmachev\r\n - Anubha
- Mathur\r\n - AnyhowStep\r\n - Armando Aguirre\r\n - Arnaud Tournier\r\n - Arnav
- Singh\r\n - Arpad Borsos\r\n - Artem Tyurin\r\n - Arthur Ozga\r\n - Asad Saeeduddin\r\n
- - Austin Cummings\r\n - Avery Morin\r\n - Aziz Khambati\r\n - Basarat Ali Syed\r\n
- - @begincalendar\r\n - Ben Duffield\r\n - Ben Lichtman\r\n - Ben Mosher\r\n -
- Benedikt Meurer\r\n - Benjamin Bock\r\n - Benjamin Lichtman\r\n - Benny Neugebauer\r\n
- - BigAru\r\n - Bill Ticehurst\r\n - Blaine Bublitz\r\n - Blake Embrey\r\n - @bluelovers\r\n
- - @bootstraponline\r\n - Bowden Kelly\r\n - Bowden Kenny\r\n - Brad Zacher\r\n
- - Brandon Banks\r\n - Brandon Bloom\r\n - Brandon Slade\r\n - Brendan Kenny\r\n
- - Brett Mayen\r\n - Brian Terlson\r\n - Bryan Forbes\r\n - Caitlin Potter\r\n
- - Caleb Sander\r\n - Cameron Taggart\r\n - @cedvdb\r\n - Charles\r\n - Charles
- Pierce\r\n - Charly POLY\r\n - Chris Bubernak\r\n - Chris Patterson\r\n - christian\r\n
- - Christophe Vidal\r\n - Chuck Jazdzewski\r\n - Clay Miller\r\n - Colby Russell\r\n
- - Colin Snover\r\n - Collins Abitekaniza\r\n - Connor Clark\r\n - Cotton Hou\r\n
- - csigs\r\n - Cyrus Najmabadi\r\n - Dafrok Zhang\r\n - Dahan Gong\r\n - Daiki
- Nishikawa\r\n - Dan Corder\r\n - Dan Freeman\r\n - Dan Quirk\r\n - Dan Rollo\r\n
- - Daniel Gooss\r\n - Daniel Imms\r\n - Daniel Krom\r\n - Daniel Król\r\n - Daniel
- Lehenbauer\r\n - Daniel Rosenwasser\r\n - David Li\r\n - David Sheldrick\r\n -
- David Sherret\r\n - David Souther\r\n - David Staheli\r\n - Denis Nedelyaev\r\n
- - Derek P Sifford\r\n - Dhruv Rajvanshi\r\n - Dick van den Brink\r\n - Diogo Franco
- (Kovensky)\r\n - Dirk Bäumer\r\n - Dirk Holtwick\r\n - Dmitrijs Minajevs\r\n -
- Dom Chen\r\n - Donald Pipowitch\r\n - Doug Ilijev\r\n - dreamran43@gmail.com\r\n
- - @e-cloud\r\n - Ecole Keine\r\n - Eddie Jaoude\r\n - Edward Thomson\r\n - EECOLOR\r\n
- - Eli Barzilay\r\n - Elizabeth Dinella\r\n - Ely Alamillo\r\n - Eric Grube\r\n
- - Eric Tsang\r\n - Erik Edrosa\r\n - Erik McClenney\r\n - Esakki Raj\r\n - Ethan
- Resnick\r\n - Ethan Rubio\r\n - Eugene Timokhov\r\n - Evan Cahill\r\n - Evan Martin\r\n
- - Evan Sebastian\r\n - ExE Boss\r\n - Eyas Sharaiha\r\n - Fabian Cook\r\n - @falsandtru\r\n
- - Filipe Silva\r\n - @flowmemo\r\n - Forbes Lindesay\r\n - Francois Hendriks\r\n
- - Francois Wouts\r\n - Frank Wallis\r\n - František Žiacik\r\n - Frederico Bittencourt\r\n
- - fullheightcoding\r\n - Gabe Moothart\r\n - Gabriel Isenberg\r\n - Gabriela Araujo
- Britto\r\n - Gabriela Britto\r\n - gb714us\r\n - Gilad Peleg\r\n - Godfrey Chan\r\n
- - Gorka Hernández Estomba\r\n - Graeme Wicksted\r\n - Guillaume Salles\r\n - Guy
- Bedford\r\n - hafiz\r\n - Halasi Tamás\r\n - Hendrik Liebau\r\n - Henry Mercer\r\n
- - Herrington Darkholme\r\n - Hoang Pham\r\n - Holger Jeromin\r\n - Homa Wong\r\n
- - Hye Sung Jung\r\n - Iain Monro\r\n - @IdeaHunter\r\n - Igor Novozhilov\r\n -
- Igor Oleinikov\r\n - Ika\r\n - iliashkolyar\r\n - IllusionMH\r\n - Ingvar Stepanyan\r\n
- - Ingvar Stepanyan\r\n - Isiah Meadows\r\n - ispedals\r\n - Ivan Enderlin\r\n
- - Ivo Gabe de Wolff\r\n - Iwata Hidetaka\r\n - Jack Bates\r\n - Jack Williams\r\n
- - Jake Boone\r\n - Jakub Korzeniowski\r\n - Jakub Młokosiewicz\r\n - James Henry\r\n
- - James Keane\r\n - James Whitney\r\n - Jan Melcher\r\n - Jason Freeman\r\n -
- Jason Jarrett\r\n - Jason Killian\r\n - Jason Ramsay\r\n - JBerger\r\n - Jean
- Pierre\r\n - Jed Mao\r\n - Jeff Wilcox\r\n - Jeffrey Morlan\r\n - Jesse Schalken\r\n
- - Jesse Trinity\r\n - Jing Ma\r\n - Jiri Tobisek\r\n - Joe Calzaretta\r\n - Joe
- Chung\r\n - Joel Day\r\n - Joey Watts\r\n - Johannes Rieken\r\n - John Doe\r\n
- - John Vilk\r\n - Jonathan Bond-Caron\r\n - Jonathan Park\r\n - Jonathan Toland\r\n
- - Jordan Harband\r\n - Jordi Oliveras Rovira\r\n - Joscha Feth\r\n - Joseph Wunderlich\r\n
- - Josh Abernathy\r\n - Josh Goldberg\r\n - Josh Kalderimis\r\n - Josh Soref\r\n
- - Juan Luis Boya García\r\n - Julian Williams\r\n - Justin Bay\r\n - Justin Johansson\r\n
- - jwbay\r\n - K. Preißer\r\n - Kagami Sascha Rosylight\r\n - Kanchalai Tanglertsampan\r\n
- - karthikkp\r\n - Kate Miháliková\r\n - Keen Yee Liau\r\n - Keith Mashinter\r\n
- - Ken Howard\r\n - Kenji Imamula\r\n - Kerem Kat\r\n - Kevin Donnelly\r\n - Kevin
- Gibbons\r\n - Kevin Lang\r\n - Khải\r\n - Kitson Kelly\r\n - Klaus Meinhardt\r\n
- - Kris Zyp\r\n - Kyle Kelley\r\n - Kārlis Gaņģis\r\n - laoxiong\r\n - Leon Aves\r\n
- - Limon Monte\r\n - Lorant Pinter\r\n - Lucien Greathouse\r\n - Luka Hartwig\r\n
- - Lukas Elmer\r\n - M.Yoshimura\r\n - Maarten Sijm\r\n - Magnus Hiie\r\n - Magnus
- Kulke\r\n - Manish Bansal\r\n - Manish Giri\r\n - Marcus Noble\r\n - Marin Marinov\r\n
- - Marius Schulz\r\n - Markus Johnsson\r\n - Markus Wolf\r\n - Martin\r\n - Martin
- Hiller\r\n - Martin Johns\r\n - Martin Probst\r\n - Martin Vseticka\r\n - Martyn
- Janes\r\n - Masahiro Wakame\r\n - Mateusz Burzyński\r\n - Matt Bierner\r\n - Matt
- McCutchen\r\n - Matt Mitchell\r\n - Matthew Aynalem\r\n - Matthew Miller\r\n -
- Mattias Buelens\r\n - Max Heiber\r\n - Maxwell Paul Brickner\r\n - @meyer\r\n
- - Micah Zoltu\r\n - @micbou\r\n - Michael\r\n - Michael Crane\r\n - Michael Henderson\r\n
- - Michael Tamm\r\n - Michael Tang\r\n - Michal Przybys\r\n - Mike Busyrev\r\n
- - Mike Morearty\r\n - Milosz Piechocki\r\n - Mine Starks\r\n - Minh Nguyen\r\n
- - Mohamed Hegazy\r\n - Mohsen Azimi\r\n - Mukesh Prasad\r\n - Myles Megyesi\r\n
- - Nathan Day\r\n - Nathan Fenner\r\n - Nathan Shively-Sanders\r\n - Nathan Yee\r\n
- - ncoley\r\n - Nicholas Yang\r\n - Nicu Micleușanu\r\n - @nieltg\r\n - Nima Zahedi\r\n
- - Noah Chen\r\n - Noel Varanda\r\n - Noel Yoo\r\n - Noj Vek\r\n - nrcoley\r\n
- - Nuno Arruda\r\n - Oleg Mihailik\r\n - Oleksandr Chekhovskyi\r\n - Omer Sheikh\r\n
- - Orta Therox\r\n - Orta Therox\r\n - Oskar Grunning\r\n - Oskar Segersva¨rd\r\n
- - Oussama Ben Brahim\r\n - Ozair Patel\r\n - Patrick McCartney\r\n - Patrick Zhong\r\n
- - Paul Koerbitz\r\n - Paul van Brenk\r\n - @pcbro\r\n - Pedro Maltez\r\n - Pete
- Bacon Darwin\r\n - Peter Burns\r\n - Peter Šándor\r\n - Philip Pesca\r\n - Philippe
- Voinov\r\n - Pi Lanningham\r\n - Piero Cangianiello\r\n - Pierre-Antoine Mills\r\n
- - @piloopin\r\n - Pranav Senthilnathan\r\n - Prateek Goel\r\n - Prateek Nayak\r\n
- - Prayag Verma\r\n - Priyantha Lankapura\r\n - @progre\r\n - Punya Biswal\r\n
- - r7kamura\r\n - Rado Kirov\r\n - Raj Dosanjh\r\n - rChaser53\r\n - Reiner Dolp\r\n
- - Remo H. Jansen\r\n - @rflorian\r\n - Rhys van der Waerden\r\n - @rhysd\r\n -
- Ricardo N Feliciano\r\n - Richard Karmazín\r\n - Richard Knoll\r\n - Roger Spratley\r\n
- - Ron Buckton\r\n - Rostislav Galimsky\r\n - Rowan Wyborn\r\n - rpgeeganage\r\n
- - Ruwan Pradeep Geeganage\r\n - Ryan Cavanaugh\r\n - Ryan Clarke\r\n - Ryohei
- Ikegami\r\n - Salisbury, Tom\r\n - Sam Bostock\r\n - Sam Drugan\r\n - Sam El-Husseini\r\n
- - Sam Lanning\r\n - Sangmin Lee\r\n - Sanket Mishra\r\n - Sarangan Rajamanickam\r\n
- - Sasha Joseph\r\n - Sean Barag\r\n - Sergey Rubanov\r\n - Sergey Shandar\r\n
- - Sergey Tychinin\r\n - Sergii Bezliudnyi\r\n - Sergio Baidon\r\n - Sharon Rolel\r\n
- - Sheetal Nandi\r\n - Shengping Zhong\r\n - Sheon Han\r\n - Shyyko Serhiy\r\n
- - Siddharth Singh\r\n - sisisin\r\n - Slawomir Sadziak\r\n - Solal Pirelli\r\n
- - Soo Jae Hwang\r\n - Stan Thomas\r\n - Stanislav Iliev\r\n - Stanislav Sysoev\r\n
- - Stas Vilchik\r\n - Stephan Ginthör\r\n - Steve Lucco\r\n - @styfle\r\n - Sudheesh
- Singanamalla\r\n - Suhas\r\n - Suhas Deshpande\r\n - superkd37\r\n - Sébastien
- Arod\r\n - @T18970237136\r\n - @t_\r\n - Tan Li Hau\r\n - Tapan Prakash\r\n -
- Taras Mankovski\r\n - Tarik Ozket\r\n - Tetsuharu Ohzeki\r\n - The Gitter Badger\r\n
- - Thomas den Hollander\r\n - Thorsten Ball\r\n - Tien Hoanhtien\r\n - Tim Lancina\r\n
- - Tim Perry\r\n - Tim Schaub\r\n - Tim Suchanek\r\n - Tim Viiding-Spader\r\n -
- Tingan Ho\r\n - Titian Cernicova-Dragomir\r\n - tkondo\r\n - Todd Thomson\r\n
- - togru\r\n - Tom J\r\n - Torben Fitschen\r\n - Toxyxer\r\n - @TravCav\r\n - Troy
- Tae\r\n - TruongSinh Tran-Nguyen\r\n - Tycho Grouwstra\r\n - uhyo\r\n - Vadi Taslim\r\n
- - Vakhurin Sergey\r\n - Valera Rozuvan\r\n - Vilic Vane\r\n - Vimal Raghubir\r\n
- - Vladimir Kurchatkin\r\n - Vladimir Matveev\r\n - Vyacheslav Pukhanov\r\n - Wenlu
- Wang\r\n - Wes Souza\r\n - Wesley Wigham\r\n - William Orr\r\n - Wilson Hobbs\r\n
- - xiaofa\r\n - xl1\r\n - Yacine Hmito\r\n - Yang Cao\r\n - York Yao\r\n - @yortus\r\n
- - Yoshiki Shibukawa\r\n - Yuichi Nukiyama\r\n - Yuval Greenfield\r\n - Yuya Tanaka\r\n
- - Z\r\n - Zeeshan Ahmed\r\n - Zev Spitz\r\n - Zhengbo Li\r\n - Zixiang Li\r\n
- - @Zzzen\r\n - 阿卡琳"
diff --git a/.licenses/npm/undici-types.dep.yml b/.licenses/npm/undici-types.dep.yml
deleted file mode 100644
index 370219bfa..000000000
--- a/.licenses/npm/undici-types.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: undici-types
-version: 7.8.0
-type: npm
-summary: A stand-alone types package for Undici
-homepage: https://undici.nodejs.org
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- MIT License
-
- Copyright (c) Matteo Collina and Undici contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices: []
diff --git a/.licenses/npm/undici.dep.yml b/.licenses/npm/undici.dep.yml
index fadecf4a7..b339a4487 100644
--- a/.licenses/npm/undici.dep.yml
+++ b/.licenses/npm/undici.dep.yml
@@ -1,6 +1,6 @@
---
name: undici
-version: 5.29.0
+version: 6.28.0
type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org
diff --git a/.licenses/npm/uuid-3.4.0.dep.yml b/.licenses/npm/uuid-3.4.0.dep.yml
deleted file mode 100644
index 45970fef6..000000000
--- a/.licenses/npm/uuid-3.4.0.dep.yml
+++ /dev/null
@@ -1,39 +0,0 @@
----
-name: uuid
-version: 3.4.0
-type: npm
-summary: RFC4122 (v1, v4, and v5) UUIDs
-homepage: https://github.com/uuidjs/uuid#readme
-license: mit
-licenses:
-- sources: LICENSE.md
- text: |
- The MIT License (MIT)
-
- Copyright (c) 2010-2016 Robert Kieffer and other contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-notices:
-- sources: AUTHORS
- text: |-
- Robert Kieffer
- Christoph Tavan
- AJ ONeal
- Vincent Voyer
- Roman Shtylman
diff --git a/.licenses/npm/uuid-8.3.2.dep.yml b/.licenses/npm/uuid-8.3.2.dep.yml
deleted file mode 100644
index bf84da082..000000000
--- a/.licenses/npm/uuid-8.3.2.dep.yml
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: uuid
-version: 8.3.2
-type: npm
-summary: RFC4122 (v1, v4, and v5) UUIDs
-homepage: https://github.com/uuidjs/uuid#readme
-license: mit
-licenses:
-- sources: LICENSE.md
- text: |
- The MIT License (MIT)
-
- Copyright (c) 2010-2020 Robert Kieffer and other contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-notices: []
diff --git a/.licenses/npm/webidl-conversions.dep.yml b/.licenses/npm/webidl-conversions.dep.yml
deleted file mode 100644
index 48c1f2272..000000000
--- a/.licenses/npm/webidl-conversions.dep.yml
+++ /dev/null
@@ -1,23 +0,0 @@
----
-name: webidl-conversions
-version: 3.0.1
-type: npm
-summary: Implements the WebIDL algorithms for converting to and from JavaScript values
-homepage: https://github.com/jsdom/webidl-conversions#readme
-license: bsd-2-clause
-licenses:
-- sources: LICENSE.md
- text: |
- # The BSD 2-Clause License
-
- Copyright (c) 2014, Domenic Denicola
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-notices: []
diff --git a/.licenses/npm/whatwg-url.dep.yml b/.licenses/npm/whatwg-url.dep.yml
deleted file mode 100644
index bca799ccc..000000000
--- a/.licenses/npm/whatwg-url.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: whatwg-url
-version: 5.0.0
-type: npm
-summary: An implementation of the WHATWG URL Standard's URL API and parsing machinery
-homepage: https://github.com/jsdom/whatwg-url#readme
-license: mit
-licenses:
-- sources: LICENSE.txt
- text: |
- The MIT License (MIT)
-
- Copyright (c) 2015–2016 Sebastian Mayr
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-notices: []
diff --git a/.licenses/npm/@oozcitak/infra.dep.yml b/.licenses/npm/xml-naming.dep.yml
similarity index 83%
rename from .licenses/npm/@oozcitak/infra.dep.yml
rename to .licenses/npm/xml-naming.dep.yml
index eeac49dd3..bfc32c71c 100644
--- a/.licenses/npm/@oozcitak/infra.dep.yml
+++ b/.licenses/npm/xml-naming.dep.yml
@@ -1,16 +1,17 @@
---
-name: "@oozcitak/infra"
-version: 1.0.8
+name: xml-naming
+version: 0.3.0
type: npm
-summary: An implementation of the Infra Living Standard
-homepage: http://github.com/oozcitak/infra
+summary: Validates XML name productions — Name, NCName, QName, NMToken, NMTokens —
+ for XML 1.0 and 1.1
+homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
- Copyright (c) 2019 Ozgur Ozcitak
+ Copyright (c) 2026 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -29,4 +30,6 @@ licenses:
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+- sources: README.md
+ text: MIT
notices: []
diff --git a/.licenses/npm/xml2js.dep.yml b/.licenses/npm/xml2js.dep.yml
deleted file mode 100644
index 92bce8dda..000000000
--- a/.licenses/npm/xml2js.dep.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-name: xml2js
-version: 0.5.0
-type: npm
-summary: Simple XML to JavaScript object converter.
-homepage: https://github.com/Leonidas-from-XIV/node-xml2js
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- Copyright 2010, 2011, 2012, 2013. All rights reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to
- deal in the Software without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- IN THE SOFTWARE.
-notices: []
diff --git a/.licenses/npm/xmlbuilder.dep.yml b/.licenses/npm/xmlbuilder.dep.yml
deleted file mode 100644
index e8c7ee12f..000000000
--- a/.licenses/npm/xmlbuilder.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: xmlbuilder
-version: 11.0.1
-type: npm
-summary: An XML builder for node.js
-homepage: http://github.com/oozcitak/xmlbuilder-js
-license: mit
-licenses:
-- sources: LICENSE
- text: |
- The MIT License (MIT)
-
- Copyright (c) 2013 Ozgur Ozcitak
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-notices: []
diff --git a/.prettierrc.js b/.prettierrc.js
deleted file mode 100644
index 468cdb1e2..000000000
--- a/.prettierrc.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
-module.exports = {
- printWidth: 80,
- tabWidth: 2,
- useTabs: false,
- semi: true,
- singleQuote: true,
- trailingComma: 'none',
- bracketSpacing: false,
- arrowParens: 'avoid'
-};
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 000000000..b243c2ff0
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,10 @@
+{
+ "printWidth": 80,
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": true,
+ "singleQuote": true,
+ "trailingComma": "none",
+ "bracketSpacing": false,
+ "arrowParens": "avoid"
+}
diff --git a/README.md b/README.md
index 844fa9933..0f1d0f209 100644
--- a/README.md
+++ b/README.md
@@ -4,276 +4,471 @@
[](https://github.com/actions/setup-java/actions/workflows/e2e-versions.yml)
[](https://github.com/actions/setup-java/actions/workflows/e2e-cache.yml)
-The `setup-java` action provides the following functionality for GitHub Actions runners:
-- Downloading and setting up a requested version of Java. See [Usage](#usage) for a list of supported distributions.
-- Extracting and caching custom version of Java from a local file.
-- Configuring runner for publishing using Apache Maven.
-- Configuring runner for publishing using Gradle.
-- Configuring runner for using GPG private key.
-- Registering problem matchers for error output.
-- Caching dependencies managed by Apache Maven.
-- Caching dependencies managed by Gradle.
-- Caching dependencies managed by sbt.
-- [Maven Toolchains declaration](https://maven.apache.org/guides/mini/guide-using-toolchains.html) for specified JDK versions.
+Set up Java for GitHub Actions workflows. `setup-java` installs a requested Java distribution, adds it to `PATH`, configures `JAVA_HOME`, and can optionally cache build dependencies for Apache Maven, Gradle, and sbt; generate Maven publishing configuration, verify JDK package signatures, manage multiple JDKs, and manage Maven toolchains.
-This action allows you to work with Java and Scala projects.
-
-## V2 vs V1
+```yaml
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ - run: java --version
+```
-- V2 supports custom distributions and provides support for Azul Zulu OpenJDK, Eclipse Temurin and AdoptOpenJDK out of the box. V1 supports only Azul Zulu OpenJDK.
-- V2 requires you to specify distribution along with the version. V1 defaults to Azul Zulu OpenJDK, only version input is required. Follow [the migration guide](docs/switching-to-v2.md) to switch from V1 to V2.
+> [!NOTE]
+> V6 is still in development on the `main` branch and is not yet recommended for production workflows. To use it, you must explicitly reference the `main` branch in your workflow, as in
+>
+> ```yaml
+> - uses: actions/setup-java@main
+> ```
+>
+> For production workflows, it is recommended to use the latest stable release `v5`.
+
+## Contents
+
+- [What it does](#what-it-does)
+- [What's new](#whats-new)
+- [Usage](#usage)
+- [Inputs](#inputs)
+- [Supported distributions](#supported-distributions)
+- [Supported version syntax](#supported-version-syntax)
+- [Caching](#caching)
+- [Multiple JDKs and Maven toolchains](#multiple-jdks-and-maven-toolchains)
+- [Publishing packages](#publishing-packages)
+- [Advanced usage](#advanced-usage)
+
+## What it does
+
+- Downloads and installs Java from a supported distribution.
+- Uses a requested Java version, a version file, or the `latest` stable release alias.
+- Extracts and caches a custom JDK archive from a local file.
+- Configures Maven `settings.xml`, Maven Toolchains, Maven GPG signing inputs, and environment-variable based credentials for publishing workflows.
+- Registers Java problem matchers for compiler diagnostics and uncaught exceptions.
+- Caches dependencies for Maven, Gradle, and sbt.
+- Caches downloaded JDK installations between jobs.
+- Verifies downloaded archive checksums when a distribution publishes authoritative checksums.
+- Optionally verifies package signatures for supported distributions.
+
+`setup-java` works with Java, Scala, Kotlin, Gradle, Maven, and sbt projects.
+
+## What's new
+
+### V6 (in development)
+
+- Migrated the action implementation to ESM to support the latest `@actions/*` packages.
+- Added the `oracle-openjdk` distribution for OpenJDK builds from Oracle.
+- Added `java-version: latest` to resolve the newest stable GA release from the distribution's remote metadata.
+- JDK downloads now automatically verify authoritative checksums for [supported distributions](#download-integrity-and-signatures).
+- Added `force-download: true` to bypass the tool cache and perform a reproducible fresh install.
+- Dependency caching now supports custom paths with `cache-path` and restore-only operation with `cache-read-only: true`.
+- Downloaded JDKs are now [cached](#caching-jdk-installations) automatically when `cache` is set; use `cache-jdk` to enable or disable it independently.
+- Set `problem-matcher: false` to disable Java compiler and uncaught-exception annotations.
+- GraalVM distributions now set `GRAALVM_HOME` in addition to `JAVA_HOME`.
+- Invalid boolean values, unsupported distribution/package/platform combinations, and mismatched Maven toolchain ID counts now fail with targeted errors.
+- Renamed environment-variable-name inputs so they are not mistaken for secret values:
+ - `server-username` -> `server-username-env-var`
+ - `server-password` -> `server-password-env-var`
+ - `gpg-passphrase` -> `gpg-passphrase-env-var`
+- Deprecated aliases still work, but emit warnings.
+- Maven GPG passphrases are now passed through `gpg.passphraseEnvName` instead of a deprecated `gpg.passphrase` server entry in `settings.xml`. This requires `maven-gpg-plugin` 3.2.0 or newer. See [GPG](docs/advanced-usage.md#gpg).
+- Legacy AdoptOpenJDK distributions were removed. Use `temurin` instead of `adopt` or `adopt-hotspot`, and `semeru` instead of `adopt-openj9`.
+
+### V5
+
+- Upgraded the action runtime from Node 20 to Node 24. Self-hosted runners must use version `v2.327.1` or later. See the [runner release notes](https://github.com/actions/runner/releases/tag/v2.327.1).
+- Added support for [GraalVM Community](#supported-distributions) and [Tencent Kona](#supported-distributions).
+- Expanded `java-version-file` support with `.sdkmanrc` files and automatic distribution detection from SDKMAN and asdf vendor identifiers.
+- Added optional package-signature verification for Eclipse Temurin and Microsoft Build of OpenJDK downloads.
+- Added `set-default: false` for installing a JDK without changing `JAVA_HOME` or `PATH`.
+- Improved dependency caching with separate Maven and Gradle wrapper caches, Maven extension-aware cache keys, and the `cache-primary-key` output.
+- Improved Maven and Java build behavior by preserving toolchain entries across repeated action invocations, suppressing transfer progress by default, generating non-interactive Maven settings, and matching `javac` compiler errors.
+- Renamed the `jdkFile` input to `jdk-file`; the old name remains available as a deprecated alias.
+- See the [complete V5 release history](https://github.com/actions/setup-java/releases?q=v5&expanded=true) for enhancements and fixes across all V5 releases.
+
+### Older versions
+
+> [!WARNING]
+> `actions/setup-java` versions `v1` through `v4` are deprecated. Upgrade workflows to `actions/setup-java@v5`, the latest stable release.
## Usage
- - `java-version`: The Java version that is going to be set up. Takes a whole or [semver](#supported-version-syntax) Java version. If not specified, the action will expect `java-version-file` input to be specified.
-
- - `java-version-file`: The path to a file containing java version. Supported file types are `.java-version` and `.tool-versions`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file).
-
- - `distribution`: _(required)_ Java [distribution](#supported-distributions).
-
- - `java-package`: The packaging variant of the chosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. Default value: `jdk`.
-
- - `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine.
-
- - `jdkFile`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM.
+### Install Eclipse Temurin
- - `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
-
- - `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
+```yaml
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ - run: java --version
+```
- - `cache-dependency-path`: The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.
+### Install Microsoft Build of OpenJDK
- #### Maven options
- The action has a bunch of inputs to generate maven's [settings.xml](https://maven.apache.org/settings.html) on the fly and pass the values to Apache Maven GPG Plugin as well as Apache Maven Toolchains. See [advanced usage](docs/advanced-usage.md) for more.
+```yaml
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: microsoft
+ java-version: '25'
+ - run: java --version
+```
- - `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists, set this to `false`.
+### Read the version from a file
- - `server-id`: ID of the distributionManagement repository in the pom.xml file. Default is `github`.
+```yaml
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version-file: .java-version
+ - run: java --version
+```
- - `server-username`: Environment variable name for the username for authentication to the Apache Maven repository. Default is GITHUB_ACTOR.
+Supported version files are `.java-version`, `.tool-versions`, and `.sdkmanrc`. A `.sdkmanrc` file can also provide the distribution when it contains a recognized suffix, such as `java=21.0.5-tem`.
- - `server-password`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB_TOKEN.
+### Use the newest stable Java
- - `settings-path`: Maven related setting to point to the directory where the settings.xml file will be written. Default is ~/.m2.
+```yaml
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: latest
+ - run: java --version
+```
- - `gpg-private-key`: GPG private key to import. Default is empty string.
+`latest` resolves the newest stable GA release from remote metadata rather than from the runner tool cache. Distributions that do not publish a release listing (such as `oracle` and `graalvm`) resolve the newest GA feature version from the Adoptium available-releases API and then request that version from their own catalog. `latest` is not supported with `java-version-file`, early-access versions, or `distribution: jdkfile`.
+
+## Inputs
+
+| Input | Description | Default |
+| --- | --- | --- |
+| `java-version` | Java version to install. Supports whole versions, semver ranges, early-access versions, and `latest`. Required unless `java-version-file` is set. | |
+| `java-version-file` | Path to `.java-version`, `.tool-versions`, or `.sdkmanrc`. Used when `java-version` is not set. | |
+| `distribution` | Java distribution keyword. Values are case-sensitive and must match one of the supported keywords below. Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix. | |
+| `java-package` | Package variant such as `jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, or `jre+ft`. Support varies by distribution. | `jdk` |
+| `architecture` | Package architecture. Canonical values are `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`, `ppc64`, and `s390x`. Aliases `ia32`, `amd64`, `arm`, and `arm64` are normalized. | Runner architecture |
+| `jdk-file` | Local compressed JDK archive. Requires `distribution: jdkfile`. | |
+| `check-latest` | Check remote metadata for the latest version satisfying the version spec before using the runner tool cache. | `false` |
+| `force-download` | Always download Java and replace any matching version in the tool cache. | `false` |
+| `set-default` | Add Java to `PATH` and set `JAVA_HOME`. When `false`, only version-specific `JAVA_HOME__` variables are set. | `true` |
+| `problem-matcher` | Register Java compiler and uncaught exception problem matchers. | `true` |
+| `verify-signature` | Verify downloaded Java package signatures when supported. Currently supported for `temurin` and `microsoft`. | `false` |
+| `verify-signature-public-key` | ASCII-armored GPG public key to use for signature verification. Overrides the bundled key. | |
+| `token` | Token for fetching GitHub.com-hosted version manifests, useful on GitHub Enterprise Server when unauthenticated requests are rate-limited. | `${{ github.token }}` on GitHub.com; empty string on GHES |
+| `cache` | Enable dependency caching for `maven`, `gradle`, or `sbt`. | |
+| `cache-jdk` | Cache downloaded JDK installations between jobs. When omitted, JDK caching is enabled only if `cache` is set. Set explicitly to `true` or `false` to override. | Enabled when `cache` is set |
+| `cache-dependency-path` | Dependency file paths used for cache key hashing. Supports globs and multiline values. | Auto-detected by package manager |
+| `cache-path` | Cache paths to use instead of the package manager's default dependency cache path. Supports multiline values and exclusions. | |
+| `cache-read-only` | Restore dependency, wrapper, and JDK caches without saving changes in the post step. | `false` |
+| `server-id` | Maven repository ID used in generated `settings.xml`. | `github` |
+| `server-username-env-var` | Environment variable name for Maven repository username. | `GITHUB_ACTOR` |
+| `server-password-env-var` | Environment variable name for Maven repository password or token. | `GITHUB_TOKEN` |
+| `settings-path` | Directory where `settings.xml` is written. | `~/.m2` |
+| `overwrite-settings` | Overwrite an existing `settings.xml`. | `true` |
+| `gpg-private-key` | GPG private key to import into an isolated temporary keyring. | |
+| `gpg-passphrase-env-var` | Environment variable name for the GPG private key passphrase. | `GPG_PASSPHRASE` when a key is set |
+| `mvn-toolchain-id` | Maven Toolchain ID. When multiple Java versions are installed, the number of IDs must match the number of versions. | `${mvn-toolchain-vendor}_${java-version}` |
+| `mvn-toolchain-vendor` | Maven Toolchain vendor value. | `${distribution}` |
+| `show-download-progress` | Keep Maven artifact download and transfer progress in logs. When `false`, the action adds `-ntp` to `MAVEN_ARGS`. | `false` |
+
+- `java-package`: Supported package types are `jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, and `jre+ft`. Availability varies by distribution.
+
+Deprecated aliases `jdkFile`, `server-username`, `server-password`, and `gpg-passphrase` remain accepted for compatibility, but should be replaced with the current input names.
+
+## Outputs
+
+| Output | Description |
+| --- | --- |
+| `distribution` | Distribution that was installed. |
+| `version` | Actual Java version that was installed. |
+| `path` | Installation path, also used for `JAVA_HOME` when `set-default` is enabled. |
+| `cache-hit` | Whether an exact dependency cache match was restored. |
+| `cache-primary-key` | Primary cache key computed for the selected package manager. Empty when caching is disabled or skipped. |
+
+## Supported distributions
+
+| Keyword | Distribution | License |
+| --- | --- | --- |
+| `corretto` | [Amazon Corretto](https://aws.amazon.com/corretto/) | [License](https://aws.amazon.com/corretto/faqs/) |
+| `dragonwell` | [Alibaba Dragonwell JDK](https://dragonwell-jdk.io/) | [License](https://www.aliyun.com/product/dragonwell/) |
+| `graalvm` | [Oracle GraalVM](https://www.graalvm.org/) | [License](https://www.oracle.com/downloads/licenses/graal-free-license.html) |
+| `graalvm-community` | [GraalVM Community](https://github.com/graalvm/graalvm-ce-builds/releases) | [License](https://github.com/oracle/graal/blob/master/LICENSE) |
+| `jetbrains` | [JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/) | [License](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE) |
+| `kona` | [Tencent Kona JDK](https://tencent.github.io/konajdk/) | [License](https://tencent.github.io/konajdk/LICENSE.txt) |
+| `liberica` | [Liberica JDK](https://bell-sw.com/) | [License](https://bell-sw.com/liberica_eula/) |
+| `liberica-nik` | [Liberica Native Image Kit](https://bell-sw.com/pages/downloads/native-image-kit/) | [License](https://bell-sw.com/liberica_nik_eula/) |
+| `microsoft` | [Microsoft Build of OpenJDK](https://www.microsoft.com/openjdk) | [License](https://docs.microsoft.com/java/openjdk/faq) |
+| `oracle` | [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) | [License](https://java.com/freeuselicense) |
+| `oracle-openjdk` | [Oracle OpenJDK](https://jdk.java.net/) | [License](https://openjdk.org/legal/gplv2+ce.html) |
+| `sapmachine` | [SAP SapMachine JDK/JRE](https://sapmachine.io/) | [License](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE) |
+| `semeru` | [IBM Semeru Runtime Open Edition](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [License](https://openjdk.java.net/legal/gplv2+ce.html) |
+| `temurin` | [Eclipse Temurin](https://adoptium.net/) | [License](https://adoptium.net/about.html) |
+| `zulu` | [Azul Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/?package=jdk) | [License](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) |
+| `jdkfile` | Custom JDK archive | |
+
+> [!NOTE]
+> Distribution availability, package variants, architectures, and version metadata differ by vendor. Check the vendor documentation when a specific version or platform matters.
+
+Additional distribution notes:
+
+- Oracle OpenJDK builds are archived after a limited number of releases and no longer receive security updates. To continue receiving security patches, use Oracle JDK or another vendor.
+- Azul Zulu maps `arm64` to `aarch64` when querying the Azul Metadata API.
+- GraalVM Community is available as `distribution: graalvm-community` for stable JDK 17 and later releases.
+- On Ubuntu runners, commands executed with `sudo` do not inherit the `JAVA_HOME` and `PATH` set by `setup-java` and may fall back to the system-default JDK.
+
+## Supported version syntax
+
+`java-version` accepts exact versions, version ranges, early-access versions, and `latest`.
+
+| Syntax | Examples |
+| --- | --- |
+| Major version | `8`, `11`, `17`, `21`, `25` |
+| Specific feature or patch version | `11.0`, `11.0.4`, `17.0`, `8.0.282+8` |
+| JEP 322 multi-field versions | `11.0.9.1`, `18.0.1.1` |
+| Early access | `15-ea`, `15.0.0-ea`, `27-ea` |
+| Latest stable GA release | `latest` |
+
+When `check-latest` is `false`, the action first tries the runner tool cache for the requested distribution, package type, architecture, and version range. It downloads Java only when no matching cached version is found. When `check-latest` is `true`, the action checks remote metadata first and downloads if the cached version is not current.
+
+GitHub-hosted runners primarily pre-cache Eclipse Temurin JDKs. See the installed Java versions for [Ubuntu](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md#java), [Windows](https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-Readme.md#java), and [macOS](https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md#java). On a fresh GitHub-hosted runner, requests for other distributions usually miss the tool cache and resolve from remote metadata. For broad version ranges such as a major version (`21`, `25`), this often behaves similarly to `check-latest: true` because the action downloads the latest available release that satisfies the range.
+
+## Download integrity and signatures
+
+`setup-java` automatically verifies downloaded archive checksums when a selected distribution publishes an authoritative checksum. Automatic checksum verification currently applies to `temurin`, `semeru`, `corretto`, `dragonwell`, `kona`, `sapmachine`, `graalvm`, `graalvm-community`, `zulu`, `oracle`, `oracle-openjdk`, `microsoft`, and `jetbrains`.
+
+Distributions or individual releases without an authoritative checksum continue to install normally, with the omission reported in debug logs. Installations resolved directly from the runner tool cache — including JDKs preinstalled on the runner image and JDKs installed by an earlier step of the same job — are not downloaded again and are not reverified, even when `verify-signature: true` is set. Use `force-download: true` to always download and verify the archive.
+
+Use `verify-signature: true` to verify package signatures for distributions that support it. Currently supported distributions are `temurin` and `microsoft`; setting it for an unsupported distribution fails the workflow.
+
+## Caching
+
+`setup-java` manages three kinds of caches. Each one is restored and saved as a separate cache entry.
+
+| Cache | What it stores | Key based on | How it is enabled |
+| --- | --- | --- | --- |
+| Dependency cache | Downloaded dependencies, such as `~/.m2/repository`, `~/.gradle/caches`, or the sbt cache paths | Runner OS, architecture, package manager, and a hash of the dependency files | Set `cache` to `maven`, `gradle`, or `sbt` |
+| Wrapper caches | Maven and Gradle wrapper distributions (`~/.m2/wrapper/dists`, `~/.gradle/wrapper`) | Runner OS, architecture, wrapper cache name, and a hash of the wrapper properties | Set `cache` to `maven` or `gradle` |
+| JDK cache | The downloaded JDK installation | Runner OS, architecture, distribution, package type, resolved version, release identity, and signature-verification identity | Enabled implicitly whenever `cache` is set, or explicitly with `cache-jdk: true`. Opt out with `cache-jdk: false` |
+
+Set `cache` to `maven`, `gradle`, or `sbt` to cache dependencies with minimal configuration.
- - `gpg-passphrase`: Environment variable name for the GPG private key passphrase. Default is GPG_PASSPHRASE.
+```yaml
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ cache: maven
+ - run: mvn verify
+```
- - `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted.
+The primary dependency cache key is `setup-java----`, where `` is the runner's Node.js process architecture. The primary cache stores dependency directories such as `~/.m2/repository`, `~/.gradle/caches`, or the sbt cache paths. Its file hash is based on these files by default:
- - `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
+| Package manager | Files used for the primary dependency-cache key |
+| --- | --- |
+| Gradle | `**/*.gradle*`, `**/gradle.properties`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, `**/versions.properties` |
+| Maven | `**/pom.xml`, `**/.mvn/wrapper/maven-wrapper.properties`, `**/.mvn/extensions.xml` |
+| sbt | `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt` |
-### Basic Configuration
+Use `cache-dependency-path` to override the files used for key hashing, especially in monorepos:
-#### Eclipse Temurin
```yaml
-steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-java@v4
+- uses: actions/setup-java@v5
with:
- distribution: 'temurin' # See 'Supported distributions' for available options
- java-version: '21'
-- run: java HelloWorldApp.java
+ distribution: temurin
+ java-version: '25'
+ cache: gradle
+ cache-dependency-path: |
+ sub-project/*.gradle*
+ sub-project/**/gradle-wrapper.properties
```
-#### Azul Zulu OpenJDK
+Use `cache-path` when the build tool stores dependencies outside the default location:
+
```yaml
-steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-java@v4
+- uses: actions/setup-java@v5
with:
- distribution: 'zulu' # See 'Supported distributions' for available options
- java-version: '21'
-- run: java HelloWorldApp.java
+ distribution: temurin
+ java-version: '25'
+ cache: maven
+ cache-path: |
+ /custom/maven/repository
+ !/custom/maven/repository/**/*.lastUpdated
+- run: mvn -Dmaven.repo.local=/custom/maven/repository verify
```
-#### Supported version syntax
-The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation:
-- major versions: `8`, `11`, `16`, `17`, `21`
-- more specific versions: `8.0.282+8`, `8.0.232`, `11.0`, `11.0.4`, `17.0`
-- early access (EA) versions: `15-ea`, `15.0.0-ea`
+`cache-path` changes what is restored and saved, but not the cache key. Jobs that should share a cache key must use the same OS, architecture, package manager, dependency files, and cache paths.
-#### Supported distributions
-Currently, the following distributions are supported:
-| Keyword | Distribution | Official site | License
-|-|-|-|-|
-| `temurin` | Eclipse Temurin | [Link](https://adoptium.net/) | [Link](https://adoptium.net/about.html)
-| `zulu` | Azul Zulu OpenJDK | [Link](https://www.azul.com/downloads/zulu-community/?package=jdk) | [Link](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) |
-| `adopt` or `adopt-hotspot` | AdoptOpenJDK Hotspot | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) |
-| `adopt-openj9` | AdoptOpenJDK OpenJ9 | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) |
-| `liberica` | Liberica JDK | [Link](https://bell-sw.com/) | [Link](https://bell-sw.com/liberica_eula/) |
-| `microsoft` | Microsoft Build of OpenJDK | [Link](https://www.microsoft.com/openjdk) | [Link](https://docs.microsoft.com/java/openjdk/faq)
-| `corretto` | Amazon Corretto Build of OpenJDK | [Link](https://aws.amazon.com/corretto/) | [Link](https://aws.amazon.com/corretto/faqs/)
-| `semeru` | IBM Semeru Runtime Open Edition | [Link](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [Link](https://openjdk.java.net/legal/gplv2+ce.html) |
-| `oracle` | Oracle JDK | [Link](https://www.oracle.com/java/technologies/downloads/) | [Link](https://java.com/freeuselicense)
-| `dragonwell` | Alibaba Dragonwell JDK | [Link](https://dragonwell-jdk.io/) | [Link](https://www.aliyun.com/product/dragonwell/)
-| `sapmachine` | SAP SapMachine JDK/JRE | [Link](https://sapmachine.io/) | [Link](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE)
-| `graalvm` | Oracle GraalVM | [Link](https://www.graalvm.org/) | [Link](https://www.oracle.com/downloads/licenses/graal-free-license.html)
-| `jetbrains` | JetBrains Runtime | [Link](https://github.com/JetBrains/JetBrainsRuntime/) | [Link](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE)
+### Wrapper caches
-**NOTE:** The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions.
+Maven and Gradle wrapper distributions are restored and saved as additional cache entries, separate from the primary dependency cache. These entries have their own keys in the form `setup-java----`.
-**NOTE:** AdoptOpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from `adopt` and `adopt-openj9`, to `temurin` and `semeru` respectively, to keep receiving software and security updates. See more details in the [Good-bye AdoptOpenJDK post](https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/).
+| Package manager | Wrapper cache name | Cached path | Files used for wrapper-cache key |
+| --- | --- | --- | --- |
+| Maven | `maven-wrapper` | `~/.m2/wrapper/dists` | `**/.mvn/wrapper/maven-wrapper.properties` |
+| Gradle | `gradle-wrapper` | `~/.gradle/wrapper` | `**/gradle-wrapper.properties` |
-**NOTE:** For Azul Zulu OpenJDK architectures x64 and arm64 are mapped to x86 / arm with proper hw_bitness.
+These wrapper caches are independent from dependency caches, so they remain useful even when dependency files change frequently. The wrapper properties are also part of the Maven and Gradle primary dependency-cache key because wrapper changes can affect how dependencies are resolved, but the wrapper distribution files themselves are stored in the separate wrapper cache entries above.
-**NOTE:** To comply with the GraalVM Free Terms and Conditions (GFTC) license, it is recommended to use GraalVM JDK 17 version 17.0.12, as this is the only version of GraalVM JDK 17 available under the GFTC license. Additionally, it is encouraged to consider upgrading to GraalVM JDK 21, which offers the latest features and improvements.
+For advanced Gradle caching features such as build output caching, configuration cache support, encrypted cache storage, cleanup, and fine-grained cache control, consider [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle).
-### Caching packages dependencies
-The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files:
+### Caching JDK installations
-- gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties`
-- maven: `**/pom.xml`
-- sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt`
+The JDK cache stores the downloaded JDK installation so later runs skip the download. It is enabled implicitly whenever dependency `cache` is set, so most workflows that cache dependencies are already caching the JDK. Set `cache-jdk: true` to enable it without dependency caching, or `cache-jdk: false` to opt out while keeping dependency caching. With neither `cache` nor `cache-jdk` set, nothing is cached.
-When the option `cache-dependency-path` is specified, the hash is based on the matching file. This option supports wildcards and a list of file names, and is especially useful for monorepos.
+> [!IMPORTANT]
+> Because JDK caching is on by default whenever `cache` is set, review [Caching JDK installations](docs/advanced-usage.md#caching-jdk-installations)
+> for the full `cache`/`cache-jdk` matrix, cache identity and storage impact.
-The workflow output `cache-hit` is set to indicate if an exact match was found for the key [as actions/cache does](https://github.com/actions/cache/tree/main#outputs).
+### Read-only caches
-The cache input is optional, and caching is turned off by default.
+Set `cache-read-only: true` to restore dependency, wrapper, and JDK caches without saving changes in the post action. This is useful for pull requests, merge queues, short-lived branches, and matrix fan-out jobs that should only consume caches produced elsewhere.
-#### Caching gradle dependencies
```yaml
-steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-java@v4
+- uses: actions/setup-java@v5
with:
- distribution: 'temurin'
- java-version: '21'
- cache: 'gradle'
- cache-dependency-path: | # optional
- sub-project/*.gradle*
- sub-project/**/gradle-wrapper.properties
-- run: ./gradlew build --no-daemon
+ distribution: temurin
+ java-version: '25'
+ cache: maven
+ cache-read-only: ${{ github.ref != 'refs/heads/main' }}
```
-#### Caching maven dependencies
-```yaml
-steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-java@v4
- with:
- distribution: 'temurin'
- java-version: '21'
- cache: 'maven'
- cache-dependency-path: 'sub-project/pom.xml' # optional
-- name: Build with Maven
- run: mvn -B package --file pom.xml
-```
+For matrix fan-out, seed the cache once and make matrix jobs read-only consumers:
-#### Caching sbt dependencies
```yaml
-steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-java@v4
- with:
- distribution: 'temurin'
- java-version: '21'
- cache: 'sbt'
- cache-dependency-path: | # optional
- sub-project/build.sbt
- sub-project/project/build.properties
-- name: Build with SBT
- run: sbt package
+jobs:
+ seed-cache:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ cache: maven
+ - run: mvn dependency:go-offline dependency:resolve-plugins
+
+ build:
+ needs: seed-cache
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ goal: [test, verify, package]
+ steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ cache: maven
+ cache-read-only: true
+ - run: mvn ${{ matrix.goal }}
```
-#### Cache segment restore timeout
-Usually, cache gets downloaded in multiple segments of fixed sizes. Sometimes, a segment download gets stuck, which causes the workflow job to be stuck. The cache segment download timeout [was introduced](https://github.com/actions/toolkit/tree/main/packages/cache#cache-segment-restore-timeout) to solve this issue as it allows the segment download to get aborted and hence allows the job to proceed with a cache miss. The default value of the cache segment download timeout is set to 10 minutes and can be customized by specifying an environment variable named `SEGMENT_DOWNLOAD_TIMEOUT_MINS` with a timeout value in minutes.
+### Cache segment restore timeout
+
+Cache downloads are split into segments. To reduce the chance of a stuck segment blocking a workflow, set `SEGMENT_DOWNLOAD_TIMEOUT_MINS`:
```yaml
env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '5'
steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-java@v4
- with:
- distribution: 'temurin'
- java-version: '21'
- cache: 'gradle'
-- run: ./gradlew build --no-daemon
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ cache: gradle
+ - run: ./gradlew build --no-daemon
```
-### Check latest
-
-In the basic examples above, the `check-latest` flag defaults to `false`. When set to `false`, the action tries to first resolve a version of Java from the local tool cache on the runner. If unable to find a specific version in the cache, the action will download a version of Java. Use the default or set `check-latest` to `false` if you prefer a faster more consistent setup experience that prioritizes trying to use the cached versions at the expense of newer versions sometimes being available for download.
-
-If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, the latest version of Java will be downloaded. Set `check-latest` to `true` if you want the most up-to-date version of Java to always be used. Setting `check-latest` to `true` has performance implications as downloading versions of Java is slower than using cached versions.
-
-For Java distributions that are not cached on Hosted images, `check-latest` always behaves as `true` and downloads Java on-flight. Check out [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) for more details about pre-cached Java versions.
+## Multiple JDKs and Maven toolchains
+Install multiple Java versions by providing a multiline `java-version` value. All configured JDKs are installed. The last one added to `PATH` becomes the default.
```yaml
steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-java@v4
- with:
- distribution: 'temurin'
- java-version: '21'
- check-latest: true
-- run: java HelloWorldApp.java
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: |
+ 8
+ 11
+ 17
+ 21
+ 25
```
-### Testing against different Java versions
+Other installed JDKs are available through version-specific variables such as `JAVA_HOME_17_X64`. To use a specific version later in the job, set `JAVA_HOME` and prepend its `bin` directory to `PATH`.
+
+`setup-java` writes a Maven Toolchains declaration for each installed JDK. When multiple JDKs are installed, the declaration contains all of them. Customize the generated toolchain values with `mvn-toolchain-id` and `mvn-toolchain-vendor`.
+
+## Testing with a Java matrix
+
```yaml
jobs:
build:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
strategy:
matrix:
- java: [ '8', '11', '17', '21' ]
- name: Java ${{ matrix.Java }} sample
+ java: ['8', '11', '17', '21', '25']
+ name: Java ${{ matrix.java }}
steps:
- - uses: actions/checkout@v4
- - name: Setup java
- uses: actions/setup-java@v4
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
with:
- distribution: ''
+ distribution: temurin
java-version: ${{ matrix.java }}
- - run: java HelloWorldApp.java
+ - run: java --version
+ - run: mvn verify
```
-### Install multiple JDKs
+## Publishing packages
-All versions are added to the PATH. The last version will be used and available globally. Other Java versions can be accessed through env variables with such specification as 'JAVA_HOME_{{ MAJOR_VERSION }}_{{ ARCHITECTURE }}'.
+`setup-java` generates Maven `settings.xml` and Maven Toolchains configuration. For Gradle publishing, it installs Java for the workflow; the Gradle build file remains responsible for reading credentials from environment variables.
+
+### Maven
```yaml
- steps:
- - uses: actions/setup-java@v4
- with:
- distribution: ''
- java-version: |
- 8
- 11
- 15
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ server-id: github
+ server-username-env-var: GITHUB_ACTOR
+ server-password-env-var: GITHUB_TOKEN
+ - run: mvn --batch-mode deploy
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
-### Using Maven Toolchains
-In the example above multiple JDKs are installed for the same job. The result after the last JDK is installed is a Maven Toolchains declaration containing references to all three JDKs. The values for `id`, `version`, and `vendor` of the individual Toolchain entries are the given input values for `distribution` and `java-version` (`vendor` being the combination of `${distribution}_${java-version}`) by default.
-
-### Advanced Configuration
-
-- [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution)
- - [Eclipse Temurin](docs/advanced-usage.md#Eclipse-Temurin)
- - [Adopt](docs/advanced-usage.md#Adopt)
- - [Zulu](docs/advanced-usage.md#Zulu)
- - [Liberica](docs/advanced-usage.md#Liberica)
- - [Microsoft](docs/advanced-usage.md#Microsoft)
- - [Amazon Corretto](docs/advanced-usage.md#Amazon-Corretto)
- - [Oracle](docs/advanced-usage.md#Oracle)
- - [Alibaba Dragonwell](docs/advanced-usage.md#Alibaba-Dragonwell)
- - [SapMachine](docs/advanced-usage.md#SapMachine)
- - [GraalVM](docs/advanced-usage.md#GraalVM)
-- [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type)
-- [Installing custom Java architecture](docs/advanced-usage.md#Installing-custom-Java-architecture)
-- [Installing custom Java distribution from local file](docs/advanced-usage.md#Installing-Java-from-local-file)
-- [Testing against different Java distributions](docs/advanced-usage.md#Testing-against-different-Java-distributions)
-- [Testing against different platforms](docs/advanced-usage.md#Testing-against-different-platforms)
-- [Publishing using Apache Maven](docs/advanced-usage.md#Publishing-using-Apache-Maven)
-- [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle)
-- [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache)
-- [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains)
-- [Java Version File](docs/advanced-usage.md#Java-version-file)
+### GPG signing
+
+```yaml
+steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: '25'
+ gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
+ gpg-passphrase-env-var: GPG_PASSPHRASE
+ - run: mvn --batch-mode deploy
+ env:
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+```
+
+Maven GPG signing requires `maven-gpg-plugin` 3.2.0 or newer because `setup-java` passes the passphrase through `gpg.passphraseEnvName`.
## Recommended permissions
@@ -284,10 +479,41 @@ permissions:
contents: read # access to check out code and install dependencies
```
+Publishing workflows may require additional permissions depending on the target registry.
+
+## Advanced usage
+
+See [advanced usage](docs/advanced-usage.md) for detailed examples:
+
+- [Selecting a Java distribution](docs/advanced-usage.md#selecting-a-java-distribution)
+- [Installing custom Java package types](docs/advanced-usage.md#installing-custom-java-package-type)
+- [Package compatibility](docs/advanced-usage.md#package-compatibility)
+- [Ensuring the Maven cache is complete](docs/advanced-usage.md#ensuring-the-maven-cache-is-complete-plugin-dependencies)
+- [Caching JDK installations](docs/advanced-usage.md#caching-jdk-installations)
+- [Platform and architecture compatibility](docs/advanced-usage.md#platform-and-architecture-compatibility)
+- [Installing custom Java architecture](docs/advanced-usage.md#installing-custom-java-architecture)
+- [Installing a JDK without setting it as default](docs/advanced-usage.md#installing-jdk-without-setting-as-default)
+- [Installing Java from a local file](docs/advanced-usage.md#installing-java-from-local-file)
+- [Testing against different Java distributions](docs/advanced-usage.md#testing-against-different-java-distributions)
+- [Testing against different platforms](docs/advanced-usage.md#testing-against-different-platforms)
+- [Publishing using Apache Maven](docs/advanced-usage.md#publishing-using-apache-maven)
+- [Apache Maven with a settings path](docs/advanced-usage.md#apache-maven-with-a-settings-path)
+- [Maven transfer progress](docs/advanced-usage.md#maven-transfer-progress-download-logs)
+- [Java problem matcher](docs/advanced-usage.md#java-problem-matcher-compiler-annotations)
+- [Publishing using Gradle](docs/advanced-usage.md#publishing-using-gradle)
+- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache)
+- [Modifying Maven Toolchains](docs/advanced-usage.md#modifying-maven-toolchains)
+- [Java version files](docs/advanced-usage.md#java-version-file)
+- [Self-signed certificates and internal CAs on GitHub Enterprise](docs/advanced-usage.md#self-signed-certificates-and-internal-cas-github-enterprise)
+
## License
The scripts and documentation in this project are released under the [MIT License](LICENSE).
## Contributions
-Contributions are welcome! See [Contributor's Guide](docs/contributors.md)
+Contributions are welcome. See our [Contributor's Guide](docs/contributors.md).
+
+## Code of Conduct
+
+:wave: Be nice. See [our code of conduct](CODE_OF_CONDUCT.md)
diff --git a/__tests__/auth.test.ts b/__tests__/auth.test.ts
index 06591da7a..7457eb603 100644
--- a/__tests__/auth.test.ts
+++ b/__tests__/auth.test.ts
@@ -1,27 +1,84 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import {fileURLToPath} from 'url';
import * as io from '@actions/io';
-import * as core from '@actions/core';
import * as fs from 'fs';
import * as path from 'path';
import os from 'os';
+import {XMLParser} from 'fast-xml-parser';
-import * as auth from '../src/auth';
-import {M2_DIR, MVN_SETTINGS_FILE} from '../src/constants';
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+jest.unstable_mockModule('../src/gpg.js', () => ({
+ importKey: jest.fn(),
+ removeGpgHome: jest.fn(),
+ toGpgPath: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const gpg = await import('../src/gpg.js');
+const auth = await import('../src/auth.js');
+const {M2_DIR, MVN_SETTINGS_FILE, STATE_GPG_HOME} =
+ await import('../src/constants.js');
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
const m2Dir = path.join(__dirname, M2_DIR);
const settingsFile = path.join(m2Dir, MVN_SETTINGS_FILE);
describe('auth tests', () => {
- let spyOSHomedir: jest.SpyInstance;
- let spyInfo: jest.SpyInstance;
+ let spyOSHomedir: any;
+ let spyInfo: any;
beforeEach(async () => {
await io.rmRF(m2Dir);
spyOSHomedir = jest.spyOn(os, 'homedir');
spyOSHomedir.mockReturnValue(__dirname);
- spyInfo = jest.spyOn(core, 'info');
+ spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
+ (gpg.toGpgPath as jest.Mock).mockImplementation((p: string) => p);
}, 300000);
+ afterEach(() => {
+ (core.getInput as jest.Mock).mockReset();
+ (core.exportVariable as jest.Mock).mockReset();
+ (gpg.importKey as jest.Mock).mockReset();
+ (gpg.removeGpgHome as jest.Mock).mockReset();
+ (gpg.toGpgPath as jest.Mock).mockReset();
+ });
+
afterAll(async () => {
try {
await io.rmRF(m2Dir);
@@ -104,6 +161,52 @@ describe('auth tests', () => {
);
}, 100000);
+ it('exports a GPG-compatible path and persists the native GPG home', async () => {
+ const gpgHome = 'D:\\a\\_temp\\setup-java-gpg-1';
+ const exportedGpgHome = '/d/a/_temp/setup-java-gpg-1';
+ (gpg.importKey as jest.Mock).mockResolvedValue(gpgHome);
+ (gpg.toGpgPath as jest.Mock).mockReturnValue(exportedGpgHome);
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
+ const inputs: Record = {
+ 'server-id': 'packages',
+ 'server-username-env-var': 'USERNAME',
+ 'server-password-env-var': 'PASSWORD',
+ 'settings-path': m2Dir,
+ 'gpg-private-key': 'KEY ONE\nKEY TWO'
+ };
+ return inputs[name] ?? '';
+ });
+
+ await auth.configureAuthentication();
+
+ expect(gpg.importKey).toHaveBeenCalledWith('KEY ONE\nKEY TWO');
+ expect(core.saveState).toHaveBeenCalledWith(STATE_GPG_HOME, gpgHome);
+ expect(gpg.toGpgPath).toHaveBeenCalledWith(gpgHome);
+ expect(core.exportVariable).toHaveBeenCalledWith(
+ 'GNUPGHOME',
+ exportedGpgHome
+ );
+ });
+
+ it('removes the isolated GPG home when environment export fails', async () => {
+ const gpgHome = path.join(__dirname, 'runner', 'temp', 'setup-java-gpg-2');
+ (gpg.importKey as jest.Mock).mockResolvedValue(gpgHome);
+ (core.exportVariable as jest.Mock).mockImplementation(() => {
+ throw new Error('environment file unavailable');
+ });
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
+ if (name === 'gpg-private-key') return 'KEY CONTENTS';
+ if (name === 'settings-path') return m2Dir;
+ return '';
+ });
+
+ await expect(auth.configureAuthentication()).rejects.toThrow(
+ 'environment file unavailable'
+ );
+
+ expect(gpg.removeGpgHome).toHaveBeenCalledWith(gpgHome);
+ });
+
it('overwrites existing settings.xml files', async () => {
const id = 'packages';
const username = 'USERNAME';
@@ -160,6 +263,7 @@ describe('auth tests', () => {
const expectedSettings = `
+ false
${id}
@@ -181,15 +285,47 @@ describe('auth tests', () => {
const expectedSettings = `
+ false
${id}
\${env.${username}}
\${env.&<>"''"><&}
+
+
+
+ setup-java-gpg
+
+ ${gpgPassphrase}
+
+
+
+
+ setup-java-gpg
+
+`;
+
+ expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
+ expectedSettings
+ );
+ });
+
+ it('does not add a gpg profile when the passphrase env var is the maven-gpg-plugin default', () => {
+ const id = 'packages';
+ const username = 'USER';
+ const password = '&<>"\'\'"><&';
+ const gpgPassphrase = 'MAVEN_GPG_PASSPHRASE';
+
+ const expectedSettings = `
+ false
+
- gpg.passphrase
- \${env.${gpgPassphrase}}
+ ${id}
+ \${env.${username}}
+ \${env.&<>"''"><&}
`;
@@ -198,4 +334,90 @@ describe('auth tests', () => {
expectedSettings
);
});
+
+ it('escapes settings.xml values while preserving parsed semantics', () => {
+ const id = `packages&<>"'é`;
+ const username = `USER&<>"'é`;
+ const password = `TOKEN&<>"'é`;
+ const gpgPassphrase = `GPG&<>"'é`;
+
+ const xml = auth.generate(id, username, password, gpgPassphrase);
+ const parsed = parseXmlObject(xml) as any;
+
+ expect(parsed.settings.interactiveMode).toBe('false');
+ expect(xmlElementText(xml, 'id')).toBe(id);
+ expect(xmlElementText(xml, 'username')).toBe(`\${env.${username}}`);
+ expect(xmlElementText(xml, 'password')).toBe(`\${env.${password}}`);
+ expect(xmlElementText(xml, 'gpg.passphraseEnvName')).toBe(gpgPassphrase);
+ expect(parsed.settings.activeProfiles.activeProfile).toBe('setup-java-gpg');
+ });
+
+ function xmlElementText(xml: string, tagName: string): string {
+ const match = new RegExp(`<${tagName}>([\\s\\S]*?)${tagName}>`).exec(xml);
+ expect(match).not.toBeNull();
+ return (parseXmlObject(`${match?.[1]}`) as {value: string})
+ .value;
+ }
+
+ function parseXmlObject(xml: string): unknown {
+ const parser = new XMLParser({
+ ignoreAttributes: false,
+ attributeNamePrefix: '@',
+ parseAttributeValue: false,
+ parseTagValue: false,
+ trimValues: true
+ });
+ return parser.parse(xml);
+ }
+
+ it('uses deprecated input aliases and warns', () => {
+ const mockGetInput = core.getInput as jest.MockedFunction<
+ typeof core.getInput
+ >;
+ const mockWarning = core.warning as jest.MockedFunction<
+ typeof core.warning
+ >;
+ mockGetInput.mockImplementation(name =>
+ name === 'server-username' ? 'LEGACY_USERNAME' : ''
+ );
+
+ expect(
+ auth.getInputWithDeprecatedAlias(
+ 'server-username-env-var',
+ 'server-username',
+ 'GITHUB_ACTOR'
+ )
+ ).toBe('LEGACY_USERNAME');
+ expect(mockWarning).toHaveBeenCalledWith(
+ "The 'server-username' input is deprecated and may be removed in a future release. Please use 'server-username-env-var' instead."
+ );
+
+ mockGetInput.mockReset();
+ mockWarning.mockReset();
+ });
+
+ it('prefers the replacement input over its deprecated alias', () => {
+ const mockGetInput = core.getInput as jest.MockedFunction<
+ typeof core.getInput
+ >;
+ mockGetInput.mockImplementation(name => {
+ const inputs: Record = {
+ 'server-password-env-var': 'NEW_PASSWORD',
+ 'server-password': 'LEGACY_PASSWORD'
+ };
+ return inputs[name] || '';
+ });
+
+ expect(
+ auth.getInputWithDeprecatedAlias(
+ 'server-password-env-var',
+ 'server-password',
+ 'GITHUB_TOKEN'
+ )
+ ).toBe('NEW_PASSWORD');
+ expect(core.warning).toHaveBeenCalled();
+
+ mockGetInput.mockReset();
+ (core.warning as jest.Mock).mockReset();
+ });
});
diff --git a/__tests__/benchmark-cache-restore.sh b/__tests__/benchmark-cache-restore.sh
new file mode 100644
index 000000000..46470eafe
--- /dev/null
+++ b/__tests__/benchmark-cache-restore.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+command=${1:?command is required}
+tool=${2:?tool is required}
+
+case "$tool" in
+ maven)
+ dependency_cache="$HOME/.m2/repository"
+ wrapper_cache="$HOME/.m2/wrapper/dists"
+ dependency_file="benchmark/pom.xml"
+ wrapper_file="benchmark/.mvn/wrapper/maven-wrapper.properties"
+ ;;
+ gradle)
+ dependency_cache="$HOME/.gradle/caches"
+ wrapper_cache="$HOME/.gradle/wrapper"
+ dependency_file="benchmark/build.gradle"
+ wrapper_file="benchmark/gradle/wrapper/gradle-wrapper.properties"
+ ;;
+ *)
+ echo "Unsupported tool: $tool" >&2
+ exit 1
+ ;;
+esac
+
+case "$command" in
+ prepare)
+ profile=${3:?profile is required}
+ mkdir -p "$(dirname "$dependency_file")" "$(dirname "$wrapper_file")"
+ printf '// setup-java cache benchmark v1: %s\n' "$profile" > "$dependency_file"
+ printf '# setup-java cache benchmark v1: %s\n' "$profile" > "$wrapper_file"
+ ;;
+ reset)
+ rm -rf "$dependency_cache" "$wrapper_cache"
+ ;;
+ populate)
+ profile=${3:?profile is required}
+ case "$profile" in
+ small)
+ dependency_megabytes=8
+ wrapper_megabytes=2
+ ;;
+ large)
+ dependency_megabytes=128
+ wrapper_megabytes=32
+ ;;
+ *)
+ echo "Unsupported profile: $profile" >&2
+ exit 1
+ ;;
+ esac
+ mkdir -p "$dependency_cache/setup-java-benchmark"
+ mkdir -p "$wrapper_cache/setup-java-benchmark"
+ dd if=/dev/urandom \
+ of="$dependency_cache/setup-java-benchmark/payload" \
+ bs=1048576 count="$dependency_megabytes" 2>/dev/null
+ dd if=/dev/urandom \
+ of="$wrapper_cache/setup-java-benchmark/payload" \
+ bs=1048576 count="$wrapper_megabytes" 2>/dev/null
+ ;;
+ start)
+ node -e "require('fs').writeFileSync('.benchmark-start', String(Date.now()))"
+ ;;
+ record)
+ os=${3:?os is required}
+ profile=${4:?profile is required}
+ implementation=${5:?implementation is required}
+ iteration=${6:?iteration is required}
+ cache_hit=${7:?cache-hit output is required}
+ if [ "$cache_hit" != "true" ]; then
+ echo "Expected an exact dependency-cache hit for $implementation" >&2
+ exit 1
+ fi
+ test -f "$dependency_cache/setup-java-benchmark/payload"
+ started=$(cat .benchmark-start)
+ finished=$(node -e "process.stdout.write(String(Date.now()))")
+ elapsed=$((finished - started))
+ mkdir -p .benchmark-results
+ printf '%s,%s,%s,%s,%s,%s\n' \
+ "$os" "$tool" "$profile" "$implementation" "$iteration" "$elapsed" \
+ >> .benchmark-results/timings.csv
+ ;;
+ summarize)
+ summary_file=${3:?summary file is required}
+ results_file=".benchmark-results/timings.csv"
+ node --input-type=module - "$results_file" "$summary_file" <<'NODE'
+import fs from 'node:fs';
+
+const [, , resultsFile, summaryFile] = process.argv;
+const rows = fs
+ .readFileSync(resultsFile, 'utf8')
+ .trim()
+ .split('\n')
+ .map(line => {
+ const [os, tool, profile, implementation, iteration, elapsed] =
+ line.split(',');
+ return {os, tool, profile, implementation, iteration, elapsed: +elapsed};
+ });
+const average = implementation => {
+ const values = rows
+ .filter(row => row.implementation === implementation)
+ .map(row => row.elapsed);
+ if (values.length === 0) {
+ throw new Error(`No ${implementation} benchmark results were recorded`);
+ }
+ return Math.round(values.reduce((sum, value) => sum + value, 0) / values.length);
+};
+const baseline = average('baseline');
+const candidate = average('candidate');
+const change = (((candidate - baseline) / baseline) * 100).toFixed(1);
+const {os, tool, profile} = rows[0];
+const lines = [
+ `### ${tool} ${profile} cache restore on ${os}`,
+ '',
+ '| Implementation | Iteration | Wall time (ms) |',
+ '| --- | ---: | ---: |',
+ ...rows.map(
+ row =>
+ `| ${row.implementation} | ${row.iteration} | ${row.elapsed} |`
+ ),
+ `| **baseline average** | | **${baseline}** |`,
+ `| **candidate average** | | **${candidate}** |`,
+ '',
+ `Candidate change from baseline: **${change}%**`,
+ ''
+];
+fs.appendFileSync(summaryFile, `${lines.join('\n')}\n`);
+NODE
+ ;;
+ *)
+ echo "Unsupported command: $command" >&2
+ exit 1
+ ;;
+esac
diff --git a/__tests__/cache-feature.test.ts b/__tests__/cache-feature.test.ts
new file mode 100644
index 000000000..4953d9b93
--- /dev/null
+++ b/__tests__/cache-feature.test.ts
@@ -0,0 +1,80 @@
+import {jest, describe, it, expect, afterEach} from '@jest/globals';
+
+jest.unstable_mockModule('@actions/cache', () => ({
+ isFeatureAvailable: jest.fn()
+}));
+
+jest.unstable_mockModule('@actions/core', () => ({
+ warning: jest.fn(),
+ debug: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ info: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const cache = await import('@actions/cache');
+const core = await import('@actions/core');
+const {isCacheFeatureAvailable} = await import('../src/cache-feature.js');
+
+describe('isCacheFeatureAvailable', () => {
+ it('is disabled on GHES when cache feature is unavailable', () => {
+ (cache.isFeatureAvailable as jest.Mock).mockImplementation(
+ () => false
+ );
+ const warningMock = core.warning as jest.Mock;
+ const message =
+ 'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.';
+
+ try {
+ process.env['GITHUB_SERVER_URL'] = 'http://example.com';
+ expect(isCacheFeatureAvailable()).toBe(false);
+ expect(warningMock).toHaveBeenCalledWith(message);
+ } finally {
+ delete process.env['GITHUB_SERVER_URL'];
+ }
+ });
+
+ it('is disabled on dotcom when cache feature is unavailable', () => {
+ (cache.isFeatureAvailable as jest.Mock).mockImplementation(
+ () => false
+ );
+ const warningMock = core.warning as jest.Mock;
+ const message =
+ 'The runner was not able to contact the cache service. Caching will be skipped';
+
+ try {
+ process.env['GITHUB_SERVER_URL'] = 'http://github.com';
+ expect(isCacheFeatureAvailable()).toBe(false);
+ expect(warningMock).toHaveBeenCalledWith(message);
+ } finally {
+ delete process.env['GITHUB_SERVER_URL'];
+ }
+ });
+
+ it('is enabled when cache feature is available', () => {
+ (cache.isFeatureAvailable as jest.Mock).mockImplementation(() => true);
+ expect(isCacheFeatureAvailable()).toBe(true);
+ });
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ jest.clearAllMocks();
+ });
+});
diff --git a/__tests__/cache.test.ts b/__tests__/cache.test.ts
index 9762fb983..690f4a6a5 100644
--- a/__tests__/cache.test.ts
+++ b/__tests__/cache.test.ts
@@ -1,22 +1,85 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
import {mkdtempSync} from 'fs';
import {tmpdir} from 'os';
import {join} from 'path';
-import {restore, save} from '../src/cache';
+import {createHash} from 'crypto';
import * as fs from 'fs';
import * as os from 'os';
-import * as core from '@actions/core';
-import * as cache from '@actions/cache';
-import * as glob from '@actions/glob';
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+jest.unstable_mockModule('@actions/cache', () => ({
+ restoreCache: jest.fn(),
+ saveCache: jest.fn(),
+ isFeatureAvailable: jest.fn(),
+ ValidationError: class ValidationError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'ValidationError';
+ }
+ },
+ ReserveCacheError: class ReserveCacheError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'ReserveCacheError';
+ }
+ }
+}));
+
+jest.unstable_mockModule('@actions/glob', () => ({
+ hashFiles: jest.fn(),
+ create: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const cache = await import('@actions/cache');
+const glob = await import('@actions/glob');
+const {restore, save, validatePackageManager} = await import('../src/cache.js');
describe('dependency cache', () => {
const ORIGINAL_RUNNER_OS = process.env['RUNNER_OS'];
const ORIGINAL_GITHUB_WORKSPACE = process.env['GITHUB_WORKSPACE'];
const ORIGINAL_CWD = process.cwd();
let workspace: string;
- let spyInfo: jest.SpyInstance>;
- let spyWarning: jest.SpyInstance>;
- let spyDebug: jest.SpyInstance>;
- let spySaveState: jest.SpyInstance>;
+ let spyInfo: any;
+ let spyWarning: any;
+ let spyDebug: any;
+ let spySaveState: any;
+ let spyCoreError: any;
beforeEach(() => {
workspace = mkdtempSync(join(tmpdir(), 'setup-java-cache-'));
@@ -40,17 +103,21 @@ describe('dependency cache', () => {
});
beforeEach(() => {
- spyInfo = jest.spyOn(core, 'info');
+ spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
- spyWarning = jest.spyOn(core, 'warning');
+ spyWarning = core.warning as jest.Mock;
spyWarning.mockImplementation(() => null);
- spyDebug = jest.spyOn(core, 'debug');
+ spyDebug = core.debug as jest.Mock;
spyDebug.mockImplementation(() => null);
- spySaveState = jest.spyOn(core, 'saveState');
+ spySaveState = core.saveState as jest.Mock;
spySaveState.mockImplementation(() => null);
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -58,25 +125,39 @@ describe('dependency cache', () => {
process.env['GITHUB_WORKSPACE'] = ORIGINAL_GITHUB_WORKSPACE;
process.env['RUNNER_OS'] = ORIGINAL_RUNNER_OS;
resetState();
+
+ jest.resetAllMocks();
+ jest.clearAllMocks();
+ jest.restoreAllMocks();
+ });
+
+ describe('validatePackageManager', () => {
+ it('accepts supported package managers', () => {
+ expect(() => validatePackageManager('maven')).not.toThrow();
+ expect(() => validatePackageManager('gradle')).not.toThrow();
+ expect(() => validatePackageManager('sbt')).not.toThrow();
+ });
+
+ it('throws the targeted error for unsupported package managers', () => {
+ expect(() => validatePackageManager('ant')).toThrow(
+ 'unknown package manager specified: ant'
+ );
+ });
});
describe('restore', () => {
- let spyCacheRestore: jest.SpyInstance<
- ReturnType,
- Parameters
- >;
- let spyGlobHashFiles: jest.SpyInstance<
- ReturnType,
- Parameters
- >;
+ let spyCacheRestore: any;
+ let spyGlobHashFiles: any;
+ let spySetOutput: any;
beforeEach(() => {
- spyCacheRestore = jest
- .spyOn(cache, 'restoreCache')
- .mockImplementation((paths: string[], primaryKey: string) =>
- Promise.resolve(undefined)
- );
- spyGlobHashFiles = jest.spyOn(glob, 'hashFiles');
+ spyCacheRestore = (cache.restoreCache as any).mockImplementation(
+ (paths: string[], primaryKey: string) => Promise.resolve(undefined)
+ );
+ spyGlobHashFiles = glob.hashFiles as jest.Mock;
+ spyGlobHashFiles.mockResolvedValue('hash-stub');
+ spySetOutput = core.setOutput as jest.Mock;
+ spySetOutput.mockImplementation(() => null);
spyWarning.mockImplementation(() => null);
});
@@ -87,29 +168,196 @@ describe('dependency cache', () => {
});
describe('for maven', () => {
- it('throws error if no pom.xml found', async () => {
+ it('throws error if no pom.xml, maven-wrapper.properties, or extensions.xml found', async () => {
+ spyGlobHashFiles.mockResolvedValue('');
await expect(restore('maven', '')).rejects.toThrow(
`No file in ${projectRoot(
workspace
- )} matched to [**/pom.xml], make sure you have checked out the target repository`
+ )} matched to [**/pom.xml,**/.mvn/wrapper/maven-wrapper.properties,**/.mvn/extensions.xml], make sure you have checked out the target repository`
);
});
- it('downloads cache', async () => {
+ it('downloads cache based on pom.xml', async () => {
createFile(join(workspace, 'pom.xml'));
await restore('maven', '');
- expect(spyCacheRestore).toHaveBeenCalled();
- expect(spyGlobHashFiles).toHaveBeenCalledWith('**/pom.xml');
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'repository')],
+ expect.any(String)
+ );
+ expect(spyGlobHashFiles).toHaveBeenCalledWith(
+ '**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties\n**/.mvn/extensions.xml'
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
+ });
+ it('sets the cache-primary-key output', async () => {
+ createFile(join(workspace, 'pom.xml'));
+
+ await restore('maven', '');
+ expect(spySetOutput).toHaveBeenCalledWith(
+ 'cache-primary-key',
+ expect.stringContaining('setup-java-')
+ );
+ });
+ it('downloads cache based on maven-wrapper.properties', async () => {
+ createDirectory(join(workspace, '.mvn'));
+ createDirectory(join(workspace, '.mvn', 'wrapper'));
+ createFile(
+ join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
+ );
+
+ await restore('maven', '');
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'repository')],
+ expect.any(String)
+ );
+ expect(spyGlobHashFiles).toHaveBeenCalledWith(
+ '**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties\n**/.mvn/extensions.xml'
+ );
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
});
+ it('downloads cache based on extensions.xml', async () => {
+ createDirectory(join(workspace, '.mvn'));
+ createFile(join(workspace, '.mvn', 'extensions.xml'));
+
+ await restore('maven', '');
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'repository')],
+ expect.any(String)
+ );
+ expect(spyGlobHashFiles).toHaveBeenCalledWith(
+ '**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties\n**/.mvn/extensions.xml'
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
+ });
+ it('restores the maven wrapper distribution cache independently of the main cache', async () => {
+ createDirectory(join(workspace, '.mvn'));
+ createDirectory(join(workspace, '.mvn', 'wrapper'));
+ createFile(
+ join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
+ );
+
+ await restore('maven', '', ['/custom/maven/repository']);
+ // Main dependency cache no longer carries the wrapper dists path.
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ ['/custom/maven/repository'],
+ expect.any(String)
+ );
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'wrapper', 'dists')],
+ expect.stringContaining('maven-wrapper')
+ );
+ expect(spyGlobHashFiles).toHaveBeenCalledWith(
+ '**/.mvn/wrapper/maven-wrapper.properties'
+ );
+ expect(spyInfo).toHaveBeenCalledWith(
+ 'maven-wrapper cache is not found'
+ );
+ });
+ it('starts maven dependency and wrapper restores before either completes', async () => {
+ createDirectory(join(workspace, '.mvn'));
+ createDirectory(join(workspace, '.mvn', 'wrapper'));
+ createFile(
+ join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
+ );
+ const dependencyRestore = deferred();
+ const wrapperRestore = deferred();
+ const bothRestoresStarted = deferred();
+ let restoreCount = 0;
+ spyCacheRestore.mockImplementation((paths: string[]) => {
+ restoreCount++;
+ if (restoreCount === 2) {
+ bothRestoresStarted.resolve();
+ }
+ return paths.includes(join(os.homedir(), '.m2', 'repository'))
+ ? dependencyRestore.promise
+ : wrapperRestore.promise;
+ });
+
+ const restorePromise = restore('maven', '');
+ await bothRestoresStarted.promise;
+
+ expect(spyCacheRestore).toHaveBeenCalledTimes(2);
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-primary-key',
+ expect.any(String)
+ );
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-primary-key-maven-wrapper',
+ expect.any(String)
+ );
+
+ wrapperRestore.resolve('maven-wrapper-hit');
+ dependencyRestore.resolve('maven-dependency-hit');
+ await restorePromise;
+
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-matched-key-maven-wrapper',
+ 'maven-wrapper-hit'
+ );
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-matched-key',
+ 'maven-dependency-hit'
+ );
+ expect(spySetOutput).toHaveBeenCalledWith('cache-hit', false);
+ });
+ it('propagates a wrapper restore failure after starting both restores', async () => {
+ createDirectory(join(workspace, '.mvn'));
+ createDirectory(join(workspace, '.mvn', 'wrapper'));
+ createFile(
+ join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
+ );
+ const dependencyRestore = deferred();
+ const wrapperRestore = deferred();
+ const bothRestoresStarted = deferred();
+ let restoreCount = 0;
+ spyCacheRestore.mockImplementation((paths: string[]) => {
+ restoreCount++;
+ if (restoreCount === 2) {
+ bothRestoresStarted.resolve();
+ }
+ return paths.includes(join(os.homedir(), '.m2', 'repository'))
+ ? dependencyRestore.promise
+ : wrapperRestore.promise;
+ });
+
+ const restorePromise = restore('maven', '');
+ await bothRestoresStarted.promise;
+ wrapperRestore.reject(new Error('wrapper restore failed'));
+ dependencyRestore.resolve(undefined);
+
+ await expect(restorePromise).rejects.toThrow('wrapper restore failed');
+ });
+ it('skips the maven wrapper cache when no wrapper properties exist', async () => {
+ createFile(join(workspace, 'pom.xml'));
+ spyGlobHashFiles.mockImplementation((pattern: string) =>
+ Promise.resolve(
+ pattern === '**/.mvn/wrapper/maven-wrapper.properties'
+ ? ''
+ : 'hash-stub'
+ )
+ );
+
+ await restore('maven', '');
+ // Only the main dependency cache is restored; the wrapper cache path is
+ // never touched because the project does not use mvnw.
+ expect(spyCacheRestore).toHaveBeenCalledTimes(1);
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'repository')],
+ expect.any(String)
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ });
});
describe('for gradle', () => {
it('throws error if no build.gradle found', async () => {
+ spyGlobHashFiles.mockResolvedValue('');
await expect(restore('gradle', '')).rejects.toThrow(
`No file in ${projectRoot(
workspace
- )} matched to [**/*.gradle*,**/gradle-wrapper.properties,buildSrc/**/Versions.kt,buildSrc/**/Dependencies.kt,gradle/*.versions.toml,**/versions.properties], make sure you have checked out the target repository`
+ )} matched to [**/*.gradle*,**/gradle.properties,**/gradle-wrapper.properties,buildSrc/**/Versions.kt,buildSrc/**/Dependencies.kt,gradle/*.versions.toml,**/versions.properties], make sure you have checked out the target repository`
);
});
it('downloads cache based on build.gradle', async () => {
@@ -118,7 +366,7 @@ describe('dependency cache', () => {
await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
- '**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
+ '**/*.gradle*\n**/gradle.properties\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
@@ -129,7 +377,7 @@ describe('dependency cache', () => {
await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
- '**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
+ '**/*.gradle*\n**/gradle.properties\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
@@ -141,7 +389,7 @@ describe('dependency cache', () => {
await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
- '**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
+ '**/*.gradle*\n**/gradle.properties\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
@@ -153,14 +401,124 @@ describe('dependency cache', () => {
await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
- '**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
+ '**/*.gradle*\n**/gradle.properties\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
});
+ it('changes the cache key when gradle.properties changes', async () => {
+ const buildFile = join(workspace, 'build.gradle');
+ const propertiesFile = join(workspace, 'gradle.properties');
+ createFile(buildFile);
+ createFile(propertiesFile, 'dependencyVersion=1.0.0');
+ spyGlobHashFiles.mockImplementation(async (pattern: string) => {
+ if (pattern === '**/gradle-wrapper.properties') {
+ return '';
+ }
+
+ const files = [buildFile];
+ if (pattern.split('\n').includes('**/gradle.properties')) {
+ files.push(propertiesFile);
+ }
+ const hash = createHash('sha256');
+ files.forEach(file => hash.update(fs.readFileSync(file)));
+ return hash.digest('hex');
+ });
+
+ await restore('gradle', '');
+ const firstKey = spyCacheRestore.mock.calls[0][1];
+
+ fs.writeFileSync(propertiesFile, 'dependencyVersion=2.0.0');
+ await restore('gradle', '');
+ const secondKey = spyCacheRestore.mock.calls[1][1];
+
+ expect(secondKey).not.toBe(firstKey);
+ });
+ it('restores the gradle wrapper distribution cache independently of the main cache', async () => {
+ createFile(join(workspace, 'build.gradle'));
+
+ await restore('gradle', '', ['/custom/gradle/caches']);
+ // Main dependency cache no longer carries the wrapper path.
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ ['/custom/gradle/caches'],
+ expect.any(String)
+ );
+ // Wrapper distribution is restored on its own, keyed only on the
+ // wrapper properties file.
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ [join(os.homedir(), '.gradle', 'wrapper')],
+ expect.stringContaining('setup-java-')
+ );
+ expect(spyGlobHashFiles).toHaveBeenCalledWith(
+ '**/gradle-wrapper.properties'
+ );
+ });
+ it('starts gradle dependency and wrapper restores before either completes', async () => {
+ createFile(join(workspace, 'build.gradle'));
+ createFile(join(workspace, 'gradle-wrapper.properties'));
+ const dependencyRestore = deferred();
+ const wrapperRestore = deferred();
+ const bothRestoresStarted = deferred();
+ let restoreCount = 0;
+ spyCacheRestore.mockImplementation((paths: string[]) => {
+ restoreCount++;
+ if (restoreCount === 2) {
+ bothRestoresStarted.resolve();
+ }
+ return paths.includes(join(os.homedir(), '.gradle', 'caches'))
+ ? dependencyRestore.promise
+ : wrapperRestore.promise;
+ });
+
+ const restorePromise = restore('gradle', '');
+ await bothRestoresStarted.promise;
+
+ expect(spyCacheRestore).toHaveBeenCalledTimes(2);
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-primary-key',
+ expect.any(String)
+ );
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-primary-key-gradle-wrapper',
+ expect.any(String)
+ );
+
+ dependencyRestore.resolve('gradle-dependency-hit');
+ wrapperRestore.resolve('gradle-wrapper-hit');
+ await restorePromise;
+
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-matched-key',
+ 'gradle-dependency-hit'
+ );
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-matched-key-gradle-wrapper',
+ 'gradle-wrapper-hit'
+ );
+ expect(spySetOutput).toHaveBeenCalledWith('cache-hit', false);
+ });
+ it('skips the gradle wrapper cache when no wrapper properties exist', async () => {
+ createFile(join(workspace, 'build.gradle'));
+ spyGlobHashFiles.mockImplementation((pattern: string) =>
+ Promise.resolve(
+ pattern === '**/gradle-wrapper.properties' ? '' : 'hash-stub'
+ )
+ );
+
+ await restore('gradle', '');
+ // Only the main dependency cache is restored; the wrapper cache path is
+ // never touched because the project does not use the gradle wrapper.
+ expect(spyCacheRestore).toHaveBeenCalledTimes(1);
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ [join(os.homedir(), '.gradle', 'caches')],
+ expect.any(String)
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ });
});
describe('for sbt', () => {
it('throws error if no build.sbt found', async () => {
+ spyGlobHashFiles.mockResolvedValue('');
await expect(restore('sbt', '')).rejects.toThrow(
`No file in ${projectRoot(
workspace
@@ -179,6 +537,13 @@ describe('dependency cache', () => {
expect(spyInfo).toHaveBeenCalledWith('sbt cache is not found');
});
it('detects scala and sbt changes under **/project/ folder', async () => {
+ let callCount = 0;
+ spyGlobHashFiles.mockImplementation(async () => {
+ callCount++;
+ // Return same hash for first two calls, different for third
+ return callCount <= 2 ? 'hash-v1' : 'hash-v2';
+ });
+
createFile(join(workspace, 'build.sbt'));
createDirectory(join(workspace, 'project'));
createFile(join(workspace, 'project/DependenciesV1.scala'));
@@ -207,13 +572,14 @@ describe('dependency cache', () => {
await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
- '**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
+ '**/*.gradle*\n**/gradle.properties\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
});
describe('cache-dependency-path', () => {
it('throws error if no matching dependency file found', async () => {
+ spyGlobHashFiles.mockResolvedValue('');
createFile(join(workspace, 'build.gradle.kts'));
await expect(
restore('gradle', 'sub-project/**/build.gradle.kts')
@@ -253,19 +619,47 @@ describe('dependency cache', () => {
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
});
});
+ describe('cache-path', () => {
+ it.each([
+ ['maven', ['/custom/maven/repository']],
+ ['gradle', ['/custom/gradle/caches']],
+ [
+ 'sbt',
+ [
+ '/custom/ivy/cache',
+ '/custom/coursier/cache',
+ '!/custom/ivy/cache/*.lock'
+ ]
+ ]
+ ])(
+ 'restores and persists custom paths for %s',
+ async (packageManager, cachePaths) => {
+ await restore(packageManager, '', cachePaths);
+
+ expect(spyCacheRestore).toHaveBeenCalledWith(
+ cachePaths,
+ expect.any(String)
+ );
+ expect(spySaveState).toHaveBeenCalledWith(
+ 'cache-paths',
+ JSON.stringify(cachePaths)
+ );
+ }
+ );
+ });
});
describe('save', () => {
- let spyCacheSave: jest.SpyInstance<
- ReturnType,
- Parameters
- >;
+ let spyCacheSave: any;
+ let spyGlobCreate: jest.Mock;
beforeEach(() => {
- spyCacheSave = jest
- .spyOn(cache, 'saveCache')
- .mockImplementation((paths: string[], key: string) =>
- Promise.resolve(0)
- );
+ spyCacheSave = (cache.saveCache as any).mockImplementation(
+ (paths: string[], key: string) => Promise.resolve(0)
+ );
+ spyGlobCreate = glob.create as jest.Mock;
+ spyGlobCreate.mockResolvedValue({
+ glob: jest.fn(() => Promise.resolve(['wrapper-path']))
+ });
spyWarning.mockImplementation(() => null);
});
@@ -282,10 +676,12 @@ describe('dependency cache', () => {
await save('maven');
expect(spyCacheSave).toHaveBeenCalled();
expect(spyWarning).not.toHaveBeenCalled();
- expect(spyInfo).toHaveBeenCalled();
- expect(spyInfo).toHaveBeenCalledWith(
+ expect(spyInfo).not.toHaveBeenCalledWith(
expect.stringMatching(/^Cache saved with the key:.*/)
);
+ expect(spyDebug).toHaveBeenCalledWith(
+ expect.stringMatching(/^Cache was not saved for the key:.*/)
+ );
});
it('saves with error from toolkit, should fail workflow', async () => {
@@ -300,6 +696,42 @@ describe('dependency cache', () => {
);
});
+ it.each([
+ ['maven', ['/custom/maven/repository']],
+ ['gradle', ['/custom/gradle/caches']],
+ [
+ 'sbt',
+ [
+ '/custom/ivy/cache',
+ '/custom/coursier/cache',
+ '!/custom/ivy/cache/*.lock'
+ ]
+ ]
+ ])(
+ 'saves the persisted custom paths for %s',
+ async (packageManager, cachePaths) => {
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-paths':
+ return JSON.stringify(cachePaths);
+ default:
+ return '';
+ }
+ });
+
+ await save(packageManager);
+
+ expect(spyCacheSave).toHaveBeenCalledWith(
+ cachePaths,
+ 'setup-java-cache-primary-key'
+ );
+ }
+ );
+
describe('for maven', () => {
it('uploads cache even if no pom.xml found', async () => {
createStateForMissingBuildFile();
@@ -327,6 +759,114 @@ describe('dependency cache', () => {
expect.stringMatching(/^Cache saved with the key:.*/)
);
});
+ it('saves the maven wrapper distribution cache under its own key', async () => {
+ createFile(join(workspace, 'pom.xml'));
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-primary-key-maven-wrapper':
+ return 'setup-java-maven-wrapper-key';
+ default:
+ return '';
+ }
+ });
+
+ await save('maven');
+ expect(spyCacheSave).toHaveBeenCalledWith(
+ ['wrapper-path'],
+ 'setup-java-maven-wrapper-key'
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ });
+ it('does not save the maven wrapper cache on an exact wrapper hit', async () => {
+ createFile(join(workspace, 'pom.xml'));
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-primary-key-maven-wrapper':
+ case 'cache-matched-key-maven-wrapper':
+ return 'setup-java-maven-wrapper-key';
+ default:
+ return '';
+ }
+ });
+
+ await save('maven');
+ expect(spyCacheSave).not.toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'wrapper', 'dists')],
+ expect.any(String)
+ );
+ });
+ it('does not fail the post step when the wrapper distribution path is missing', async () => {
+ createFile(join(workspace, 'pom.xml'));
+ createDirectory(join(workspace, '.mvn'));
+ createDirectory(join(workspace, '.mvn', 'wrapper'));
+ createFile(
+ join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
+ );
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-primary-key-maven-wrapper':
+ return 'setup-java-maven-wrapper-key';
+ default:
+ return '';
+ }
+ });
+ spyGlobCreate.mockResolvedValue({
+ glob: jest.fn(() => Promise.resolve([]))
+ });
+
+ await expect(save('maven')).resolves.toBeUndefined();
+ expect(spyCacheSave).not.toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'wrapper', 'dists')],
+ expect.any(String)
+ );
+ expect(spyCacheSave).toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'repository')],
+ 'setup-java-cache-primary-key'
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ });
+ it('continues with primary cache save when additional cache save fails unexpectedly', async () => {
+ createFile(join(workspace, 'pom.xml'));
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-primary-key-maven-wrapper':
+ return 'setup-java-maven-wrapper-key';
+ default:
+ return '';
+ }
+ });
+ spyCacheSave.mockImplementation((paths: string[], key: string) => {
+ if (paths[0] === 'wrapper-path') {
+ return Promise.reject(new Error('wrapper save exploded'));
+ }
+ return Promise.resolve(0);
+ });
+
+ await expect(save('maven')).resolves.toBeUndefined();
+ expect(spyWarning).toHaveBeenCalledWith(
+ 'Failed to save maven-wrapper cache: wrapper save exploded. Continuing with primary cache save.'
+ );
+ expect(spyCacheSave).toHaveBeenCalledWith(
+ [join(os.homedir(), '.m2', 'repository')],
+ 'setup-java-cache-primary-key'
+ );
+ });
});
describe('for gradle', () => {
it('uploads cache even if no build.gradle found', async () => {
@@ -379,6 +919,80 @@ describe('dependency cache', () => {
expect.stringMatching(/^Cache saved with the key:.*/)
);
});
+ it('saves the gradle wrapper distribution cache under its own key', async () => {
+ createFile(join(workspace, 'build.gradle'));
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-primary-key-gradle-wrapper':
+ return 'setup-java-gradle-wrapper-key';
+ default:
+ return '';
+ }
+ });
+
+ await save('gradle');
+ expect(spyCacheSave).toHaveBeenCalledWith(
+ ['wrapper-path'],
+ 'setup-java-gradle-wrapper-key'
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ });
+ it('does not save the gradle wrapper cache on an exact wrapper hit', async () => {
+ createFile(join(workspace, 'build.gradle'));
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-primary-key-gradle-wrapper':
+ case 'cache-matched-key-gradle-wrapper':
+ return 'setup-java-gradle-wrapper-key';
+ default:
+ return '';
+ }
+ });
+
+ await save('gradle');
+ expect(spyCacheSave).not.toHaveBeenCalledWith(
+ [join(os.homedir(), '.gradle', 'wrapper')],
+ expect.any(String)
+ );
+ });
+ it('does not fail the post step when the wrapper distribution path is missing', async () => {
+ createFile(join(workspace, 'build.gradle'));
+ createFile(join(workspace, 'gradle-wrapper.properties'));
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case 'cache-primary-key-gradle-wrapper':
+ return 'setup-java-gradle-wrapper-key';
+ default:
+ return '';
+ }
+ });
+ spyGlobCreate.mockResolvedValue({
+ glob: jest.fn(() => Promise.resolve([]))
+ });
+
+ await expect(save('gradle')).resolves.toBeUndefined();
+ expect(spyCacheSave).not.toHaveBeenCalledWith(
+ [join(os.homedir(), '.gradle', 'wrapper')],
+ expect.any(String)
+ );
+ expect(spyCacheSave).toHaveBeenCalledWith(
+ [join(os.homedir(), '.gradle', 'caches')],
+ 'setup-java-cache-primary-key'
+ );
+ expect(spyWarning).not.toHaveBeenCalled();
+ });
});
describe('for sbt', () => {
it('uploads cache even if no build.sbt found', async () => {
@@ -423,14 +1037,14 @@ describe('dependency cache', () => {
});
function resetState() {
- jest.spyOn(core, 'getState').mockReset();
+ (core.getState as jest.Mock).mockReset();
}
/**
* Create states to emulate a restore process without build file.
*/
function createStateForMissingBuildFile() {
- jest.spyOn(core, 'getState').mockImplementation(name => {
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-';
@@ -444,7 +1058,7 @@ function createStateForMissingBuildFile() {
* Create states to emulate a successful restore process.
*/
function createStateForSuccessfulRestore() {
- jest.spyOn(core, 'getState').mockImplementation(name => {
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
@@ -456,9 +1070,19 @@ function createStateForSuccessfulRestore() {
});
}
-function createFile(path: string) {
+function createFile(path: string, contents = '') {
core.info(`created a file at ${path}`);
- fs.writeFileSync(path, '');
+ fs.writeFileSync(path, contents);
+}
+
+function deferred() {
+ let resolve!: (value: T | PromiseLike) => void;
+ let reject!: (reason?: unknown) => void;
+ const promise = new Promise((promiseResolve, promiseReject) => {
+ resolve = promiseResolve;
+ reject = promiseReject;
+ });
+ return {promise, resolve, reject};
}
function createDirectory(path: string) {
diff --git a/__tests__/cache/gradle1/gradle/wrapper/gradle-wrapper.properties b/__tests__/cache/gradle1/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..e78380889
--- /dev/null
+++ b/__tests__/cache/gradle1/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1 @@
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
diff --git a/__tests__/cache/maven/.mvn/wrapper/maven-wrapper.properties b/__tests__/cache/maven/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 000000000..2b8cd3d63
--- /dev/null
+++ b/__tests__/cache/maven/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip
diff --git a/__tests__/cache/maven2/.gitignore b/__tests__/cache/maven2/.gitignore
new file mode 100644
index 000000000..0e13eebbe
--- /dev/null
+++ b/__tests__/cache/maven2/.gitignore
@@ -0,0 +1,11 @@
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+# https://github.com/takari/maven-wrapper#usage-without-binary-jar
+.mvn/wrapper/maven-wrapper.jar
diff --git a/__tests__/cache/maven2/pom.xml b/__tests__/cache/maven2/pom.xml
new file mode 100644
index 000000000..70b8d0cc1
--- /dev/null
+++ b/__tests__/cache/maven2/pom.xml
@@ -0,0 +1,15 @@
+
+
+ 4.0.0
+ io.github.actions
+ setup-java-maven2-example
+ 1.0.0-SNAPSHOT
+ jar
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+
+
+
diff --git a/__tests__/cache/sbt2/.gitignore b/__tests__/cache/sbt2/.gitignore
new file mode 100644
index 000000000..2f7896d1d
--- /dev/null
+++ b/__tests__/cache/sbt2/.gitignore
@@ -0,0 +1 @@
+target/
diff --git a/__tests__/cache/sbt2/build.sbt b/__tests__/cache/sbt2/build.sbt
new file mode 100644
index 000000000..c8737676e
--- /dev/null
+++ b/__tests__/cache/sbt2/build.sbt
@@ -0,0 +1,3 @@
+ThisBuild / scalaVersion := "2.12.15"
+
+libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1"
diff --git a/__tests__/check-dir.sh b/__tests__/check-dir.sh
new file mode 100755
index 000000000..30da05fdc
--- /dev/null
+++ b/__tests__/check-dir.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Assert whether a directory exists, for use in the e2e cache workflows.
+#
+# Usage: check-dir.sh [present|absent]
+#
+# present (default): fail if does NOT exist, otherwise list its contents.
+# absent: fail if DOES exist.
+#
+# Call with already-expanded paths (e.g. "$HOME/.gradle/caches") to avoid
+# tilde-expansion pitfalls.
+set -eu
+
+if [ "$#" -lt 1 ]; then
+ echo "Usage: check-dir.sh [present|absent]" >&2
+ exit 2
+fi
+
+dir=$1
+mode=${2:-present}
+
+case "$mode" in
+ present)
+ if [ ! -d "$dir" ]; then
+ echo "::error::The $dir directory does not exist unexpectedly"
+ exit 1
+ fi
+ ls "$dir"
+ ;;
+ absent)
+ if [ -d "$dir" ]; then
+ echo "::error::The $dir directory exists unexpectedly"
+ exit 1
+ fi
+ ;;
+ *)
+ echo "::error::Unknown mode '$mode' (expected 'present' or 'absent')"
+ exit 1
+ ;;
+esac
diff --git a/__tests__/checksum.test.ts b/__tests__/checksum.test.ts
new file mode 100644
index 000000000..b8e3f0185
--- /dev/null
+++ b/__tests__/checksum.test.ts
@@ -0,0 +1,130 @@
+import {afterEach, describe, expect, it, jest} from '@jest/globals';
+import {createHash} from 'crypto';
+import fs from 'fs';
+import os from 'os';
+import path from 'path';
+
+import {calculateChecksum, verifyChecksum} from '../src/checksum.js';
+import type {ChecksumMetadata} from '../src/distributions/base-models.js';
+
+const temporaryPaths: string[] = [];
+
+async function temporaryFile(contents: string): Promise {
+ const directory = await fs.promises.mkdtemp(
+ path.join(os.tmpdir(), 'setup-java-checksum-')
+ );
+ const file = path.join(directory, 'archive');
+ await fs.promises.writeFile(file, contents);
+ temporaryPaths.push(directory);
+ return file;
+}
+
+afterEach(async () => {
+ await Promise.all(
+ temporaryPaths
+ .splice(0)
+ .map(item => fs.promises.rm(item, {recursive: true, force: true}))
+ );
+ jest.restoreAllMocks();
+});
+
+describe('verifyChecksum', () => {
+ it.each(['sha256', 'sha512'] as const)(
+ 'verifies a matching %s digest',
+ async algorithm => {
+ const contents = `jdk archive for ${algorithm}`;
+ const file = await temporaryFile(contents);
+ const value = createHash(algorithm).update(contents).digest('hex');
+
+ await expect(
+ verifyChecksum(
+ file,
+ {algorithm, value: value.toUpperCase()},
+ {distribution: 'Test', version: '21.0.1'}
+ )
+ ).resolves.toBeUndefined();
+ }
+ );
+
+ it('reports mismatch context and both digests', async () => {
+ const file = await temporaryFile('corrupt archive');
+ const expected = 'a'.repeat(64);
+ const actual = await calculateChecksum(file, 'sha256');
+
+ await expect(
+ verifyChecksum(
+ file,
+ {algorithm: 'sha256', value: expected},
+ {distribution: 'Corretto', version: '21.0.8'}
+ )
+ ).rejects.toThrow(
+ `Checksum verification failed for Corretto version 21.0.8: sha256 expected ${expected}, actual ${actual}.`
+ );
+ });
+
+ it('rejects malformed digest metadata before reading the file', async () => {
+ await expect(
+ verifyChecksum(
+ '/missing/archive',
+ {algorithm: 'sha512', value: 'not-a-digest'},
+ {distribution: 'Test', version: '17'}
+ )
+ ).rejects.toThrow(
+ 'Malformed sha512 checksum metadata: expected a 128-character hexadecimal digest.'
+ );
+ });
+
+ it.each([undefined, null, 123])(
+ 'reports a malformed digest when the value is %p',
+ async value => {
+ const checksum = {
+ algorithm: 'sha256',
+ value
+ } as unknown as ChecksumMetadata;
+
+ await expect(
+ verifyChecksum('/missing/archive', checksum, {
+ distribution: 'Test',
+ version: '17'
+ })
+ ).rejects.toThrow(
+ 'Malformed sha256 checksum metadata: expected a 64-character hexadecimal digest.'
+ );
+ }
+ );
+
+ it('rejects unsupported algorithms without leaking source query parameters', async () => {
+ const checksum = {
+ algorithm: 'md5',
+ value: 'a'.repeat(32),
+ source: 'https://vendor.example/checksum.txt?token=secret-value#private'
+ } as unknown as ChecksumMetadata;
+
+ let message = '';
+ try {
+ await verifyChecksum('/missing/archive', checksum, {
+ distribution: 'Test',
+ version: '17'
+ });
+ } catch (error) {
+ message = (error as Error).message;
+ }
+
+ expect(message).toContain(
+ "Unsupported checksum algorithm 'md5' from https://vendor.example/checksum.txt"
+ );
+ expect(message).not.toContain('secret-value');
+ expect(message).not.toContain('token=');
+ expect(message).not.toContain('#private');
+ });
+
+ it('surfaces file read errors', async () => {
+ await expect(
+ verifyChecksum(
+ '/missing/archive',
+ {algorithm: 'sha256', value: 'a'.repeat(64)},
+ {distribution: 'Test', version: '17'}
+ )
+ ).rejects.toMatchObject({code: 'ENOENT'});
+ });
+});
diff --git a/__tests__/cleanup-java.test.ts b/__tests__/cleanup-java.test.ts
index 375a2ad15..63b0df8a0 100644
--- a/__tests__/cleanup-java.test.ts
+++ b/__tests__/cleanup-java.test.ts
@@ -1,32 +1,111 @@
-import {run as cleanup} from '../src/cleanup-java';
-import * as core from '@actions/core';
-import * as cache from '@actions/cache';
-import * as util from '../src/util';
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import fs from 'fs';
+import os from 'os';
+import path from 'path';
+
+// Mock @actions/cache before importing source modules
+const real_cache_module = await import('@actions/cache');
+jest.unstable_mockModule('@actions/cache', () => ({
+ ...real_cache_module,
+ saveCache: jest.fn(),
+ restoreCache: jest.fn()
+}));
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_util_module = await import('../src/util.js');
+jest.unstable_mockModule('../src/util.js', () => ({
+ ...real_util_module,
+ extractJdkFile: jest.fn(),
+ getDownloadArchiveExtension: jest.fn(),
+ getToolcachePath: jest.fn(),
+ isJobStatusSuccess: jest.fn(),
+ renameWinArchive: jest.fn(),
+ isVersionSatisfies: real_util_module.isVersionSatisfies,
+ getTempDir: real_util_module.getTempDir
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const cache = await import('@actions/cache');
+const {run: cleanup} = await import('../src/cleanup-java.js');
+const util = await import('../src/util.js');
+const constants = await import('../src/constants.js');
+const {GPG_HOME_PREFIX} = await import('../src/gpg.js');
+const {registerJdk, buildJdkCacheKey} = await import('../src/jdk-cache.js');
+
+const jdkTempRoots: string[] = [];
describe('cleanup', () => {
- let spyWarning: jest.SpyInstance>;
- let spyInfo: jest.SpyInstance>;
- let spyCacheSave: jest.SpyInstance<
- ReturnType,
- Parameters
- >;
- let spyJobStatusSuccess: jest.SpyInstance;
+ let spyWarning: any;
+ let spyInfo: any;
+ let spyCacheSave: any;
+ let spyJobStatusSuccess: any;
+ let spyCoreError: any;
beforeEach(() => {
- spyWarning = jest.spyOn(core, 'warning');
+ spyWarning = core.warning as jest.Mock;
spyWarning.mockImplementation(() => null);
- spyInfo = jest.spyOn(core, 'info');
+
+ spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
- spyCacheSave = jest.spyOn(cache, 'saveCache');
- spyJobStatusSuccess = jest.spyOn(util, 'isJobStatusSuccess');
+
+ spyCacheSave = cache.saveCache as jest.Mock;
+
+ spyJobStatusSuccess = util.isJobStatusSuccess as jest.Mock;
spyJobStatusSuccess.mockReturnValue(true);
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
+
createStateForSuccessfulRestore();
});
+
afterEach(() => {
+ while (jdkTempRoots.length) {
+ fs.rmSync(jdkTempRoots.pop()!, {recursive: true, force: true});
+ }
resetState();
+ jest.resetAllMocks();
+ jest.clearAllMocks();
+ jest.restoreAllMocks();
});
- it('does not fail nor warn even when the save process throws a ReserveCacheError', async () => {
+ it('does not warn/fail even when the save process throws a ReserveCacheError', async () => {
spyCacheSave.mockImplementation((paths: string[], key: string) =>
Promise.reject(
new cache.ReserveCacheError(
@@ -34,35 +113,230 @@ describe('cleanup', () => {
)
)
);
- jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
return name === 'cache' ? 'gradle' : '';
});
+
await cleanup();
expect(spyCacheSave).toHaveBeenCalled();
expect(spyWarning).not.toHaveBeenCalled();
});
+ it('removes the isolated GPG home without touching unrelated key material', async () => {
+ const tempDir = util.getTempDir();
+ fs.mkdirSync(tempDir, {recursive: true});
+ const gpgHome = fs.mkdtempSync(path.join(tempDir, GPG_HOME_PREFIX));
+ const unrelatedGpgHome = fs.mkdtempSync(
+ path.join(tempDir, 'user-gpg-home-')
+ );
+ fs.writeFileSync(
+ path.join(unrelatedGpgHome, 'private.key'),
+ 'pre-existing'
+ );
+ (core.getInput as jest.Mock).mockReturnValue('');
+ (core.getState as jest.Mock).mockImplementation((name: string) =>
+ name === constants.STATE_GPG_HOME ? gpgHome : ''
+ );
+
+ await cleanup();
+
+ expect(fs.existsSync(gpgHome)).toBe(false);
+ expect(
+ fs.readFileSync(path.join(unrelatedGpgHome, 'private.key'), 'utf8')
+ ).toBe('pre-existing');
+ fs.rmSync(unrelatedGpgHome, {recursive: true, force: true});
+ });
+
+ it('makes repeated cleanup of the same GPG home idempotent', async () => {
+ const tempDir = util.getTempDir();
+ fs.mkdirSync(tempDir, {recursive: true});
+ const gpgHome = fs.mkdtempSync(path.join(tempDir, GPG_HOME_PREFIX));
+ (core.getInput as jest.Mock).mockReturnValue('');
+ (core.getState as jest.Mock).mockImplementation((name: string) =>
+ name === constants.STATE_GPG_HOME ? gpgHome : ''
+ );
+
+ await cleanup();
+ await cleanup();
+
+ expect(fs.existsSync(gpgHome)).toBe(false);
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('skips GPG cleanup when no home was persisted', async () => {
+ (core.getInput as jest.Mock).mockReturnValue('');
+ (core.getState as jest.Mock).mockReturnValue('');
+
+ await cleanup();
+
+ expect(spyInfo).not.toHaveBeenCalledWith(
+ 'Removing private key from isolated GPG home'
+ );
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
it('does not fail even though the save process throws error', async () => {
spyCacheSave.mockImplementation((paths: string[], key: string) =>
Promise.reject(new Error('Unexpected error'))
);
- jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
return name === 'cache' ? 'gradle' : '';
});
await cleanup();
expect(spyCacheSave).toHaveBeenCalled();
});
+
+ it.each(['maven', 'gradle', 'sbt'])(
+ 'does not save the %s cache in read-only mode',
+ async packageManager => {
+ createStateForSuccessfulRestoreWithWrapper(packageManager);
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
+ switch (name) {
+ case 'cache':
+ return packageManager;
+ case 'cache-read-only':
+ return 'true';
+ default:
+ return '';
+ }
+ });
+
+ await cleanup();
+
+ expect(spyCacheSave).not.toHaveBeenCalled();
+ expect(core.getState).toHaveBeenCalledTimes(1);
+ expect(core.getState).toHaveBeenCalledWith(constants.STATE_GPG_HOME);
+ expect(spyInfo).toHaveBeenCalledWith(
+ 'Cache saving is skipped because cache-read-only is enabled.'
+ );
+ }
+ );
+
+ it('saves the cache when read-only mode is explicitly disabled', async () => {
+ spyCacheSave.mockResolvedValue(0);
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
+ switch (name) {
+ case 'cache':
+ return 'maven';
+ case 'cache-read-only':
+ return 'false';
+ default:
+ return '';
+ }
+ });
+
+ await cleanup();
+
+ expect(spyCacheSave).toHaveBeenCalled();
+ });
+
+ it('saves the JDK cache without dependency caching', async () => {
+ const {key, path: jdkPath, state} = createRegisteredJdk();
+ (core.getInput as jest.Mock).mockImplementation((name: string) =>
+ name === 'cache-jdk' ? 'true' : ''
+ );
+ (core.getState as jest.Mock).mockImplementation((name: string) =>
+ name === 'jdk-caches' ? state : ''
+ );
+ spyCacheSave.mockResolvedValue(1);
+
+ await cleanup();
+
+ expect(spyCacheSave).toHaveBeenCalledWith([jdkPath], key);
+ });
+
+ it('does not save a JDK cache when cache-jdk is disabled', async () => {
+ (core.getInput as jest.Mock).mockImplementation((name: string) =>
+ name === 'cache-jdk' ? 'false' : ''
+ );
+
+ await cleanup();
+
+ expect(spyCacheSave).not.toHaveBeenCalled();
+ });
+
+ it.each([
+ ['', '', false],
+ ['', 'true', true],
+ ['', 'false', false],
+ ['maven', '', true],
+ ['maven', 'true', true],
+ ['maven', 'false', false]
+ ])(
+ 'uses effective JDK caching for cache=%j and cache-jdk=%j',
+ async (cacheInput, cacheJdkInput, expectedJdkSave) => {
+ const {key: jdkKey, path: jdkPath, state} = createRegisteredJdk();
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
+ if (name === 'cache') return cacheInput;
+ if (name === 'cache-jdk') return cacheJdkInput;
+ return '';
+ });
+ (core.getState as jest.Mock).mockImplementation((name: string) =>
+ name === 'jdk-caches' ? state : ''
+ );
+ spyCacheSave.mockResolvedValue(1);
+
+ await cleanup();
+
+ const jdkSaveCalls = spyCacheSave.mock.calls.filter(
+ ([, key]) => key === jdkKey
+ );
+ expect(jdkSaveCalls).toHaveLength(expectedJdkSave ? 1 : 0);
+ if (expectedJdkSave) {
+ expect(spyCacheSave).toHaveBeenCalledWith([jdkPath], jdkKey);
+ }
+ }
+ );
+
+ it('keeps saving the remaining JDK caches when one save fails', async () => {
+ const first = createRegisteredJdk();
+ const second = createRegisteredJdk('17.0.19+9');
+ (core.getInput as jest.Mock).mockImplementation((name: string) =>
+ name === 'cache-jdk' ? 'true' : ''
+ );
+ (core.getState as jest.Mock).mockImplementation((name: string) =>
+ name === 'jdk-caches' ? second.state : ''
+ );
+ spyCacheSave.mockImplementation(async (paths: string[]) => {
+ if (paths[0] === first.path) {
+ throw new Error('Unexpected save failure');
+ }
+ return 1;
+ });
+
+ await cleanup();
+
+ expect(spyCacheSave).toHaveBeenCalledWith([first.path], first.key);
+ expect(spyCacheSave).toHaveBeenCalledWith([second.path], second.key);
+ expect(spyCoreError).not.toHaveBeenCalled();
+ });
+
+ it('does not save a JDK installation that was replaced after registration', async () => {
+ const {key, path: jdkPath, state, replace} = createRegisteredJdk();
+ (core.getInput as jest.Mock).mockImplementation((name: string) =>
+ name === 'cache-jdk' ? 'true' : ''
+ );
+ (core.getState as jest.Mock).mockImplementation((name: string) =>
+ name === 'jdk-caches' ? state : ''
+ );
+ spyCacheSave.mockResolvedValue(1);
+ replace();
+
+ await cleanup();
+
+ expect(spyCacheSave).not.toHaveBeenCalledWith([jdkPath], key);
+ });
});
function resetState() {
- jest.spyOn(core, 'getState').mockReset();
+ (core.getState as jest.Mock).mockReset();
}
/**
* Create states to emulate a successful restore process.
*/
function createStateForSuccessfulRestore() {
- jest.spyOn(core, 'getState').mockImplementation(name => {
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
@@ -73,3 +347,64 @@ function createStateForSuccessfulRestore() {
}
});
}
+
+function createStateForSuccessfulRestoreWithWrapper(packageManager: string) {
+ (core.getState as jest.Mock).mockImplementation((name: any) => {
+ switch (name) {
+ case 'cache-primary-key':
+ return 'setup-java-cache-primary-key';
+ case 'cache-matched-key':
+ return 'setup-java-cache-matched-key';
+ case `cache-primary-key-${packageManager}-wrapper`:
+ return `setup-java-${packageManager}-wrapper-primary-key`;
+ default:
+ return '';
+ }
+ });
+}
+
+/**
+ * Register a real JDK installation in a temporary tool cache so the post-job
+ * save sees the same installation identity that setup recorded.
+ */
+function createRegisteredJdk(version = '21.0.8+9') {
+ const root = fs.mkdtempSync(
+ path.join(os.tmpdir(), 'setup-java-cleanup-jdk-')
+ );
+ jdkTempRoots.push(root);
+ const jdkPath = path.join(
+ root,
+ 'Java_temurin_jdk',
+ version.replace('+', '-')
+ );
+ const write = (marker: string) => {
+ const architecturePath = path.join(jdkPath, 'x64');
+ fs.rmSync(architecturePath, {recursive: true, force: true});
+ fs.rmSync(`${architecturePath}.complete`, {force: true});
+ fs.mkdirSync(architecturePath, {recursive: true});
+ fs.writeFileSync(path.join(architecturePath, 'release'), marker);
+ fs.writeFileSync(`${architecturePath}.complete`, marker);
+ };
+ write('installed');
+
+ const jdk = {
+ distribution: 'temurin',
+ packageType: 'jdk',
+ architecture: 'x64',
+ version,
+ source: `sha256:${path.basename(root)}`,
+ verification: 'unverified',
+ path: jdkPath
+ };
+ registerJdk(jdk);
+ const state = (
+ (core.saveState as jest.Mock).mock.calls.at(-1) as string[]
+ )[1];
+
+ return {
+ key: buildJdkCacheKey(jdk),
+ path: jdkPath,
+ state,
+ replace: () => write('replaced-by-a-later-step')
+ };
+}
diff --git a/__tests__/data/adopt.json b/__tests__/data/adopt.json
deleted file mode 100644
index bcf140309..000000000
--- a/__tests__/data/adopt.json
+++ /dev/null
@@ -1,909 +0,0 @@
-[
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 74181,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "09b7e6ab5d5eb4b73813f4caa793a0b616d33794a17988fa6a6b7c972e8f3dd3",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz.sha256.txt",
- "download_count": 23872,
- "link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz.json",
- "name": "OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz",
- "size": 195705010
- },
- "project": "jdk",
- "scm_ref": "jdk-14.0.2+12_adopt",
- "updated_at": "2020-07-16T08:55:45Z"
- }
- ],
- "download_count": 477080,
- "id": "MDc6UmVsZWFzZTI4NjIyMDc4.+ve8KojpqJUpsA==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/tag/jdk-14.0.2%2B12",
- "release_name": "jdk-14.0.2+12",
- "release_type": "ga",
- "timestamp": "2020-07-16T08:54:16Z",
- "updated_at": "2020-07-16T08:54:16Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 12,
- "major": 14,
- "minor": 0,
- "openjdk_version": "14.0.2+12",
- "security": 2,
- "semver": "14.0.2+12"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 58023,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "b11cb192312530bcd84607631203d0c1727e672af12813078e6b525e3cce862d",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.1%2B7/OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz.sha256.txt",
- "download_count": 25276,
- "link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.1%2B7/OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.1%2B7/OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz.json",
- "name": "OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz",
- "size": 195769653
- },
- "project": "jdk",
- "scm_ref": "jdk-14.0.1+7_adopt",
- "updated_at": "2020-04-20T12:54:23Z"
- }
- ],
- "download_count": 198607,
- "id": "MDc6UmVsZWFzZTI1Njc4MzEw.z3NqYG25PFlG+Q==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/tag/jdk-14.0.1%2B7",
- "release_name": "jdk-14.0.1+7",
- "release_type": "ga",
- "timestamp": "2020-04-20T12:52:51Z",
- "updated_at": "2020-04-20T12:52:51Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 7,
- "major": 14,
- "minor": 0,
- "openjdk_version": "14.0.1+7",
- "security": 1,
- "semver": "14.0.1+7.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 30069,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "d358a7ff03905282348c6c80562a4da2e04eb377b60ad2152be4c90f8d580b7f",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz.sha256.txt",
- "download_count": 3718,
- "link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz.json",
- "name": "OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz",
- "size": 195232978
- },
- "project": "jdk",
- "scm_ref": "jdk-15.0.2+7_adopt",
- "updated_at": "2021-01-22T17:33:20Z"
- }
- ],
- "download_count": 124226,
- "id": "MDc6UmVsZWFzZTM2NzgwOTAw.X2+6VqPND3E8CA==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15.0.2%2B7",
- "release_name": "jdk-15.0.2+7",
- "release_type": "ga",
- "timestamp": "2021-01-22T17:31:37Z",
- "updated_at": "2021-01-22T17:31:37Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 7,
- "major": 15,
- "minor": 0,
- "openjdk_version": "15.0.2+7",
- "security": 2,
- "semver": "15.0.2+7"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 24542,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "b8c2e2ad31f3d6676ea665d9505b06df15e23741847556612b40e3ee329fc046",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9.1/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.sha256.txt",
- "download_count": 3274,
- "link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9.1/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9.1/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.json",
- "name": "OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
- "size": 195872839
- },
- "project": "jdk",
- "scm_ref": "jdk-15.0.1+9_adopt",
- "updated_at": "2020-12-01T16:57:47Z"
- }
- ],
- "download_count": 25378,
- "id": "MDc6UmVsZWFzZTM0NjQ2MDU4.Yj2XZf+VBGAPtw==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15.0.1%2B9.1",
- "release_name": "jdk-15.0.1+9.1",
- "release_type": "ga",
- "timestamp": "2020-12-01T16:57:26Z",
- "updated_at": "2020-12-01T16:57:26Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 9,
- "major": 15,
- "minor": 0,
- "openjdk_version": "15.0.1+9",
- "security": 1,
- "semver": "15.0.1+9.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 21675,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "d32f9429c4992cef7be559a15c542011503d6bc38c89379800cd209a9d7ec539",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.sha256.txt",
- "download_count": 11935,
- "link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.json",
- "name": "OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
- "size": 195773522
- },
- "project": "jdk",
- "scm_ref": "jdk-15.0.1+9_adopt",
- "updated_at": "2020-10-23T20:48:09Z"
- }
- ],
- "download_count": 308690,
- "id": "MDc6UmVsZWFzZTMyOTk4MTUx.3oazo3YGfHhF3w==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15.0.1%2B9",
- "release_name": "jdk-15.0.1+9",
- "release_type": "ga",
- "timestamp": "2020-10-23T20:46:22Z",
- "updated_at": "2020-10-23T20:46:22Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 9,
- "major": 15,
- "minor": 0,
- "openjdk_version": "15.0.1+9",
- "security": 1,
- "semver": "15.0.1+9"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 51254,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "bd1fc774232e2dfee93056a01f5765bd92ffb19d68dd548c233a82bb5c162be4",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz.sha256.txt",
- "download_count": 5325,
- "link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz.json",
- "name": "OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz",
- "size": 195853361
- },
- "project": "jdk",
- "scm_ref": "jdk-15+36_adopt",
- "updated_at": "2020-09-17T07:43:54Z"
- }
- ],
- "download_count": 157313,
- "id": "MDc6UmVsZWFzZTMxNDUwMjA0.eYpt0EBEjldfEQ==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15%2B36",
- "release_name": "jdk-15+36",
- "release_type": "ga",
- "timestamp": "2020-09-17T07:42:21Z",
- "updated_at": "2020-09-17T07:42:21Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 36,
- "major": 15,
- "minor": 0,
- "openjdk_version": "15+36",
- "security": 0,
- "semver": "15.0.0+36"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 27428,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "aabc3aebb0abf1ba64d9bd5796d0c7eb7239983f6e4c0f015b5b88be5616e4bd",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14%2B36/OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz.sha256.txt",
- "download_count": 19544,
- "link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14%2B36/OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14%2B36/OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz.json",
- "name": "OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz",
- "size": 201087797
- },
- "project": "jdk",
- "scm_ref": "jdk-14+36_adopt",
- "updated_at": "2020-03-18T12:13:05Z"
- }
- ],
- "download_count": 364816,
- "id": "MDc6UmVsZWFzZTI0NjMxMDAy.AY7rtvmrnWWlIg==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/tag/jdk-14%2B36",
- "release_name": "jdk-14+36",
- "release_type": "ga",
- "timestamp": "2020-03-18T12:11:08Z",
- "updated_at": "2020-03-18T12:11:08Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 36,
- "major": 14,
- "minor": 0,
- "openjdk_version": "14+36",
- "security": 0,
- "semver": "14.0.0+36.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 63201,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "0ddb24efdf5aab541898d19b7667b149a1a64a8bd039b708fc58ee0284fa7e07",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.2%2B8/OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz.sha256.txt",
- "download_count": 32531,
- "link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.2%2B8/OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.2%2B8/OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz.json",
- "name": "OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz",
- "size": 198206427
- },
- "project": "jdk",
- "scm_ref": "jdk-13.0.2+8_adopt",
- "updated_at": "2020-01-20T16:46:24Z"
- }
- ],
- "download_count": 349677,
- "id": "MDc6UmVsZWFzZTIyOTgxNTM1.gtZYwGfBgkb3Gg==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/tag/jdk-13.0.2%2B8",
- "release_name": "jdk-13.0.2+8",
- "release_type": "ga",
- "timestamp": "2020-01-20T16:42:35Z",
- "updated_at": "2020-01-20T16:42:35Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 8,
- "major": 13,
- "minor": 0,
- "openjdk_version": "13.0.2+8",
- "security": 2,
- "semver": "13.0.2+8.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 41508,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "9c82de98ce9bc2353bcf314d85366c9a2c572db034e10a71aa47e804e13748c1",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.1%2B9/OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz.sha256.txt",
- "download_count": 32262,
- "link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.1%2B9/OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.1%2B9/OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz.json",
- "name": "OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz",
- "size": 198205689
- },
- "project": "jdk",
- "scm_ref": "jdk-13.0.1+9_adopt",
- "updated_at": "2019-10-26T14:44:27Z"
- }
- ],
- "download_count": 680021,
- "id": "MDc6UmVsZWFzZTIwOTk4NDA0.srlG2TmLho/j0w==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/tag/jdk-13.0.1%2B9",
- "release_name": "jdk-13.0.1+9",
- "release_type": "ga",
- "timestamp": "2019-10-26T14:43:52Z",
- "updated_at": "2019-10-26T14:43:52Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 9,
- "major": 13,
- "minor": 0,
- "openjdk_version": "13.0.1+9",
- "security": 1,
- "semver": "13.0.1+9.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 37738,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "f948be96daba250b6695e22cb51372d2ba3060e4d778dd09c89548889783099f",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13%2B33/OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz.sha256.txt",
- "download_count": 37738,
- "link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13%2B33/OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13%2B33/OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz.json",
- "name": "OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz",
- "size": 198189530
- },
- "project": "jdk",
- "scm_ref": "jdk-13+33_adopt",
- "updated_at": "2019-09-19T10:20:21Z"
- }
- ],
- "download_count": 226200,
- "id": "MDc6UmVsZWFzZTIwMTA0MTUy.trK7qCbNtlMWFw==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/tag/jdk-13%2B33",
- "release_name": "jdk-13+33",
- "release_type": "ga",
- "timestamp": "2019-09-19T10:19:58Z",
- "updated_at": "2019-09-19T10:19:58Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 33,
- "major": 13,
- "minor": 0,
- "openjdk_version": "13+33",
- "security": 0,
- "semver": "13.0.0+33.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 24493,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "9919eee037554d40c7d2f219bbd654f2bf119e16a2f4d284d8dedaf525ee59e6",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
- "download_count": 22907,
- "link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
- "name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "size": 198392994
- },
- "project": "jdk",
- "scm_ref": "jdk-12.0.2+10_adopt",
- "updated_at": "2019-07-18T20:27:24Z"
- }
- ],
- "download_count": 396318,
- "id": "MDc6UmVsZWFzZTE4NzE2Mzk5.S/VUFSgnrVIv8A==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10",
- "release_name": "jdk-12.0.2+10",
- "release_type": "ga",
- "timestamp": "2019-07-18T20:26:29Z",
- "updated_at": "2019-07-18T20:26:29Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 10,
- "major": 12,
- "minor": 0,
- "openjdk_version": "12.0.2+10",
- "security": 2,
- "semver": "12.0.2+10.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 5539,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "7acd697e816491d31b24d0ae1867fd63060aa738cfa388757946ae312a60b4f2",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.3/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
- "download_count": 5539,
- "link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.3/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.3/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
- "name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "size": 198429049
- },
- "project": "jdk",
- "scm_ref": "jdk-12.0.2+10_adopt",
- "updated_at": "2019-09-19T17:17:37Z"
- }
- ],
- "download_count": 5879,
- "id": "MDc6UmVsZWFzZTIwMTE2ODQ3.QGQl8Nj1qkma4Q==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10.3",
- "release_name": "jdk-12.0.2+10.3",
- "release_type": "ga",
- "timestamp": "2019-09-19T17:17:26Z",
- "updated_at": "2019-12-06T15:10:37Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 3,
- "build": 10,
- "major": 12,
- "minor": 0,
- "openjdk_version": "12.0.2+10",
- "security": 2,
- "semver": "12.0.2+10.3"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 22794,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "2c1a46c0fab6d4bdbc443f23c3f6a313c2de47fbbd9c16b5c1133a88f6c1ab8f",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.2/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
- "download_count": 637,
- "link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.2/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.2/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
- "name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "size": 198862174
- },
- "project": "jdk",
- "scm_ref": "jdk-12.0.2+10_adopt",
- "updated_at": "2019-08-06T10:41:10Z"
- }
- ],
- "download_count": 23563,
- "id": "MDc6UmVsZWFzZTE5MTAzMTI3.in65dKG+veAxOg==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10.2",
- "release_name": "jdk-12.0.2+10.2",
- "release_type": "ga",
- "timestamp": "2019-08-06T10:40:44Z",
- "updated_at": "2019-08-06T10:40:44Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 2,
- "build": 10,
- "major": 12,
- "minor": 0,
- "openjdk_version": "12.0.2+10",
- "security": 2,
- "semver": "12.0.2+10.2"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 24493,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "9919eee037554d40c7d2f219bbd654f2bf119e16a2f4d284d8dedaf525ee59e6",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
- "download_count": 22907,
- "link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
- "name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
- "size": 198392994
- },
- "project": "jdk",
- "scm_ref": "jdk-12.0.2+9_adopt",
- "updated_at": "2019-07-18T20:27:24Z"
- }
- ],
- "download_count": 396318,
- "id": "MDc6UmVsZWFzZTE4NzE2Mzk5.S/VUFSgnrVIv8A==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10",
- "release_name": "jdk-12.0.2+9",
- "release_type": "ga",
- "timestamp": "2019-07-18T20:26:29Z",
- "updated_at": "2019-07-18T20:26:29Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 10,
- "major": 12,
- "minor": 0,
- "openjdk_version": "12.0.2+9",
- "security": 2,
- "semver": "12.0.2+9.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 39519,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "dcb2ab681247298eda018df24166ba01674127083fb02892acf087e6181d8c56",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.1%2B12/OpenJDK12U-jdk_x64_mac_hotspot_12.0.1_12.tar.gz.sha256.txt",
- "download_count": 33306,
- "link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.1%2B12/OpenJDK12U-jdk_x64_mac_hotspot_12.0.1_12.tar.gz",
- "name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.1_12.tar.gz",
- "size": 198112975
- },
- "project": "jdk",
- "updated_at": "2019-04-21T15:12:34Z"
- }
- ],
- "download_count": 1038669,
- "id": "MDc6UmVsZWFzZTE2ODg3NDU3",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.1%2B12",
- "release_name": "jdk-12.0.1+12",
- "release_type": "ga",
- "timestamp": "2019-04-21T15:11:56Z",
- "updated_at": "2019-04-21T15:11:56Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 12,
- "major": 12,
- "minor": 0,
- "openjdk_version": "12.0.1+12",
- "security": 1,
- "semver": "12.0.1+12"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 3136,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "985036459d4ef0867a3fe83b0bf87877d8e66a121c7b9c145bb97bd921aaf3f1",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12%2B33/OpenJDK12U-jdk_x64_mac_hotspot_12_33.tar.gz.sha256.txt",
- "download_count": 1905,
- "link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12%2B33/OpenJDK12U-jdk_x64_mac_hotspot_12_33.tar.gz",
- "name": "OpenJDK12U-jdk_x64_mac_hotspot_12_33.tar.gz",
- "size": 198099074
- },
- "project": "jdk",
- "updated_at": "2019-03-22T12:09:13Z"
- }
- ],
- "download_count": 757289,
- "id": "MDc6UmVsZWFzZTE2MjgyMjM2",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12%2B33",
- "release_name": "jdk-12+33",
- "release_type": "ga",
- "timestamp": "2019-03-22T12:08:43Z",
- "updated_at": "2019-03-22T12:08:43Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 33,
- "major": 12,
- "minor": 0,
- "openjdk_version": "12+33",
- "security": 0,
- "semver": "12.0.0+33"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 75576,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "ee7c98c9d79689aca6e717965747b8bf4eec5413e89d5444cc2bd6dbd59e3811",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz.sha256.txt",
- "download_count": 17426,
- "link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz.json",
- "name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz",
- "size": 186160219
- },
- "project": "jdk",
- "scm_ref": "jdk-11.0.10+9_adopt",
- "updated_at": "2021-01-22T14:16:47Z"
- }
- ],
- "download_count": 636180,
- "id": "MDc6UmVsZWFzZTM2NzcwNDUy.hAVJRiZZTufG+w==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.10%2B9",
- "release_name": "jdk-11.0.10+9",
- "release_type": "ga",
- "timestamp": "2021-01-22T14:15:12Z",
- "updated_at": "2021-01-22T14:15:12Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 9,
- "major": 11,
- "minor": 0,
- "openjdk_version": "11.0.10+9",
- "security": 10,
- "semver": "11.0.10+9"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 108441,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "96bc469f9b02a3b84382a0685b0bd7935e1ad1bd82a0aab9befb5b42a17cbd77",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9.1%2B1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz.sha256.txt",
- "download_count": 22211,
- "link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9.1%2B1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9.1%2B1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz.json",
- "name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz",
- "size": 185368626
- },
- "project": "jdk",
- "scm_ref": "jdk-11.0.9.1+1_adopt",
- "updated_at": "2020-11-12T14:10:45Z"
- }
- ],
- "download_count": 815676,
- "id": "MDc6UmVsZWFzZTMzODU4MDE1.94IbKUd3vvhzsA==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.9.1%2B1",
- "release_name": "jdk-11.0.9.1+1",
- "release_type": "ga",
- "timestamp": "2020-11-12T14:08:55Z",
- "updated_at": "2020-11-12T14:08:55Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 1,
- "major": 11,
- "minor": 0,
- "openjdk_version": "11.0.9.1+1",
- "patch": 1,
- "security": 9,
- "semver": "11.0.9+101"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 45450,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "7b21961ffb2649e572721a0dfad64169b490e987937b661cb4e13a594c21e764",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11.1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.sha256.txt",
- "download_count": 11117,
- "link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11.1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11.1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.json",
- "name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
- "size": 186006796
- },
- "project": "jdk",
- "scm_ref": "jdk-11.0.9+11_adopt",
- "updated_at": "2020-10-25T14:43:54Z"
- }
- ],
- "download_count": 423635,
- "id": "MDc6UmVsZWFzZTMzMDI4MDcz.dRvNNRwJCgY3Xw==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.9%2B11.1",
- "release_name": "jdk-11.0.9+11.1",
- "release_type": "ga",
- "timestamp": "2020-10-25T13:31:15Z",
- "updated_at": "2020-10-25T13:31:15Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "adopt_build_number": 1,
- "build": 11,
- "major": 11,
- "minor": 0,
- "openjdk_version": "11.0.9+11",
- "security": 9,
- "semver": "11.0.9+11.1"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 2456,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "e84b00d74f08f059829bbf121c8423dc37ff65135968c1fcda5839600be4f542",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.sha256.txt",
- "download_count": 1046,
- "link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.json",
- "name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
- "size": 185532704
- },
- "project": "jdk",
- "scm_ref": "jdk-11.0.9+11_adopt",
- "updated_at": "2020-10-25T13:28:33Z"
- }
- ],
- "download_count": 359580,
- "id": "MDc6UmVsZWFzZTMyOTk4MzM5.6h9TT9pzYTK2Kg==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.9%2B11",
- "release_name": "jdk-11.0.9+11",
- "release_type": "ga",
- "timestamp": "2020-10-23T20:52:14Z",
- "updated_at": "2020-10-23T20:52:14Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 11,
- "major": 11,
- "minor": 0,
- "openjdk_version": "11.0.9+11",
- "security": 9,
- "semver": "11.0.9+11"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 149393,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "4a8dadd58cdc32c7e59978971d56aec610be7ee0ddf0dc1d137bb8b78456499f",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.sha256.txt",
- "download_count": 40158,
- "link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.json",
- "name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
- "size": 185054456
- },
- "project": "jdk",
- "scm_ref": "jdk-11.0.8+10_adopt",
- "updated_at": "2020-07-15T14:30:51Z"
- }
- ],
- "download_count": 1968658,
- "id": "MDc6UmVsZWFzZTI4NTg5Nzcz.pCNBA7G9E1o7pw==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.8%2B10",
- "release_name": "jdk-11.0.8+10",
- "release_type": "ga",
- "timestamp": "2020-07-15T14:29:27Z",
- "updated_at": "2020-07-15T14:29:27Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 10,
- "major": 11,
- "minor": 0,
- "openjdk_version": "11.0.8+10",
- "security": 8,
- "semver": "11.0.8+10"
- }
- },
- {
- "binaries": [],
- "download_count": 1968658,
- "id": "MDc6UmVsZWFzZTI4NTg5Nzcz.pCNBA7G9E1o7pw==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.8%2B10",
- "release_name": "jdk-11.0.8+10",
- "release_type": "ga",
- "timestamp": "2020-07-15T14:29:27Z",
- "updated_at": "2020-07-15T14:29:27Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 10,
- "major": 9,
- "minor": 0,
- "openjdk_version": "9.0.8+10",
- "security": 8,
- "semver": "9.0.8+10"
- }
- },
- {
- "binaries": [
- {
- "architecture": "x64",
- "download_count": 149393,
- "heap_size": "normal",
- "image_type": "jdk",
- "jvm_impl": "hotspot",
- "os": "mac",
- "package": {
- "checksum": "4a8dadd58cdc32c7e59978971d56aec610be7ee0ddf0dc1d137bb8b78456499f",
- "checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.sha256.txt",
- "download_count": 40158,
- "link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
- "metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.json",
- "name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
- "size": 185054456
- },
- "project": "jdk",
- "scm_ref": "jdk-11.0.8+10_adopt",
- "updated_at": "2020-07-15T14:30:51Z"
- }
- ],
- "download_count": 1968658,
- "id": "MDc6UmVsZWFzZTI4NTg5Nzcz.pCNBA7G9E1o7pw==",
- "release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.8%2B10",
- "release_name": "jdk-11.0.8+10",
- "release_type": "ga",
- "timestamp": "2020-07-15T14:29:27Z",
- "updated_at": "2020-07-15T14:29:27Z",
- "vendor": "adoptopenjdk",
- "version_data": {
- "build": 10,
- "major": 9,
- "minor": 0,
- "openjdk_version": "9.0.8+10",
- "security": 8,
- "semver": "9.0.7+10"
- }
- }
-]
\ No newline at end of file
diff --git a/__tests__/data/kona.json b/__tests__/data/kona.json
new file mode 100644
index 000000000..7dc24c38d
--- /dev/null
+++ b/__tests__/data/kona.json
@@ -0,0 +1,202 @@
+{
+ "8": [
+ {
+ "version": "8.0.20",
+ "jdkVersion": "8u432",
+ "latest": true,
+ "baseUrl": "https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/",
+ "files": [
+ {
+ "os": "linux",
+ "arch": "aarch64",
+ "filename": "TencentKona8.0.20.b1_jdk_linux-aarch64_8u432.tar.gz",
+ "checksum": "8e6ab38b17f98d7ba727037cb49bbd174f3103a6ddacafb1fb7c0231006a80a7"
+ },
+ {
+ "os": "linux",
+ "arch": "x86_64",
+ "filename": "TencentKona8.0.20.b1_jdk_linux-x86_64_8u432.tar.gz",
+ "checksum": "384cdb36b38993f4b7292682a5dfd8d5d33ba7bdbca2d95018d1341c792d2823"
+ },
+ {
+ "os": "macos",
+ "arch": "aarch64",
+ "filename": "TencentKona8.0.20.b1_jdk_macosx-aarch64_8u432_notarized.tar.gz",
+ "checksum": "829c46691a4b519f14fedfcdca32a94d7793d3570c4a51b3a5072cc394619f25"
+ },
+ {
+ "os": "macos",
+ "arch": "x86_64",
+ "filename": "TencentKona8.0.20.b1_jdk_macosx-x86_64_8u432_notarized.tar.gz",
+ "checksum": ""
+ },
+ {
+ "os": "windows",
+ "arch": "x86_64",
+ "filename": "TencentKona8.0.20.b1_jdk_windows-x86_64_8u432_signed.zip",
+ "checksum": "339646817254dbcb5c17904807bbfdeafaa8e4bac9f2aae25434870cdeaba296"
+ }
+ ]
+ }
+ ],
+ "11": [
+ {
+ "version": "11.0.25",
+ "jdkVersion": "11.0.25",
+ "latest": true,
+ "baseUrl": "https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/",
+ "files": [
+ {
+ "os": "linux",
+ "arch": "aarch64",
+ "filename": "TencentKona-11.0.25.b1-jdk_linux-aarch64.tar.gz",
+ "checksum": "887ca5eeb675dd9b9d22833a8b0c1031ee1a031227d6cf2d8c1920cc585d2b71"
+ },
+ {
+ "os": "linux",
+ "arch": "x86_64",
+ "filename": "TencentKona-11.0.25.b1-jdk_linux-x86_64.tar.gz",
+ "checksum": "6642d7cccf98f33b3ec55cdbf77979c614f0d3cbbd282e8d0df52233edc52f9a"
+ },
+ {
+ "os": "macos",
+ "arch": "aarch64",
+ "filename": "TencentKona-11.0.25.b1_jdk_macosx-aarch64_notarized.tar.gz",
+ "checksum": "8f07242d3191a35c3b2fca1122f315518c7312f0155e98ac7ae39ea083f93e21"
+ },
+ {
+ "os": "macos",
+ "arch": "x86_64",
+ "filename": "TencentKona-11.0.25.b1_jdk_macosx-x86_64_notarized.tar.gz",
+ "checksum": "0832b93d8d8122cb72db85321ddd85c9a6086e0f28327733fc2da3c0ecc9c455"
+ },
+ {
+ "os": "windows",
+ "arch": "x86_64",
+ "filename": "TencentKona-11.0.25.b1_jdk_windows-x86_64_signed.zip",
+ "checksum": "05c470c5da4b3bc1844117f611ecd241d3ae9e5d01c17ffafffde0f23825aad7"
+ }
+ ]
+ }
+ ],
+ "17": [
+ {
+ "version": "17.0.13",
+ "jdkVersion": "17.0.13",
+ "latest": true,
+ "baseUrl": "https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/",
+ "files": [
+ {
+ "os": "linux",
+ "arch": "aarch64",
+ "filename": "TencentKona-17.0.13.b1-jdk_linux-aarch64.tar.gz",
+ "checksum": "372411dff5b42f6e419f1dd40772d98141a15c3d180ed1af6f2b49bdbbd32d52"
+ },
+ {
+ "os": "linux",
+ "arch": "x86_64",
+ "filename": "TencentKona-17.0.13.b1-jdk_linux-x86_64.tar.gz",
+ "checksum": "b54bb023d1187737b23ca34d0857d2d40822b14e38d28c7948c8ff6b5927e523"
+ },
+ {
+ "os": "macos",
+ "arch": "aarch64",
+ "filename": "TencentKona-17.0.13.b1_jdk_macosx-aarch64_notarized.tar.gz",
+ "checksum": "22f5d296c407fc137e6af9ce275e662346ca82f1a5acfc407247efd8cedf5256"
+ },
+ {
+ "os": "macos",
+ "arch": "x86_64",
+ "filename": "TencentKona-17.0.13.b1_jdk_macosx-x86_64_notarized.tar.gz",
+ "checksum": "87ace41ac9718f2a9512b24bad0f735bc5ac61b8198b4cd5634199f124883b36"
+ },
+ {
+ "os": "windows",
+ "arch": "x86_64",
+ "filename": "TencentKona-17.0.13.b1_jdk_windows-x86_64_signed.zip",
+ "checksum": "616089018151e8e5daf8e88276063633a2cb28a718a2afce49bb8fc10541e83d"
+ }
+ ]
+ }
+ ],
+ "21": [
+ {
+ "version": "21.0.5",
+ "jdkVersion": "21.0.5",
+ "latest": true,
+ "baseUrl": "https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/",
+ "files": [
+ {
+ "os": "linux",
+ "arch": "aarch64",
+ "filename": "TencentKona-21.0.5.b1-jdk_linux-aarch64.tar.gz",
+ "checksum": "d8ca108147db3f19134d7aa995bac14e1fb3d124b0300a9a7893266a8f028104"
+ },
+ {
+ "os": "linux",
+ "arch": "x86_64",
+ "filename": "TencentKona-21.0.5.b1-jdk_linux-x86_64.tar.gz",
+ "checksum": "afae039d9666fadcb84940c5350b29cd061019b0cc43700f0bf0342320892adf"
+ },
+ {
+ "os": "macos",
+ "arch": "aarch64",
+ "filename": "TencentKona-21.0.5.b1_jdk_macosx-aarch64_notarized.tar.gz",
+ "checksum": "7621a218767bfbd3023b176dc6d9dd019677f8efec0d48a4eb2b2ed2b50bd1fb"
+ },
+ {
+ "os": "macos",
+ "arch": "x86_64",
+ "filename": "TencentKona-21.0.5.b1_jdk_macosx-x86_64_notarized.tar.gz",
+ "checksum": "6c54d46f979ad998b708f664c5aeeeef855660ef527d584a7c2930951cca9999"
+ },
+ {
+ "os": "windows",
+ "arch": "x86_64",
+ "filename": "TencentKona-21.0.5.b1_jdk_windows-x86_64_signed.zip",
+ "checksum": "ee1ee730fc5e02268d91b9df602b65122dad25b3d3898069331ebc8338005da1"
+ }
+ ]
+ }
+ ],
+ "25": [
+ {
+ "version": "25.0.3",
+ "jdkVersion": "25.0.3",
+ "latest": true,
+ "baseUrl": "https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/",
+ "files": [
+ {
+ "os": "linux",
+ "arch": "aarch64",
+ "filename": "TencentKona-25.0.3.b1-jdk_linux-aarch64.tar.gz",
+ "checksum": "2fb77e3ba9c00045ca497ea22210f18dae4bf7df4c87029f5abadd42a5daf8c7"
+ },
+ {
+ "os": "linux",
+ "arch": "x86_64",
+ "filename": "TencentKona-25.0.3.b1-jdk_linux-x86_64.tar.gz",
+ "checksum": "47445e6fad020e834055a705bb48fa3cd0727a2c57ad6f1c5206a45f4efb2d67"
+ },
+ {
+ "os": "macos",
+ "arch": "aarch64",
+ "filename": "TencentKona-25.0.3.b1_jdk_macosx-aarch64_notarized.tar.gz",
+ "checksum": "e29405eff95da412ed7ecc890e6ef5ebbfcd9ab334005b3d32d1700bbe4204d2"
+ },
+ {
+ "os": "macos",
+ "arch": "x86_64",
+ "filename": "TencentKona-25.0.3.b1_jdk_macosx-x86_64_notarized.tar.gz",
+ "checksum": "d512db5c079db16bd3a9c86d9cb979808994e90e4de29e17d27e5219fe488659"
+ },
+ {
+ "os": "windows",
+ "arch": "x86_64",
+ "filename": "TencentKona-25.0.3.b1_jdk_windows-x86_64_signed.zip",
+ "checksum": "865bce92ccbbca75115076e618a98baa1d0f30fcccdce954c0a22bee33d6ae83"
+ }
+ ]
+ }
+ ]
+}
diff --git a/__tests__/data/liberica-nik.json b/__tests__/data/liberica-nik.json
new file mode 100644
index 000000000..e5d920515
--- /dev/null
+++ b/__tests__/data/liberica-nik.json
@@ -0,0 +1,739 @@
+[
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.1+3-25.0.1+16/bellsoft-liberica-vm-openjdk25.0.1+16-25.0.1+3-linux-amd64.tar.gz",
+ "version": "25.0.1+3",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "25.0.1+16",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.1.0+1-23+38/bellsoft-liberica-vm-openjdk23+38-24.1.0+1-linux-amd64.tar.gz",
+ "version": "24.1.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "23+38",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.2/bellsoft-liberica-vm-openjdk11.0.15.1+2-21.3.2+2-linux-amd64.tar.gz",
+ "version": "21.3.2+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.15.1+2",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.0/bellsoft-liberica-vm-openjdk17.0.5+8-22.3.0+2-linux-amd64.tar.gz",
+ "version": "22.3.0+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.5+8",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.9+1-17.0.16+13/bellsoft-liberica-vm-openjdk17.0.16+13-23.0.9+1-linux-amd64.tar.gz",
+ "version": "23.0.9+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.16+13",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/23.0.0/bellsoft-liberica-vm-openjdk17.0.7+7-23.0.0+1-src.tar.gz",
+ "version": "23.0.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.7+7",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.2+1-25.0.2+13/bellsoft-liberica-vm-openjdk25.0.2+13-25.0.2+1-linux-amd64.tar.gz",
+ "version": "25.0.2+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "25.0.2+13",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.1.1+1-23.0.1+13/bellsoft-liberica-vm-openjdk23.0.1+13-24.1.1+1-linux-amd64.tar.gz",
+ "version": "24.1.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "23.0.1+13",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.12+1-17.0.19+12/bellsoft-liberica-vm-openjdk17.0.19+12-23.0.12+1-linux-amd64.tar.gz",
+ "version": "23.0.12+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.19+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.3+1-17.0.10+13/bellsoft-liberica-vm-openjdk17.0.10+13-23.0.3+1-linux-amd64.tar.gz",
+ "version": "23.0.3+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.10+13",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.2/bellsoft-liberica-vm-openjdk11-21.3.2-src.tar.gz",
+ "version": "21.3.2+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.15+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.3/bellsoft-liberica-vm-openjdk11.0.20+8-22.3.3+1-src.tar.gz",
+ "version": "22.3.3+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.20+8",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.8+1-17.0.15+10/bellsoft-liberica-vm-openjdk17.0.15+10-23.0.8+1-linux-amd64.tar.gz",
+ "version": "23.0.8+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.15+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.3/bellsoft-liberica-vm-openjdk17.0.4-21.3.3-src.tar.gz",
+ "version": "21.3.3+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.4+8",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.7+1-21.0.7+9/bellsoft-liberica-vm-openjdk21.0.7+9-23.1.7+1-linux-amd64.tar.gz",
+ "version": "23.1.7+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.7+9",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.8+1-21.0.8+13/bellsoft-liberica-vm-openjdk21.0.8+13-23.1.8+1-linux-amd64.tar.gz",
+ "version": "23.1.8+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.8+13",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.0.0.2/bellsoft-liberica-vm-openjdk11-21.0.0.2-src.tar.gz",
+ "version": "21.0.0.2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.10+9",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/23.0.1/bellsoft-liberica-vm-openjdk17.0.8+7-23.0.1+1-linux-amd64.tar.gz",
+ "version": "23.0.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.8+7",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.0.0+1-22+37/bellsoft-liberica-vm-openjdk22+37-24.0.0+1-linux-amd64.tar.gz",
+ "version": "24.0.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "22+37",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.1.0/bellsoft-liberica-vm-openjdk17-22.1.0-src.tar.gz",
+ "version": "22.1.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.3+7",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.0.2+1-22.0.2+11/bellsoft-liberica-vm-openjdk22.0.2+11-24.0.2+1-linux-amd64.tar.gz",
+ "version": "24.0.2+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "22.0.2+11",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/23.0.1/bellsoft-liberica-vm-openjdk20.0.2+10-23.0.1+1-src.tar.gz",
+ "version": "23.0.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "20.0.2+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/23.1.0/bellsoft-liberica-vm-openjdk21+37-23.1.0+1-linux-amd64.tar.gz",
+ "version": "23.1.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21+37",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.4+3-21.0.4+9/bellsoft-liberica-vm-openjdk21.0.4+9-23.1.4+3-linux-amd64.tar.gz",
+ "version": "23.1.4+3",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.4+9",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.3/bellsoft-liberica-vm-openjdk11.0.20.1+1-22.3.3+2-linux-amd64.tar.gz",
+ "version": "22.3.3+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.20.1+1",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.4+1-17.0.11+10/bellsoft-liberica-vm-openjdk17.0.11+10-23.0.4+1-linux-amd64.tar.gz",
+ "version": "23.0.4+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.11+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.1.2+1-23.0.2+9/bellsoft-liberica-vm-openjdk23.0.2+9-24.1.2+1-linux-amd64.tar.gz",
+ "version": "24.1.2+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "23.0.2+9",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.10+1-17.0.17+12/bellsoft-liberica-vm-openjdk17.0.17+12-23.0.10+1-linux-amd64.tar.gz",
+ "version": "23.0.10+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.17+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.1/bellsoft-liberica-vm-openjdk11.0.18+10-22.3.1+1-src.tar.gz",
+ "version": "22.3.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.18+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.0.0.2/bellsoft-liberica-vm-openjdk17-22.0.0.2-src.tar.gz",
+ "version": "22.0.0.2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.2+9",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.0.0.2/bellsoft-liberica-vm-openjdk11-22.0.0.2-linux-amd64.tar.gz",
+ "version": "22.0.0.2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.14.1+1",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.1+2-25.0.1+14/bellsoft-liberica-vm-openjdk25.0.1+14-25.0.1+2-linux-amd64.tar.gz",
+ "version": "25.0.1+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "25.0.1+14",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.3/bellsoft-liberica-vm-openjdk11.0.16-21.3.3-src.tar.gz",
+ "version": "21.3.3+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.16+8",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.5+1-21.0.5+11/bellsoft-liberica-vm-openjdk21.0.5+11-23.1.5+1-linux-amd64.tar.gz",
+ "version": "23.1.5+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.5+11",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.4/bellsoft-liberica-vm-openjdk17.0.9+11-22.3.4+1-linux-amd64.tar.gz",
+ "version": "22.3.4+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.9+11",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.0+1-25+37/bellsoft-liberica-vm-openjdk25+37-25.0.0+1-linux-amd64.tar.gz",
+ "version": "25.0.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "25+37",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.3/bellsoft-liberica-vm-openjdk17.0.8.1+1-22.3.3+2-linux-amd64.tar.gz",
+ "version": "22.3.3+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.8.1+1",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.3+1-21.0.3+10/bellsoft-liberica-vm-openjdk21.0.3+10-23.1.3+1-linux-amd64.tar.gz",
+ "version": "23.1.3+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.3+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.2.0+1-24+37/bellsoft-liberica-vm-openjdk24+37-24.2.0+1-linux-amd64.tar.gz",
+ "version": "24.2.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "24+37",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/23.1.1/bellsoft-liberica-vm-openjdk21.0.1+12-23.1.1+1-linux-amd64.tar.gz",
+ "version": "23.1.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.1+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.3/bellsoft-liberica-vm-openjdk17.0.4.1-21.3.3-src.tar.gz",
+ "version": "21.3.3+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.4.1+1",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.11+2-21.0.11+12/bellsoft-liberica-vm-openjdk21.0.11+12-23.1.11+2-linux-amd64.tar.gz",
+ "version": "23.1.11+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.11+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.2/bellsoft-liberica-vm-openjdk11.0.19+7-22.3.2+1-src.tar.gz",
+ "version": "22.3.2+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.19+7",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.4/bellsoft-liberica-vm-openjdk11.0.21+10-22.3.4+1-src.tar.gz",
+ "version": "22.3.4+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.21+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.3+2-25.0.3+12/bellsoft-liberica-vm-openjdk25.0.3+12-25.0.3+2-linux-amd64.tar.gz",
+ "version": "25.0.3+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "25.0.3+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.2/bellsoft-liberica-vm-openjdk17.0.3.1+2-21.3.2+2-linux-amd64.tar.gz",
+ "version": "21.3.2+2",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.3.1+2",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.2.1+1-24.0.1+11/bellsoft-liberica-vm-openjdk24.0.1+11-24.2.1+1-linux-amd64.tar.gz",
+ "version": "24.2.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "24.0.1+11",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.2.0/bellsoft-liberica-vm-openjdk11.0.16.1+1-22.2.0+3-linux-amd64.tar.gz",
+ "version": "22.2.0+3",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.16.1+1",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.6+1-17.0.13+12/bellsoft-liberica-vm-openjdk17.0.13+12-23.0.6+1-linux-amd64.tar.gz",
+ "version": "23.0.6+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.13+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/23.0.0/bellsoft-liberica-vm-openjdk20.0.1+10-23.0.0+1-linux-amd64.tar.gz",
+ "version": "23.0.0+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "20.0.1+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.10+1-21.0.10+11/bellsoft-liberica-vm-openjdk21.0.10+11-23.1.10+1-linux-amd64.tar.gz",
+ "version": "23.1.10+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.10+11",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/22.3.1/bellsoft-liberica-vm-openjdk17.0.6+10-22.3.1+1-src.tar.gz",
+ "version": "22.3.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.6+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.0/bellsoft-liberica-vm-openjdk17-21.3.0-src.tar.gz",
+ "version": "21.3.0",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.1+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.0/bellsoft-liberica-vm-openjdk11-21.3.0-src.tar.gz",
+ "version": "21.3.0",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.13+8",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.0.1+1-22.0.1+10/bellsoft-liberica-vm-openjdk22.0.1+10-24.0.1+1-linux-amd64.tar.gz",
+ "version": "24.0.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "22.0.1+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.7+1-17.0.14+10/bellsoft-liberica-vm-openjdk17.0.14+10-23.0.7+1-linux-amd64.tar.gz",
+ "version": "23.0.7+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.14+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.1.0/bellsoft-liberica-vm-openjdk11-21.1.0-src.tar.gz",
+ "version": "21.1.0",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.11+9",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.6+1-21.0.6+10/bellsoft-liberica-vm-openjdk21.0.6+10-23.1.6+1-linux-amd64.tar.gz",
+ "version": "23.1.6+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.6+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.1+1-25.0.1+12/bellsoft-liberica-vm-openjdk25.0.1+12-25.0.1+1-linux-amd64.tar.gz",
+ "version": "25.0.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "25.0.1+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.9+1-21.0.9+12/bellsoft-liberica-vm-openjdk21.0.9+12-23.1.9+1-linux-amd64.tar.gz",
+ "version": "23.1.9+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.9+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/22.3.5+1-11.0.22+12/bellsoft-liberica-vm-openjdk11.0.22+12-22.3.5+1-linux-amd64.tar.gz",
+ "version": "22.3.5+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.22+12",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.5+1-17.0.12+10/bellsoft-liberica-vm-openjdk17.0.12+10-23.0.5+1-linux-amd64.tar.gz",
+ "version": "23.0.5+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.12+10",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.3.3.1/bellsoft-liberica-vm-openjdk11.0.17+7-21.3.3.1+1-linux-amd64.tar.gz",
+ "version": "21.3.3.1+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.17+7",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://download.bell-sw.com/vm/21.2.0/bellsoft-liberica-vm-openjdk11-21.2.0-linux-amd64.tar.gz",
+ "version": "21.2.0",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "11.0.12+7",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.11+1-17.0.18+11/bellsoft-liberica-vm-openjdk17.0.18+11-23.0.11+1-linux-amd64.tar.gz",
+ "version": "23.0.11+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "17.0.18+11",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.2+1-21.0.2+14/bellsoft-liberica-vm-openjdk21.0.2+14-23.1.2+1-linux-amd64.tar.gz",
+ "version": "23.1.2+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "21.0.2+14",
+ "embedded": true
+ }
+ ]
+ },
+ {
+ "downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.2.2+1-24.0.2+13/bellsoft-liberica-vm-openjdk24.0.2+13-24.2.2+1-linux-amd64.tar.gz",
+ "version": "24.2.2+1",
+ "components": [
+ {
+ "component": "liberica",
+ "version": "24.0.2+13",
+ "embedded": true
+ }
+ ]
+ }
+]
diff --git a/__tests__/data/microsoft.json b/__tests__/data/microsoft.json
index 18e67d9d3..b67b9447d 100644
--- a/__tests__/data/microsoft.json
+++ b/__tests__/data/microsoft.json
@@ -1,4 +1,47 @@
[
+ {
+ "version": "25.0.0",
+ "stable": true,
+ "release_url": "https://aka.ms/download-jdk",
+ "files": [
+ {
+ "filename": "microsoft-jdk-25.0.0-macos-x64.tar.gz",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-25.0.0-macos-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-25.0.0-linux-x64.tar.gz",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-25.0.0-linux-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-25.0.0-windows-x64.zip",
+ "arch": "x64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-25.0.0-windows-x64.zip"
+ },
+ {
+ "filename": "microsoft-jdk-25.0.0-macos-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-25.0.0-macos-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-25.0.0-linux-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-25.0.0-linux-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-25.0.0-windows-aarch64.zip",
+ "arch": "aarch64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-25.0.0-windows-aarch64.zip"
+ }
+ ]
+ },
{
"version": "21.0.0",
"stable": true,
@@ -36,6 +79,49 @@
}
]
},
+ {
+ "version": "17.0.18",
+ "stable": true,
+ "release_url": "https://aka.ms/download-jdk",
+ "files": [
+ {
+ "filename": "microsoft-jdk-17.0.18-macos-x64.tar.gz",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.18-linux-x64.tar.gz",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.18-windows-x64.zip",
+ "arch": "x64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-x64.zip"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.18-macos-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.18-linux-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.18-windows-aarch64.zip",
+ "arch": "aarch64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-aarch64.zip"
+ }
+ ]
+ },
{
"version": "17.0.7",
"stable": true,
diff --git a/__tests__/data/sapmachine-release-classes.json b/__tests__/data/sapmachine-release-classes.json
new file mode 100644
index 000000000..79e88f6cd
--- /dev/null
+++ b/__tests__/data/sapmachine-release-classes.json
@@ -0,0 +1,73 @@
+{
+ "25": {
+ "lts": "false",
+ "updates": {
+ "25.0.2": {
+ "sapmachine-25.0.2": {
+ "release_url": "https://example.test/releases/25.0.2",
+ "ea": false,
+ "assets": {
+ "jdk": {
+ "linux-x64": {
+ "tar.gz": {
+ "name": "sapmachine-jdk-25.0.2_linux-x64_bin.tar.gz",
+ "checksum": "stable-boolean",
+ "url": "https://example.test/sapmachine-25.0.2-ga.tar.gz"
+ }
+ }
+ }
+ }
+ }
+ },
+ "25.0.1": {
+ "sapmachine-25.0.1": {
+ "release_url": "https://example.test/releases/25.0.1",
+ "ea": "false",
+ "assets": {
+ "jdk": {
+ "linux-x64": {
+ "tar.gz": {
+ "name": "sapmachine-jdk-25.0.1_linux-x64_bin.tar.gz",
+ "checksum": "stable-string",
+ "url": "https://example.test/sapmachine-25.0.1-ga.tar.gz"
+ }
+ }
+ }
+ }
+ }
+ },
+ "25": {
+ "sapmachine-25+11": {
+ "release_url": "https://example.test/releases/25+11",
+ "ea": true,
+ "assets": {
+ "jdk": {
+ "linux-x64": {
+ "tar.gz": {
+ "name": "sapmachine-jdk-25-ea.11_linux-x64_bin.tar.gz",
+ "checksum": "ea-boolean",
+ "url": "https://example.test/sapmachine-25-ea.11.tar.gz"
+ }
+ }
+ }
+ }
+ },
+ "sapmachine-25+10": {
+ "release_url": "https://example.test/releases/25+10",
+ "ea": "true",
+ "assets": {
+ "jdk": {
+ "linux-x64": {
+ "tar.gz": {
+ "name": "sapmachine-jdk-25-ea.10_linux-x64_bin.tar.gz",
+ "checksum": "ea-string",
+ "url": "https://example.test/sapmachine-25-ea.10.tar.gz"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/__tests__/data/sdkman-java-versions.csv b/__tests__/data/sdkman-java-versions.csv
new file mode 100644
index 000000000..edbdc265c
--- /dev/null
+++ b/__tests__/data/sdkman-java-versions.csv
@@ -0,0 +1,135 @@
+6.0.119-zulu, 6.0.119
+7.0.352-zulu, 7.0.352
+8.0.282-trava, 8.0.282
+8.0.432-albba, 8.0.432
+8.0.432-amzn, 8
+8.0.432-kona, 8.0.432
+8.0.432-librca, 8.0.432
+8.0.432-sem, 8.0.432
+8.0.432-tem, 8.0.432
+8.0.432-zulu, 8.0.432
+8.0.432.fx-librca, 8.0.432
+8.0.432.fx-zulu, 8.0.432
+8.0.442-amzn, 8
+8.0.442-librca, 8.0.442
+8.0.442-tem, 8.0.442
+8.0.442-zulu, 8.0.442
+8.0.442.fx-librca, 8.0.442
+8.0.442.fx-zulu, 8.0.442
+11.0.14.1-jbr, 11.0.14
+11.0.15-trava, 11.0.15
+11.0.25-albba, 11.0.25
+11.0.25-amzn, 11
+11.0.25-kona, 11.0.25
+11.0.25-librca, 11.0.25
+11.0.25-ms, 11.0.25
+11.0.25-sapmchn, 11.0.25
+11.0.25-sem, 11.0.25
+11.0.25-tem, 11.0.25
+11.0.25-zulu, 11.0.25
+11.0.25.fx-librca, 11.0.25
+11.0.25.fx-zulu, 11.0.25
+11.0.26-amzn, 11
+11.0.26-librca, 11.0.26
+11.0.26-ms, 11.0.26
+11.0.26-sapmchn, 11.0.26
+11.0.26-zulu, 11.0.26
+11.0.26.fx-librca, 11.0.26
+11.0.26.fx-zulu, 11.0.26
+17.0.12-graal, 17.0.12
+17.0.12-jbr, 17.0.12
+17.0.12-oracle, 17.0.12
+17.0.13-albba, 17.0.13
+17.0.13-amzn, 17
+17.0.13-kona, 17.0.13
+17.0.13-librca, 17.0.13
+17.0.13-ms, 17.0.13
+17.0.13-sapmchn, 17.0.13
+17.0.13-sem, 17.0.13
+17.0.13-tem, 17.0.13
+17.0.13-zulu, 17.0.13
+17.0.13.crac-librca, 17.0.13
+17.0.13.crac-zulu, 17.0.13
+17.0.13.fx-librca, 17.0.13
+17.0.13.fx-zulu, 17.0.13
+17.0.14-amzn, 17
+17.0.14-librca, 17.0.14
+17.0.14-ms, 17.0.14
+17.0.14-sapmchn, 17.0.14
+17.0.14-zulu, 17.0.14
+17.0.14.fx-librca, 17.0.14
+17.0.14.fx-zulu, 17.0.14
+17.0.9-graalce, 17.0.9
+21.0.2-graalce, 21.0.2
+21.0.2-open, 21.0.2
+21.0.5-amzn, 21
+21.0.5-graal, 21.0.5
+21.0.5-jbr, 21.0.5
+21.0.5-kona, 21.0.5
+21.0.5-librca, 21.0.5
+21.0.5-ms, 21.0.5
+21.0.5-oracle, 21.0.5
+21.0.5-sapmchn, 21.0.5
+21.0.5-sem, 21.0.5
+21.0.5-tem, 21.0.5
+21.0.5-zulu, 21.0.5
+21.0.5.crac-librca, 21.0.5
+21.0.5.crac-zulu, 21.0.5
+21.0.5.fx-librca, 21.0.5
+21.0.5.fx-zulu, 21.0.5
+21.0.6-amzn, 21
+21.0.6-graal, 21.0.6
+21.0.6-librca, 21.0.6
+21.0.6-ms, 21.0.6
+21.0.6-oracle, 21.0.6
+21.0.6-sapmchn, 21.0.6
+21.0.6-tem, 21.0.6
+21.0.6-zulu, 21.0.6
+21.0.6.fx-librca, 21.0.6
+21.0.6.fx-zulu, 21.0.6
+22.0.2-oracle, 22.0.2
+22.1.0.1.r11-gln, 22.1.0
+22.1.0.1.r17-gln, 22.1.0
+22.3.5.r11-nik, 22.3.5
+22.3.5.r17-mandrel, 22.3.5
+22.3.5.r17-nik, 22.3.5
+23-open, 23
+23.0.1-amzn, 23
+23.0.1-graal, 23.0.1
+23.0.1-graalce, 23.0.1
+23.0.1-librca, 23.0.1
+23.0.1-open, 23.0.1
+23.0.1-oracle, 23.0.1
+23.0.1-sapmchn, 23.0.1
+23.0.1-tem, 23.0.1
+23.0.1-zulu, 23.0.1
+23.0.1.crac-zulu, 23.0.1
+23.0.1.fx-librca, 23.0.1
+23.0.1.fx-zulu, 23.0.1
+23.0.2-amzn, 23
+23.0.2-graal, 23.0.2
+23.0.2-graalce, 23.0.2
+23.0.2-librca, 23.0.2
+23.0.2-oracle, 23.0.2
+23.0.2-sapmchn, 23.0.2
+23.0.2-tem, 23.0.2
+23.0.2-zulu, 23.0.2
+23.0.2.fx-librca, 23.0.2
+23.0.2.fx-zulu, 23.0.2
+23.0.6.fx-nik, 23.0.6
+23.0.6.r17-mandrel, 23.0.6
+23.0.6.r17-nik, 23.0.6
+23.1.5.fx-nik, 23.1.5
+23.1.5.r21-mandrel, 23.1.5
+23.1.5.r21-nik, 23.1.5
+24.0.2.r22-mandrel, 24.0.2
+24.ea.27-graal, 24.0.0
+24.ea.28-graal, 24.0.0
+24.ea.31-open, 24.0.0
+24.ea.32-open, 24.0.0
+24.1.1.r23-mandrel, 24.1.1
+24.1.1.r23-nik, 24.1.1
+25.ea.4-graal, 25.0.0
+25.ea.5-graal, 25.0.0
+25.ea.5-open, 25.0.0
+25.ea.6-open, 25.0.0
\ No newline at end of file
diff --git a/__tests__/data/temurin.json b/__tests__/data/temurin.json
index 7ce00d2c7..cec2c631a 100644
--- a/__tests__/data/temurin.json
+++ b/__tests__/data/temurin.json
@@ -15,7 +15,8 @@
"link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz.json",
"name": "OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz",
- "size": 205463525
+ "size": 205463525,
+ "signature_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-16.0.2+7_adopt",
@@ -44,7 +45,8 @@
"link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz.json",
"name": "OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz",
- "size": 206621395
+ "size": 206621395,
+ "signature_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-16.0.2+7_adopt",
@@ -73,7 +75,8 @@
"link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip",
"metadata_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip.json",
"name": "OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip",
- "size": 203448494
+ "size": 203448494,
+ "signature_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-16.0.2+7_adopt",
@@ -113,7 +116,8 @@
"link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz.json",
"name": "OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz",
- "size": 102954777
+ "size": 102954777,
+ "signature_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk8u302-b08",
@@ -142,7 +146,8 @@
"link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz.json",
"name": "OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz",
- "size": 107303398
+ "size": 107303398,
+ "signature_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk8u302-b08",
@@ -171,7 +176,8 @@
"link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip",
"metadata_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip.json",
"name": "OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip",
- "size": 104297671
+ "size": 104297671,
+ "signature_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk8u302-b08",
@@ -211,7 +217,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz",
- "size": 188909250
+ "size": 188909250,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-16-ge39bf269d60",
@@ -240,7 +247,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz",
- "size": 192952713
+ "size": 192952713,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-219-ge39bf269d60",
@@ -260,7 +268,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz",
- "size": 188816971
+ "size": 188816971,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-16-ge39bf269d60",
@@ -280,7 +289,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz",
- "size": 182299353
+ "size": 182299353,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-219-ge39bf269d60",
@@ -300,7 +310,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz",
- "size": 187674392
+ "size": 187674392,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-46-gea8d2c72e83",
@@ -320,7 +331,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz",
- "size": 179501342
+ "size": 179501342,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-21-ge39bf269d60",
@@ -340,7 +352,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz",
- "size": 192126971
+ "size": 192126971,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-219-ge39bf269d60",
@@ -360,7 +373,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz",
- "size": 192015878
+ "size": 192015878,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-21-ge39bf269d60",
@@ -389,7 +403,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz.json",
"name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz",
- "size": 192422068
+ "size": 192422068,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-219-ge39bf269d60",
@@ -418,7 +433,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip",
- "size": 188694175
+ "size": 188694175,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-219-ge39bf269d60",
@@ -447,7 +463,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip",
- "size": 184618115
+ "size": 184618115,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+33_adopt-219-ge39bf269d60",
@@ -489,7 +506,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz",
- "size": 192125161
+ "size": 192125161,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-242-gce1857dd7a1",
@@ -531,7 +549,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz",
- "size": 188911467
+ "size": 188911467,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-42-g4596b4e9d4e",
@@ -560,7 +579,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz",
- "size": 192950510
+ "size": 192950510,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e",
@@ -580,7 +600,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz",
- "size": 188815685
+ "size": 188815685,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-36-g4596b4e9d4e",
@@ -600,7 +621,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz",
- "size": 182307654
+ "size": 182307654,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e",
@@ -620,7 +642,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz",
- "size": 187698851
+ "size": 187698851,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-36-g4596b4e9d4e",
@@ -640,7 +663,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz",
- "size": 179501218
+ "size": 179501218,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-40-g4596b4e9d4e",
@@ -660,7 +684,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz",
- "size": 192124471
+ "size": 192124471,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e",
@@ -680,7 +705,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz",
- "size": 192015026
+ "size": 192015026,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-40-g4596b4e9d4e",
@@ -709,7 +735,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz",
- "size": 193003513
+ "size": 193003513,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e",
@@ -738,7 +765,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip",
- "size": 188694996
+ "size": 188694996,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e",
@@ -767,7 +795,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip",
- "size": 184626937
+ "size": 184626937,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e",
@@ -809,7 +838,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz",
- "size": 188891565
+ "size": 188891565,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "a342f28aaec",
@@ -829,7 +859,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz",
- "size": 188790907
+ "size": 188790907,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "a342f28aaec",
@@ -849,7 +880,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz",
- "size": 182276594
+ "size": 182276594,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-191-ga342f28aaec",
@@ -869,7 +901,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz",
- "size": 187678422
+ "size": 187678422,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-26-ga342f28aaec",
@@ -889,7 +922,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz",
- "size": 179475721
+ "size": 179475721,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-26-ga342f28aaec",
@@ -909,7 +943,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz",
- "size": 192104689
+ "size": 192104689,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-191-ga342f28aaec",
@@ -929,7 +964,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz",
- "size": 191982821
+ "size": 191982821,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "a342f28aaec",
@@ -958,7 +994,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip",
- "size": 188685330
+ "size": 188685330,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-191-ga342f28aaec",
@@ -987,7 +1024,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip",
- "size": 184607457
+ "size": 184607457,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-191-ga342f28aaec",
@@ -1029,7 +1067,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz",
- "size": 188896773
+ "size": 188896773,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-14-g20418a26958",
@@ -1058,7 +1097,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz",
- "size": 192948484
+ "size": 192948484,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-179-g20418a26958",
@@ -1078,7 +1118,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz",
- "size": 188791964
+ "size": 188791964,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-14-g20418a26958",
@@ -1098,7 +1139,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz",
- "size": 182281944
+ "size": 182281944,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-179-g20418a26958",
@@ -1118,7 +1160,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz",
- "size": 187650365
+ "size": 187650365,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-23-g20418a26958",
@@ -1138,7 +1181,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz",
- "size": 179483622
+ "size": 179483622,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-55-g20418a26958",
@@ -1158,7 +1202,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz",
- "size": 192108731
+ "size": 192108731,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-179-g20418a26958",
@@ -1178,7 +1223,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz",
- "size": 191985123
+ "size": 191985123,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-14-g20418a26958",
@@ -1207,7 +1253,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip",
- "size": 188688539
+ "size": 188688539,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-179-g20418a26958",
@@ -1236,7 +1283,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip",
- "size": 184612045
+ "size": 184612045,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+31_adopt-179-g20418a26958",
@@ -1278,7 +1326,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz",
- "size": 188899456
+ "size": 188899456,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "ce22197617d",
@@ -1307,7 +1356,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz",
- "size": 192953428
+ "size": 192953428,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-200-gce22197617d",
@@ -1327,7 +1377,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz",
- "size": 188792852
+ "size": 188792852,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-66-gce22197617d",
@@ -1347,7 +1398,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz",
- "size": 187678600
+ "size": 187678600,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "ce22197617d",
@@ -1367,7 +1419,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz",
- "size": 179480996
+ "size": 179480996,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "ce22197617d",
@@ -1387,7 +1440,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz",
- "size": 192105446
+ "size": 192105446,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-200-gce22197617d",
@@ -1407,7 +1461,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz",
- "size": 191986856
+ "size": 191986856,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "ce22197617d",
@@ -1436,7 +1491,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz.json",
"name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz",
- "size": 192995067
+ "size": 192995067,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-200-gce22197617d",
@@ -1465,7 +1521,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip",
- "size": 188686556
+ "size": 188686556,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-200-gce22197617d",
@@ -1494,7 +1551,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip",
- "size": 184620492
+ "size": 184620492,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-200-gce22197617d",
@@ -1536,7 +1594,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz",
- "size": 188896299
+ "size": 188896299,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003",
@@ -1565,7 +1624,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz",
- "size": 192941671
+ "size": 192941671,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003",
@@ -1585,7 +1645,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz",
- "size": 188838708
+ "size": 188838708,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-161-g3e7e5bc2003",
@@ -1605,7 +1666,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz",
- "size": 182274073
+ "size": 182274073,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-40-g3e7e5bc2003",
@@ -1625,7 +1687,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz",
- "size": 187666608
+ "size": 187666608,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-40-g3e7e5bc2003",
@@ -1645,7 +1708,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz",
- "size": 179472325
+ "size": 179472325,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-30-g3e7e5bc2003",
@@ -1665,7 +1729,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz",
- "size": 192098387
+ "size": 192098387,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003",
@@ -1685,7 +1750,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz",
- "size": 191983708
+ "size": 191983708,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003",
@@ -1714,7 +1780,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz.json",
"name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz",
- "size": 193004476
+ "size": 193004476,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003",
@@ -1743,7 +1810,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip",
- "size": 188681640
+ "size": 188681640,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003",
@@ -1772,7 +1840,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip",
- "size": 184605514
+ "size": 184605514,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003",
@@ -1823,7 +1892,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz",
- "size": 192962903
+ "size": 192962903,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-172-g06428c22b61",
@@ -1843,7 +1913,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz",
- "size": 188800217
+ "size": 188800217,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "06428c22b61",
@@ -1863,7 +1934,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz",
- "size": 187663978
+ "size": 187663978,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-78-g06428c22b61",
@@ -1883,7 +1955,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz",
- "size": 179496669
+ "size": 179496669,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-78-g06428c22b61",
@@ -1903,7 +1976,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz",
- "size": 192113242
+ "size": 192113242,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-172-g06428c22b61",
@@ -1923,7 +1997,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz",
- "size": 192021951
+ "size": 192021951,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-172-g06428c22b61",
@@ -1952,7 +2027,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz.json",
"name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz",
- "size": 193018554
+ "size": 193018554,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-172-g06428c22b61",
@@ -1981,7 +2057,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip",
- "size": 188702463
+ "size": 188702463,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-172-g06428c22b61",
@@ -2023,7 +2100,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz",
- "size": 188953178
+ "size": 188953178,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2052,7 +2130,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz",
- "size": 192957934
+ "size": 192957934,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2072,7 +2151,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz",
- "size": 188797466
+ "size": 188797466,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-43-g6d3debb5c12",
@@ -2092,7 +2172,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz",
- "size": 182292580
+ "size": 182292580,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2112,7 +2193,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz",
- "size": 187684930
+ "size": 187684930,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-64-g6d3debb5c12",
@@ -2132,7 +2214,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz",
- "size": 179484390
+ "size": 179484390,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-54-g6d3debb5c12",
@@ -2152,7 +2235,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz",
- "size": 192114561
+ "size": 192114561,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2172,7 +2256,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz",
- "size": 192014644
+ "size": 192014644,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2201,7 +2286,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz.json",
"name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz",
- "size": 192425033
+ "size": 192425033,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2230,7 +2316,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip",
- "size": 188697393
+ "size": 188697393,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2259,7 +2346,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip",
- "size": 184618232
+ "size": 184618232,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12",
@@ -2301,7 +2389,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz",
- "size": 188940191
+ "size": 188940191,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7",
@@ -2330,7 +2419,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz",
- "size": 192953718
+ "size": 192953718,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7",
@@ -2350,7 +2440,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz",
- "size": 188795343
+ "size": 188795343,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "0fe0d0825e7",
@@ -2370,7 +2461,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz",
- "size": 182285782
+ "size": 182285782,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "0fe0d0825e7",
@@ -2390,7 +2482,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz",
- "size": 187652430
+ "size": 187652430,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "0fe0d0825e7",
@@ -2410,7 +2503,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz",
- "size": 179489547
+ "size": 179489547,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "0fe0d0825e7",
@@ -2430,7 +2524,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz.json",
"name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz",
- "size": 192109453
+ "size": 192109453,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7",
@@ -2450,7 +2545,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz",
- "size": 192013559
+ "size": 192013559,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7",
@@ -2479,7 +2575,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz.json",
"name": "OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz",
- "size": 192419518
+ "size": 192419518,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7",
@@ -2508,7 +2605,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip.json",
"name": "OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip",
- "size": 188672489
+ "size": 188672489,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7",
@@ -2537,7 +2635,8 @@
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip",
"metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip.json",
"name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip",
- "size": 184626094
+ "size": 184626094,
+ "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip.sig"
},
"project": "jdk",
"scm_ref": "jdk-17+28_adopt-132-g23fbf51b850",
diff --git a/__tests__/data/zulu-linux.json b/__tests__/data/zulu-linux.json
index 1f2fa2716..c74487e2c 100644
--- a/__tests__/data/zulu-linux.json
+++ b/__tests__/data/zulu-linux.json
@@ -1,254 +1,686 @@
-[
+[
{
- "id": 10996,
- "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-linux.tar.gz",
+ "package_uuid": "test-uuid-10996",
"name": "zulu1.8.0_05-8.1.0.10-linux.tar.gz",
- "zulu_version": [8, 1, 0, 10],
- "jdk_version": [8, 0, 5, 13]
- },
- {
- "id": 10997,
- "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-linux.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-linux.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 8,
+ 1,
+ 0,
+ 10
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10997",
"name": "zulu1.8.0_11-8.2.0.1-linux.tar.gz",
- "zulu_version": [8, 2, 0, 1],
- "jdk_version": [8, 0, 11, 12]
- },
- {
- "id": 10346,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-linux.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 11
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 8,
+ 2,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10346",
"name": "zulu8.21.0.1-jdk8.0.131-linux_x64.tar.gz",
- "zulu_version": [8, 21, 0, 1],
- "jdk_version": [8, 0, 131, 11]
- },
- {
- "id": 10362,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 131
+ ],
+ "openjdk_build_number": 11,
+ "distro_version": [
+ 8,
+ 21,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10362",
"name": "zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
- "zulu_version": [8, 23, 0, 3],
- "jdk_version": [8, 0, 144, 1]
- },
- {
- "id": 10399,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 144
+ ],
+ "openjdk_build_number": 1,
+ "distro_version": [
+ 8,
+ 23,
+ 0,
+ 3
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10399",
"name": "zulu8.25.0.1-jdk8.0.152-linux_x64.tar.gz",
- "zulu_version": [8, 25, 0, 1],
- "jdk_version": [8, 0, 152, 16]
- },
- {
- "id": 11355,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 152
+ ],
+ "openjdk_build_number": 16,
+ "distro_version": [
+ 8,
+ 25,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11355",
"name": "zulu8.46.0.19-ca-jdk8.0.252-linux_x64.tar.gz",
- "zulu_version": [8, 46, 0, 19],
- "jdk_version": [8, 0, 252, 14]
- },
- {
- "id": 11481,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 252
+ ],
+ "openjdk_build_number": 14,
+ "distro_version": [
+ 8,
+ 46,
+ 0,
+ 19
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11481",
"name": "zulu8.48.0.47-ca-jdk8.0.262-linux_x64.tar.gz",
- "zulu_version": [8, 48, 0, 47],
- "jdk_version": [8, 0, 262, 17]
- },
- {
- "id": 11622,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 17,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 47
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11622",
"name": "zulu8.48.0.51-ca-jdk8.0.262-linux_x64.tar.gz",
- "zulu_version": [8, 48, 0, 51],
- "jdk_version": [8, 0, 262, 19]
- },
- {
- "id": 11535,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 19,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 51
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11535",
"name": "zulu8.48.0.49-ca-jdk8.0.262-linux_x64.tar.gz",
- "zulu_version": [8, 48, 0, 49],
- "jdk_version": [8, 0, 262, 18]
- },
- {
- "id": 12424,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 18,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 49
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12424",
"name": "zulu8.52.0.23-ca-jdk8.0.282-linux_x64.tar.gz",
- "zulu_version": [8, 52, 0, 23],
- "jdk_version": [8, 0, 282, 8]
- },
- {
- "id": 10383,
- "url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-linux_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 282
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 8,
+ 52,
+ 0,
+ 23
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10383",
"name": "zulu9.0.0.15-jdk9.0.0-linux_x64.tar.gz",
- "zulu_version": [9, 0, 0, 15],
- "jdk_version": [9, 0, 0, 0]
- },
- {
- "id": 10413,
- "url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-linux_x64.tar.gz",
+ "java_version": [
+ 9,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 0,
+ "distro_version": [
+ 9,
+ 0,
+ 0,
+ 15
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10413",
"name": "zulu9.0.1.3-jdk9.0.1-linux_x64.tar.gz",
- "zulu_version": [9, 0, 1, 3],
- "jdk_version": [9, 0, 1, 0]
- },
- {
- "id": 10503,
- "url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 9,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 0,
+ "distro_version": [
+ 9,
+ 0,
+ 1,
+ 3
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10503",
"name": "zulu10.2+3-jdk10.0.1-linux_x64.tar.gz",
- "zulu_version": [10, 2, 3, 0],
- "jdk_version": [10, 0, 1, 9]
- },
- {
- "id": 10541,
- "url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 10,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 10,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10541",
"name": "zulu10.3+5-jdk10.0.2-linux_x64.tar.gz",
- "zulu_version": [10, 3, 5, 0],
- "jdk_version": [10, 0, 2, 13]
- },
- {
- "id": 10576,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-linux_x64.tar.gz",
+ "java_version": [
+ 10,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 10,
+ 3,
+ 5,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10576",
"name": "zulu11.2.3-jdk11.0.1-linux_x64.tar.gz",
- "zulu_version": [11, 2, 3, 0],
- "jdk_version": [11, 0, 1, 13]
- },
- {
- "id": 10604,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 11,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10604",
"name": "zulu11.29.3-ca-jdk11.0.2-linux_x64.tar.gz",
- "zulu_version": [11, 29, 3, 0],
- "jdk_version": [11, 0, 2, 7]
- },
- {
- "id": 10687,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-linux_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 11,
+ 29,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10687",
"name": "zulu11.31.11-ca-jdk11.0.3-linux_x64.tar.gz",
- "zulu_version": [11, 31, 11, 0],
- "jdk_version": [11, 0, 3, 7]
- },
- {
- "id": 10856,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-linux_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 3
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 11,
+ 31,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10856",
"name": "zulu11.35.13-ca-jdk11.0.5-linux_x64.tar.gz",
- "zulu_version": [11, 35, 13, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 10933,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-linux_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 13,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10933",
"name": "zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz",
- "zulu_version": [11, 35, 15, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 10933,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 15,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10933",
"name": "zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz",
- "zulu_version": [11, 35, 11, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 12397,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-linux_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12397",
"name": "zulu11.45.27-ca-jdk11.0.10-linux_x64.tar.gz",
- "zulu_version": [11, 45, 27, 0],
- "jdk_version": [11, 0, 10, 9]
- },
- {
- "id": 10667,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-linux_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 10
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 11,
+ 45,
+ 27,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10667",
"name": "zulu12.1.3-ca-jdk12.0.0-linux_x64.tar.gz",
- "zulu_version": [12, 1, 3, 0],
- "jdk_version": [12, 0, 0, 33]
- },
- {
- "id": 10710,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-linux_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 33,
+ "distro_version": [
+ 12,
+ 1,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10710",
"name": "zulu12.2.3-ca-jdk12.0.1-linux_x64.tar.gz",
- "zulu_version": [12, 2, 3, 0],
- "jdk_version": [12, 0, 1, 12]
- },
- {
- "id": 10780,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 12,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10780",
"name": "zulu12.3.11-ca-jdk12.0.2-linux_x64.tar.gz",
- "zulu_version": [12, 3, 11, 0],
- "jdk_version": [12, 0, 2, 3]
- },
- {
- "id": 10846,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-linux_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 3,
+ "distro_version": [
+ 12,
+ 3,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10846",
"name": "zulu13.27.9-ca-jdk13.0.0-linux_x64.tar.gz",
- "zulu_version": [13, 27, 9, 0],
- "jdk_version": [13, 0, 0, 33]
- },
- {
- "id": 10888,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-linux_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 33,
+ "distro_version": [
+ 13,
+ 27,
+ 9,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10888",
"name": "zulu13.28.11-ca-jdk13.0.1-linux_x64.tar.gz",
- "zulu_version": [13, 28, 11, 0],
- "jdk_version": [13, 0, 1, 10]
- },
- {
- "id": 11073,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 13,
+ 28,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11073",
"name": "zulu13.29.9-ca-jdk13.0.2-linux_x64.tar.gz",
- "zulu_version": [13, 29, 9, 0],
- "jdk_version": [13, 0, 2, 6]
- },
- {
- "id": 12408,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-linux_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 6,
+ "distro_version": [
+ 13,
+ 29,
+ 9,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12408",
"name": "zulu13.37.21-ca-jdk13.0.6-linux_x64.tar.gz",
- "zulu_version": [13, 37, 21, 0],
- "jdk_version": [13, 0, 6, 5]
- },
- {
- "id": 11236,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-linux_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 6
+ ],
+ "openjdk_build_number": 5,
+ "distro_version": [
+ 13,
+ 37,
+ 21,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11236",
"name": "zulu14.27.1-ca-jdk14.0.0-linux_x64.tar.gz",
- "zulu_version": [14, 27, 1, 0],
- "jdk_version": [14, 0, 0, 36]
- },
- {
- "id": 11349,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-linux_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 36,
+ "distro_version": [
+ 14,
+ 27,
+ 1,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11349",
"name": "zulu14.28.21-ca-jdk14.0.1-linux_x64.tar.gz",
- "zulu_version": [14, 28, 21, 0],
- "jdk_version": [14, 0, 1, 8]
- },
- {
- "id": 11513,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 14,
+ 28,
+ 21,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11513",
"name": "zulu14.29.23-ca-jdk14.0.2-linux_x64.tar.gz",
- "zulu_version": [14, 29, 23, 0],
- "jdk_version": [14, 0, 2, 12]
- },
- {
- "id": 11780,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-linux_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 14,
+ 29,
+ 23,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11780",
"name": "zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz",
- "zulu_version": [15, 27, 17, 0],
- "jdk_version": [15, 0, 0, 36]
- },
- {
- "id": 11924,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 36,
+ "distro_version": [
+ 15,
+ 27,
+ 17,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11924",
"name": "zulu15.28.13-ca-jdk15.0.1-linux_x64.tar.gz",
- "zulu_version": [15, 28, 13, 0],
- "jdk_version": [15, 0, 1, 8]
- },
- {
- "id": 12101,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 15,
+ 28,
+ 13,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12101",
"name": "zulu15.28.51-ca-jdk15.0.1-linux_x64.tar.gz",
- "zulu_version": [15, 28, 51, 0],
- "jdk_version": [15, 0, 1, 9]
- },
- {
- "id": 12445,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-linux_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-linux_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 15,
+ 28,
+ 51,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12445",
"name": "zulu15.29.15-ca-jdk15.0.2-linux_x64.tar.gz",
- "zulu_version": [15, 29, 15, 0],
- "jdk_version": [15, 0, 2, 7]
- },
- {
- "id": 12447,
- "url": "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-linux_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 15,
+ 29,
+ 15,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12447",
"name": "zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz",
- "zulu_version": [21, 32, 17, 0],
- "jdk_version": [21, 0, 2, 6]
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz",
+ "java_version": [
+ 21,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 6,
+ "distro_version": [
+ 21,
+ 32,
+ 17,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
}
-]
\ No newline at end of file
+]
diff --git a/__tests__/data/zulu-releases-default.json b/__tests__/data/zulu-releases-default.json
index f23a87d43..16ed97772 100644
--- a/__tests__/data/zulu-releases-default.json
+++ b/__tests__/data/zulu-releases-default.json
@@ -1,247 +1,667 @@
[
{
- "id": 10996,
- "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-macosx.tar.gz",
+ "package_uuid": "test-uuid-10996",
"name": "zulu1.8.0_05-8.1.0.10-macosx.tar.gz",
- "zulu_version": [8, 1, 0, 10],
- "jdk_version": [8, 0, 5, 13]
- },
- {
- "id": 10997,
- "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-macosx.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-macosx.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 8,
+ 1,
+ 0,
+ 10
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10997",
"name": "zulu1.8.0_11-8.2.0.1-macosx.tar.gz",
- "zulu_version": [8, 2, 0, 1],
- "jdk_version": [8, 0, 11, 12]
- },
- {
- "id": 10346,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-macosx.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 11
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 8,
+ 2,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10346",
"name": "zulu8.21.0.1-jdk8.0.131-macosx_x64.tar.gz",
- "zulu_version": [8, 21, 0, 1],
- "jdk_version": [8, 0, 131, 11]
- },
- {
- "id": 10362,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 131
+ ],
+ "openjdk_build_number": 11,
+ "distro_version": [
+ 8,
+ 21,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10362",
"name": "zulu8.23.0.3-jdk8.0.144-macosx_x64.tar.gz",
- "zulu_version": [8, 23, 0, 3],
- "jdk_version": [8, 0, 144, 1]
- },
- {
- "id": 10399,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 144
+ ],
+ "openjdk_build_number": 1,
+ "distro_version": [
+ 8,
+ 23,
+ 0,
+ 3
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10399",
"name": "zulu8.25.0.1-jdk8.0.152-macosx_x64.tar.gz",
- "zulu_version": [8, 25, 0, 1],
- "jdk_version": [8, 0, 152, 16]
- },
- {
- "id": 11355,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 152
+ ],
+ "openjdk_build_number": 16,
+ "distro_version": [
+ 8,
+ 25,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11355",
"name": "zulu8.46.0.19-ca-jdk8.0.252-macosx_x64.tar.gz",
- "zulu_version": [8, 46, 0, 19],
- "jdk_version": [8, 0, 252, 14]
- },
- {
- "id": 11481,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 252
+ ],
+ "openjdk_build_number": 14,
+ "distro_version": [
+ 8,
+ 46,
+ 0,
+ 19
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11481",
"name": "zulu8.48.0.47-ca-jdk8.0.262-macosx_x64.tar.gz",
- "zulu_version": [8, 48, 0, 47],
- "jdk_version": [8, 0, 262, 17]
- },
- {
- "id": 11622,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 17,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 47
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11622",
"name": "zulu8.48.0.51-ca-jdk8.0.262-macosx_x64.tar.gz",
- "zulu_version": [8, 48, 0, 51],
- "jdk_version": [8, 0, 262, 19]
- },
- {
- "id": 11535,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 19,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 51
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11535",
"name": "zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz",
- "zulu_version": [8, 48, 0, 49],
- "jdk_version": [8, 0, 262, 18]
- },
- {
- "id": 12424,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 18,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 49
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12424",
"name": "zulu8.52.0.23-ca-jdk8.0.282-macosx_x64.tar.gz",
- "zulu_version": [8, 52, 0, 23],
- "jdk_version": [8, 0, 282, 8]
- },
- {
- "id": 10383,
- "url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-macosx_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 282
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 8,
+ 52,
+ 0,
+ 23
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10383",
"name": "zulu9.0.0.15-jdk9.0.0-macosx_x64.tar.gz",
- "zulu_version": [9, 0, 0, 15],
- "jdk_version": [9, 0, 0, 0]
- },
- {
- "id": 10413,
- "url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-macosx_x64.tar.gz",
+ "java_version": [
+ 9,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 0,
+ "distro_version": [
+ 9,
+ 0,
+ 0,
+ 15
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10413",
"name": "zulu9.0.1.3-jdk9.0.1-macosx_x64.tar.gz",
- "zulu_version": [9, 0, 1, 3],
- "jdk_version": [9, 0, 1, 0]
- },
- {
- "id": 10503,
- "url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 9,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 0,
+ "distro_version": [
+ 9,
+ 0,
+ 1,
+ 3
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10503",
"name": "zulu10.2+3-jdk10.0.1-macosx_x64.tar.gz",
- "zulu_version": [10, 2, 3, 0],
- "jdk_version": [10, 0, 1, 9]
- },
- {
- "id": 10541,
- "url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 10,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 10,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10541",
"name": "zulu10.3+5-jdk10.0.2-macosx_x64.tar.gz",
- "zulu_version": [10, 3, 5, 0],
- "jdk_version": [10, 0, 2, 13]
- },
- {
- "id": 10576,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-macosx_x64.tar.gz",
+ "java_version": [
+ 10,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 10,
+ 3,
+ 5,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10576",
"name": "zulu11.2.3-jdk11.0.1-macosx_x64.tar.gz",
- "zulu_version": [11, 2, 3, 0],
- "jdk_version": [11, 0, 1, 13]
- },
- {
- "id": 10604,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 11,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10604",
"name": "zulu11.29.3-ca-jdk11.0.2-macosx_x64.tar.gz",
- "zulu_version": [11, 29, 3, 0],
- "jdk_version": [11, 0, 2, 7]
- },
- {
- "id": 10687,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-macosx_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 11,
+ 29,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10687",
"name": "zulu11.31.11-ca-jdk11.0.3-macosx_x64.tar.gz",
- "zulu_version": [11, 31, 11, 0],
- "jdk_version": [11, 0, 3, 7]
- },
- {
- "id": 10856,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-macosx_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 3
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 11,
+ 31,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10856",
"name": "zulu11.35.13-ca-jdk11.0.5-macosx_x64.tar.gz",
- "zulu_version": [11, 35, 13, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 10933,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-macosx_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 13,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10933",
"name": "zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz",
- "zulu_version": [11, 35, 15, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 10933,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 15,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10933",
"name": "zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz",
- "zulu_version": [11, 35, 11, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 12397,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-macosx_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12397",
"name": "zulu11.45.27-ca-jdk11.0.10-macosx_x64.tar.gz",
- "zulu_version": [11, 45, 27, 0],
- "jdk_version": [11, 0, 10, 9]
- },
- {
- "id": 10667,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-macosx_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 10
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 11,
+ 45,
+ 27,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10667",
"name": "zulu12.1.3-ca-jdk12.0.0-macosx_x64.tar.gz",
- "zulu_version": [12, 1, 3, 0],
- "jdk_version": [12, 0, 0, 33]
- },
- {
- "id": 10710,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-macosx_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 33,
+ "distro_version": [
+ 12,
+ 1,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10710",
"name": "zulu12.2.3-ca-jdk12.0.1-macosx_x64.tar.gz",
- "zulu_version": [12, 2, 3, 0],
- "jdk_version": [12, 0, 1, 12]
- },
- {
- "id": 10780,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 12,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10780",
"name": "zulu12.3.11-ca-jdk12.0.2-macosx_x64.tar.gz",
- "zulu_version": [12, 3, 11, 0],
- "jdk_version": [12, 0, 2, 3]
- },
- {
- "id": 10846,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-macosx_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 3,
+ "distro_version": [
+ 12,
+ 3,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10846",
"name": "zulu13.27.9-ca-jdk13.0.0-macosx_x64.tar.gz",
- "zulu_version": [13, 27, 9, 0],
- "jdk_version": [13, 0, 0, 33]
- },
- {
- "id": 10888,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-macosx_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 33,
+ "distro_version": [
+ 13,
+ 27,
+ 9,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10888",
"name": "zulu13.28.11-ca-jdk13.0.1-macosx_x64.tar.gz",
- "zulu_version": [13, 28, 11, 0],
- "jdk_version": [13, 0, 1, 10]
- },
- {
- "id": 11073,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 13,
+ 28,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11073",
"name": "zulu13.29.9-ca-jdk13.0.2-macosx_x64.tar.gz",
- "zulu_version": [13, 29, 9, 0],
- "jdk_version": [13, 0, 2, 6]
- },
- {
- "id": 12408,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-macosx_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 6,
+ "distro_version": [
+ 13,
+ 29,
+ 9,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12408",
"name": "zulu13.37.21-ca-jdk13.0.6-macosx_x64.tar.gz",
- "zulu_version": [13, 37, 21, 0],
- "jdk_version": [13, 0, 6, 5]
- },
- {
- "id": 11236,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-macosx_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 6
+ ],
+ "openjdk_build_number": 5,
+ "distro_version": [
+ 13,
+ 37,
+ 21,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11236",
"name": "zulu14.27.1-ca-jdk14.0.0-macosx_x64.tar.gz",
- "zulu_version": [14, 27, 1, 0],
- "jdk_version": [14, 0, 0, 36]
- },
- {
- "id": 11349,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-macosx_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 36,
+ "distro_version": [
+ 14,
+ 27,
+ 1,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11349",
"name": "zulu14.28.21-ca-jdk14.0.1-macosx_x64.tar.gz",
- "zulu_version": [14, 28, 21, 0],
- "jdk_version": [14, 0, 1, 8]
- },
- {
- "id": 11513,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 14,
+ 28,
+ 21,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11513",
"name": "zulu14.29.23-ca-jdk14.0.2-macosx_x64.tar.gz",
- "zulu_version": [14, 29, 23, 0],
- "jdk_version": [14, 0, 2, 12]
- },
- {
- "id": 11780,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-macosx_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 14,
+ 29,
+ 23,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11780",
"name": "zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz",
- "zulu_version": [15, 27, 17, 0],
- "jdk_version": [15, 0, 0, 36]
- },
- {
- "id": 11924,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 36,
+ "distro_version": [
+ 15,
+ 27,
+ 17,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11924",
"name": "zulu15.28.13-ca-jdk15.0.1-macosx_x64.tar.gz",
- "zulu_version": [15, 28, 13, 0],
- "jdk_version": [15, 0, 1, 8]
- },
- {
- "id": 12101,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 15,
+ 28,
+ 13,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12101",
"name": "zulu15.28.51-ca-jdk15.0.1-macosx_x64.tar.gz",
- "zulu_version": [15, 28, 51, 0],
- "jdk_version": [15, 0, 1, 9]
- },
- {
- "id": 12445,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-macosx_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-macosx_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 15,
+ 28,
+ 51,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12445",
"name": "zulu15.29.15-ca-jdk15.0.2-macosx_x64.tar.gz",
- "zulu_version": [15, 29, 15, 0],
- "jdk_version": [15, 0, 2, 7]
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-macosx_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 15,
+ 29,
+ 15,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
}
]
diff --git a/__tests__/data/zulu-windows.json b/__tests__/data/zulu-windows.json
index e4ce99538..dcfb9462f 100644
--- a/__tests__/data/zulu-windows.json
+++ b/__tests__/data/zulu-windows.json
@@ -1,254 +1,686 @@
-[
+[
{
- "id": 10996,
- "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-windows.tar.gz",
+ "package_uuid": "test-uuid-10996",
"name": "zulu1.8.0_05-8.1.0.10-windows.tar.gz",
- "zulu_version": [8, 1, 0, 10],
- "jdk_version": [8, 0, 5, 13]
- },
- {
- "id": 10997,
- "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-windows.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-windows.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 8,
+ 1,
+ 0,
+ 10
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10997",
"name": "zulu1.8.0_11-8.2.0.1-windows.tar.gz",
- "zulu_version": [8, 2, 0, 1],
- "jdk_version": [8, 0, 11, 12]
- },
- {
- "id": 10346,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-windows.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 11
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 8,
+ 2,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10346",
"name": "zulu8.21.0.1-jdk8.0.131-windows_x64.tar.gz",
- "zulu_version": [8, 21, 0, 1],
- "jdk_version": [8, 0, 131, 11]
- },
- {
- "id": 10362,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 131
+ ],
+ "openjdk_build_number": 11,
+ "distro_version": [
+ 8,
+ 21,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10362",
"name": "zulu8.23.0.3-jdk8.0.144-windows_x64.tar.gz",
- "zulu_version": [8, 23, 0, 3],
- "jdk_version": [8, 0, 144, 1]
- },
- {
- "id": 10399,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 144
+ ],
+ "openjdk_build_number": 1,
+ "distro_version": [
+ 8,
+ 23,
+ 0,
+ 3
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10399",
"name": "zulu8.25.0.1-jdk8.0.152-windows_x64.tar.gz",
- "zulu_version": [8, 25, 0, 1],
- "jdk_version": [8, 0, 152, 16]
- },
- {
- "id": 11355,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 152
+ ],
+ "openjdk_build_number": 16,
+ "distro_version": [
+ 8,
+ 25,
+ 0,
+ 1
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11355",
"name": "zulu8.46.0.19-ca-jdk8.0.252-windows_x64.tar.gz",
- "zulu_version": [8, 46, 0, 19],
- "jdk_version": [8, 0, 252, 14]
- },
- {
- "id": 11481,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 252
+ ],
+ "openjdk_build_number": 14,
+ "distro_version": [
+ 8,
+ 46,
+ 0,
+ 19
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11481",
"name": "zulu8.48.0.47-ca-jdk8.0.262-windows_x64.tar.gz",
- "zulu_version": [8, 48, 0, 47],
- "jdk_version": [8, 0, 262, 17]
- },
- {
- "id": 11622,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 17,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 47
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11622",
"name": "zulu8.48.0.51-ca-jdk8.0.262-windows_x64.tar.gz",
- "zulu_version": [8, 48, 0, 51],
- "jdk_version": [8, 0, 262, 19]
- },
- {
- "id": 11535,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 19,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 51
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11535",
"name": "zulu8.48.0.49-ca-jdk8.0.262-windows_x64.tar.gz",
- "zulu_version": [8, 48, 0, 49],
- "jdk_version": [8, 0, 262, 18]
- },
- {
- "id": 12424,
- "url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 262
+ ],
+ "openjdk_build_number": 18,
+ "distro_version": [
+ 8,
+ 48,
+ 0,
+ 49
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12424",
"name": "zulu8.52.0.23-ca-jdk8.0.282-windows_x64.tar.gz",
- "zulu_version": [8, 52, 0, 23],
- "jdk_version": [8, 0, 282, 8]
- },
- {
- "id": 10383,
- "url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-windows_x64.tar.gz",
+ "java_version": [
+ 8,
+ 0,
+ 282
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 8,
+ 52,
+ 0,
+ 23
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10383",
"name": "zulu9.0.0.15-jdk9.0.0-windows_x64.tar.gz",
- "zulu_version": [9, 0, 0, 15],
- "jdk_version": [9, 0, 0, 0]
- },
- {
- "id": 10413,
- "url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-windows_x64.tar.gz",
+ "java_version": [
+ 9,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 0,
+ "distro_version": [
+ 9,
+ 0,
+ 0,
+ 15
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10413",
"name": "zulu9.0.1.3-jdk9.0.1-windows_x64.tar.gz",
- "zulu_version": [9, 0, 1, 3],
- "jdk_version": [9, 0, 1, 0]
- },
- {
- "id": 10503,
- "url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 9,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 0,
+ "distro_version": [
+ 9,
+ 0,
+ 1,
+ 3
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10503",
"name": "zulu10.2+3-jdk10.0.1-windows_x64.tar.gz",
- "zulu_version": [10, 2, 3, 0],
- "jdk_version": [10, 0, 1, 9]
- },
- {
- "id": 10541,
- "url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 10,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 10,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10541",
"name": "zulu10.3+5-jdk10.0.2-windows_x64.tar.gz",
- "zulu_version": [10, 3, 5, 0],
- "jdk_version": [10, 0, 2, 13]
- },
- {
- "id": 10576,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-windows_x64.tar.gz",
+ "java_version": [
+ 10,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 10,
+ 3,
+ 5,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10576",
"name": "zulu11.2.3-jdk11.0.1-windows_x64.tar.gz",
- "zulu_version": [11, 2, 3, 0],
- "jdk_version": [11, 0, 1, 13]
- },
- {
- "id": 10604,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 13,
+ "distro_version": [
+ 11,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10604",
"name": "zulu11.29.3-ca-jdk11.0.2-windows_x64.tar.gz",
- "zulu_version": [11, 29, 3, 0],
- "jdk_version": [11, 0, 2, 7]
- },
- {
- "id": 10687,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-windows_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 11,
+ 29,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10687",
"name": "zulu11.31.11-ca-jdk11.0.3-windows_x64.tar.gz",
- "zulu_version": [11, 31, 11, 0],
- "jdk_version": [11, 0, 3, 7]
- },
- {
- "id": 10856,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-windows_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 3
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 11,
+ 31,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10856",
"name": "zulu11.35.13-ca-jdk11.0.5-windows_x64.tar.gz",
- "zulu_version": [11, 35, 13, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 10933,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-windows_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 13,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10933",
"name": "zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz",
- "zulu_version": [11, 35, 15, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 10933,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 15,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10933",
"name": "zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz",
- "zulu_version": [11, 35, 11, 0],
- "jdk_version": [11, 0, 5, 10]
- },
- {
- "id": 12397,
- "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-windows_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 5
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 11,
+ 35,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12397",
"name": "zulu11.45.27-ca-jdk11.0.10-windows_x64.tar.gz",
- "zulu_version": [11, 45, 27, 0],
- "jdk_version": [11, 0, 10, 9]
- },
- {
- "id": 10667,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-windows_x64.tar.gz",
+ "java_version": [
+ 11,
+ 0,
+ 10
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 11,
+ 45,
+ 27,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10667",
"name": "zulu12.1.3-ca-jdk12.0.0-windows_x64.tar.gz",
- "zulu_version": [12, 1, 3, 0],
- "jdk_version": [12, 0, 0, 33]
- },
- {
- "id": 10710,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-windows_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 33,
+ "distro_version": [
+ 12,
+ 1,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10710",
"name": "zulu12.2.3-ca-jdk12.0.1-windows_x64.tar.gz",
- "zulu_version": [12, 2, 3, 0],
- "jdk_version": [12, 0, 1, 12]
- },
- {
- "id": 10780,
- "url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 12,
+ 2,
+ 3,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10780",
"name": "zulu12.3.11-ca-jdk12.0.2-windows_x64.tar.gz",
- "zulu_version": [12, 3, 11, 0],
- "jdk_version": [12, 0, 2, 3]
- },
- {
- "id": 10846,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-windows_x64.tar.gz",
+ "java_version": [
+ 12,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 3,
+ "distro_version": [
+ 12,
+ 3,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10846",
"name": "zulu13.27.9-ca-jdk13.0.0-windows_x64.tar.gz",
- "zulu_version": [13, 27, 9, 0],
- "jdk_version": [13, 0, 0, 33]
- },
- {
- "id": 10888,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-windows_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 33,
+ "distro_version": [
+ 13,
+ 27,
+ 9,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-10888",
"name": "zulu13.28.11-ca-jdk13.0.1-windows_x64.tar.gz",
- "zulu_version": [13, 28, 11, 0],
- "jdk_version": [13, 0, 1, 10]
- },
- {
- "id": 11073,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 10,
+ "distro_version": [
+ 13,
+ 28,
+ 11,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11073",
"name": "zulu13.29.9-ca-jdk13.0.2-windows_x64.tar.gz",
- "zulu_version": [13, 29, 9, 0],
- "jdk_version": [13, 0, 2, 6]
- },
- {
- "id": 12408,
- "url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-windows_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 6,
+ "distro_version": [
+ 13,
+ 29,
+ 9,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12408",
"name": "zulu13.37.21-ca-jdk13.0.6-windows_x64.tar.gz",
- "zulu_version": [13, 37, 21, 0],
- "jdk_version": [13, 0, 6, 5]
- },
- {
- "id": 11236,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-windows_x64.tar.gz",
+ "java_version": [
+ 13,
+ 0,
+ 6
+ ],
+ "openjdk_build_number": 5,
+ "distro_version": [
+ 13,
+ 37,
+ 21,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11236",
"name": "zulu14.27.1-ca-jdk14.0.0-windows_x64.tar.gz",
- "zulu_version": [14, 27, 1, 0],
- "jdk_version": [14, 0, 0, 36]
- },
- {
- "id": 11349,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-windows_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 36,
+ "distro_version": [
+ 14,
+ 27,
+ 1,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11349",
"name": "zulu14.28.21-ca-jdk14.0.1-windows_x64.tar.gz",
- "zulu_version": [14, 28, 21, 0],
- "jdk_version": [14, 0, 1, 8]
- },
- {
- "id": 11513,
- "url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 14,
+ 28,
+ 21,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11513",
"name": "zulu14.29.23-ca-jdk14.0.2-windows_x64.tar.gz",
- "zulu_version": [14, 29, 23, 0],
- "jdk_version": [14, 0, 2, 12]
- },
- {
- "id": 11780,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-windows_x64.tar.gz",
+ "java_version": [
+ 14,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 12,
+ "distro_version": [
+ 14,
+ 29,
+ 23,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11780",
"name": "zulu15.27.17-ca-jdk15.0.0-windows_x64.tar.gz",
- "zulu_version": [15, 27, 17, 0],
- "jdk_version": [15, 0, 0, 36]
- },
- {
- "id": 11924,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-windows_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 0
+ ],
+ "openjdk_build_number": 36,
+ "distro_version": [
+ 15,
+ 27,
+ 17,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-11924",
"name": "zulu15.28.13-ca-jdk15.0.1-windows_x64.tar.gz",
- "zulu_version": [15, 28, 13, 0],
- "jdk_version": [15, 0, 1, 8]
- },
- {
- "id": 12101,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 8,
+ "distro_version": [
+ 15,
+ 28,
+ 13,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12101",
"name": "zulu15.28.51-ca-jdk15.0.1-windows_x64.tar.gz",
- "zulu_version": [15, 28, 51, 0],
- "jdk_version": [15, 0, 1, 9]
- },
- {
- "id": 12445,
- "url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-windows_x64.tar.gz",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-windows_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 1
+ ],
+ "openjdk_build_number": 9,
+ "distro_version": [
+ 15,
+ 28,
+ 51,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12445",
"name": "zulu15.29.15-ca-jdk15.0.2-windows_x64.tar.gz",
- "zulu_version": [15, 29, 15, 0],
- "jdk_version": [15, 0, 2, 7]
- },
- {
- "id": 12446,
- "url": "https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip",
- "name": "zulu17.48.15-ca-jdk17.0.10-win_aarhc4.zip",
- "zulu_version": [17, 48, 15, 0],
- "jdk_version": [17, 0, 10, 7]
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-windows_x64.tar.gz",
+ "java_version": [
+ 15,
+ 0,
+ 2
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 15,
+ 29,
+ 15,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
+ },
+ {
+ "package_uuid": "test-uuid-12446",
+ "name": "zulu17.48.15-ca-jdk17.0.10-win_aarch64.zip",
+ "download_url": "https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip",
+ "java_version": [
+ 17,
+ 0,
+ 10
+ ],
+ "openjdk_build_number": 7,
+ "distro_version": [
+ 17,
+ 48,
+ 15,
+ 0
+ ],
+ "latest": false,
+ "availability_type": "ca"
}
-]
\ No newline at end of file
+]
diff --git a/__tests__/distributors/adopt-installer.test.ts b/__tests__/distributors/adopt-installer.test.ts
deleted file mode 100644
index 0b35c3d3e..000000000
--- a/__tests__/distributors/adopt-installer.test.ts
+++ /dev/null
@@ -1,299 +0,0 @@
-import {HttpClient} from '@actions/http-client';
-import {IAdoptAvailableVersions} from '../../src/distributions/adopt/models';
-import {
- AdoptDistribution,
- AdoptImplementation
-} from '../../src/distributions/adopt/installer';
-import {JavaInstallerOptions} from '../../src/distributions/base-models';
-
-import os from 'os';
-
-import manifestData from '../data/adopt.json';
-
-describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
-
- beforeEach(() => {
- spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
- spyHttpClient.mockReturnValue({
- statusCode: 200,
- headers: {},
- result: []
- });
- });
-
- afterEach(() => {
- jest.resetAllMocks();
- jest.clearAllMocks();
- jest.restoreAllMocks();
- });
-
- it.each([
- [
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot,
- 'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
- ],
- [
- {
- version: '11',
- architecture: 'x86',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot,
- 'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
- ],
- [
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jre',
- checkLatest: false
- },
- AdoptImplementation.Hotspot,
- 'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
- ],
- [
- {
- version: '11-ea',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot,
- 'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=hotspot&page_size=20&page=0'
- ],
- [
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.OpenJ9,
- 'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
- ],
- [
- {
- version: '11',
- architecture: 'x86',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.OpenJ9,
- 'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
- ],
- [
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jre',
- checkLatest: false
- },
- AdoptImplementation.OpenJ9,
- 'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
- ],
- [
- {
- version: '11-ea',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.OpenJ9,
- 'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=openj9&page_size=20&page=0'
- ]
- ])(
- 'build correct url for %s',
- async (
- installerOptions: JavaInstallerOptions,
- impl: AdoptImplementation,
- expectedParameters
- ) => {
- const distribution = new AdoptDistribution(installerOptions, impl);
- const baseUrl =
- 'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D';
- const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
- distribution['getPlatformOption'] = () => 'mac';
-
- await distribution['getAvailableVersions']();
-
- expect(spyHttpClient.mock.calls).toHaveLength(1);
- expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl);
- }
- );
-
- it('load available versions', async () => {
- spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
- spyHttpClient
- .mockReturnValueOnce({
- statusCode: 200,
- headers: {},
- result: manifestData as any
- })
- .mockReturnValueOnce({
- statusCode: 200,
- headers: {},
- result: manifestData as any
- })
- .mockReturnValueOnce({
- statusCode: 200,
- headers: {},
- result: []
- });
-
- const distribution = new AdoptDistribution(
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot
- );
- const availableVersions = await distribution['getAvailableVersions']();
- expect(availableVersions).not.toBeNull();
- expect(availableVersions.length).toBe(manifestData.length * 2);
- });
-
- it.each([
- [AdoptImplementation.Hotspot, 'jdk', 'Java_Adopt_jdk'],
- [AdoptImplementation.Hotspot, 'jre', 'Java_Adopt_jre'],
- [AdoptImplementation.OpenJ9, 'jdk', 'Java_Adopt-OpenJ9_jdk'],
- [AdoptImplementation.OpenJ9, 'jre', 'Java_Adopt-OpenJ9_jre']
- ])(
- 'find right toolchain folder',
- (impl: AdoptImplementation, packageType: string, expected: string) => {
- const distribution = new AdoptDistribution(
- {
- version: '11',
- architecture: 'x64',
- packageType: packageType,
- checkLatest: false
- },
- impl
- );
-
- // @ts-ignore - because it is protected
- expect(distribution.toolcacheFolderName).toBe(expected);
- }
- );
-
- it.each([
- ['amd64', 'x64'],
- ['arm64', 'aarch64']
- ])(
- 'defaults to os.arch(): %s mapped to distro arch: %s',
- async (osArch: string, distroArch: string) => {
- jest
- .spyOn(os, 'arch')
- .mockReturnValue(osArch as ReturnType);
-
- const installerOptions: JavaInstallerOptions = {
- version: '17',
- architecture: '', // to get default value
- packageType: 'jdk',
- checkLatest: false
- };
-
- const expectedParameters = `os=mac&architecture=${distroArch}&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0`;
-
- const distribution = new AdoptDistribution(
- installerOptions,
- AdoptImplementation.Hotspot
- );
- const baseUrl =
- 'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D';
- const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
- distribution['getPlatformOption'] = () => 'mac';
-
- await distribution['getAvailableVersions']();
-
- expect(spyHttpClient.mock.calls).toHaveLength(1);
- expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl);
- }
- );
-});
-
-describe('findPackageForDownload', () => {
- it.each([
- ['9', '9.0.7+10'],
- ['15', '15.0.2+7'],
- ['15.0', '15.0.2+7'],
- ['15.0.2', '15.0.2+7'],
- ['15.0.1', '15.0.1+9.1'],
- ['11.x', '11.0.10+9'],
- ['x', '15.0.2+7'],
- ['12', '12.0.2+10.3'], // make sure that '12.0.2+10.1', '12.0.2+10.3', '12.0.2+10.2' are sorted correctly
- ['12.0.2+10.1', '12.0.2+10.1'],
- ['15.0.1+9', '15.0.1+9'],
- ['15.0.1+9.1', '15.0.1+9.1']
- ])('version is resolved correctly %s -> %s', async (input, expected) => {
- const distribution = new AdoptDistribution(
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot
- );
- distribution['getAvailableVersions'] = async () => manifestData as any;
- const resolvedVersion = await distribution['findPackageForDownload'](input);
- expect(resolvedVersion.version).toBe(expected);
- });
-
- it('version is found but binaries list is empty', async () => {
- const distribution = new AdoptDistribution(
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot
- );
- distribution['getAvailableVersions'] = async () => manifestData as any;
- await expect(
- distribution['findPackageForDownload']('9.0.8')
- ).rejects.toThrow(/Could not find satisfied version for SemVer */);
- });
-
- it('version is not found', async () => {
- const distribution = new AdoptDistribution(
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot
- );
- distribution['getAvailableVersions'] = async () => manifestData as any;
- await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
- );
- });
-
- it('version list is empty', async () => {
- const distribution = new AdoptDistribution(
- {
- version: '11',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- },
- AdoptImplementation.Hotspot
- );
- distribution['getAvailableVersions'] = async () => [];
- await expect(distribution['findPackageForDownload']('11')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
- );
- });
-});
diff --git a/__tests__/distributors/base-installer.test.ts b/__tests__/distributors/base-installer.test.ts
index 08a95828c..825d792a3 100644
--- a/__tests__/distributors/base-installer.test.ts
+++ b/__tests__/distributors/base-installer.test.ts
@@ -1,19 +1,110 @@
-import * as tc from '@actions/tool-cache';
-import * as core from '@actions/core';
-import * as util from '../../src/util';
-
-import path from 'path';
-import * as semver from 'semver';
-
-import {JavaBase} from '../../src/distributions/base-installer';
import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import type {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
-} from '../../src/distributions/base-models';
+} from '../../src/distributions/base-models.js';
+
+import path from 'path';
+import * as semver from 'semver';
+import fs from 'fs';
+import {createHash} from 'crypto';
+import {HttpClient} from '@actions/http-client';
import os from 'os';
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+jest.unstable_mockModule('@actions/tool-cache', () => ({
+ find: jest.fn(),
+ findAllVersions: jest.fn(),
+ downloadTool: jest.fn(),
+ extractZip: jest.fn(),
+ extractTar: jest.fn(),
+ extract7z: jest.fn(),
+ extractXar: jest.fn(),
+ cacheDir: jest.fn(),
+ cacheFile: jest.fn(),
+ getManifestFromRepo: jest.fn(),
+ findFromManifest: jest.fn(),
+ evaluateVersions: jest.fn(),
+ HTTPError: class HTTPError extends Error {
+ httpStatusCode: number;
+ constructor(statusCode: number) {
+ super(`HTTP Error: ${statusCode}`);
+ this.httpStatusCode = statusCode;
+ }
+ }
+}));
+
+jest.unstable_mockModule('../../src/jdk-cache.js', () => ({
+ getJdkVerificationIdentity: jest.fn((verified: boolean, key?: string) =>
+ verified ? (key ? 'verified:custom' : 'verified:bundled') : 'unverified'
+ ),
+ registerJdk: jest.fn(),
+ restoreJdk: jest.fn()
+}));
+
+jest.unstable_mockModule('../../src/jdk-resolution-cache.js', () => ({
+ registerJdkResolution: jest.fn(),
+ restoreJdkResolution: jest.fn()
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ extractJdkFile: jest.fn(),
+ getDownloadArchiveExtension: jest.fn(),
+ getToolcachePath: jest.fn(),
+ isJobStatusSuccess: jest.fn(),
+ renameWinArchive: jest.fn(),
+ isVersionSatisfies: real_util_module.isVersionSatisfies,
+ getTempDir: real_util_module.getTempDir
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const tc = await import('@actions/tool-cache');
+const util = await import('../../src/util.js');
+const jdkCache = await import('../../src/jdk-cache.js');
+const jdkResolutionCache = await import('../../src/jdk-resolution-cache.js');
+const {getJavaPlatformIdentity} =
+ await import('../../src/distributions/platform-types.js');
+const {JavaBase} = await import('../../src/distributions/base-installer.js');
+
class EmptyJavaBase extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
super('Empty', installerOptions);
@@ -38,7 +129,7 @@ class EmptyJavaBase extends JavaBase {
): Promise {
const availableVersion = '11.0.9';
if (!semver.satisfies(availableVersion, range)) {
- throw new Error('Available version not found');
+ throw this.createVersionNotFoundError(range, [availableVersion]);
}
return {
@@ -46,6 +137,58 @@ class EmptyJavaBase extends JavaBase {
url: `some/random_url/java/${availableVersion}`
};
}
+
+ public downloadRelease(javaRelease: JavaDownloadRelease): Promise {
+ return this.downloadAndVerify(javaRelease);
+ }
+
+ public fetchChecksumForTest(
+ checksumUrl: string,
+ algorithm: 'sha256' | 'sha512' | ('sha256' | 'sha512')[]
+ ) {
+ return this.fetchChecksum(checksumUrl, algorithm);
+ }
+}
+
+class FloatingJavaBase extends JavaBase {
+ static actualVersion = '21.0.8+9';
+ static checksum: string | undefined = 'artifact-one';
+ static fingerprint: string | undefined = undefined;
+
+ constructor(installerOptions: JavaInstallerOptions) {
+ super('Floating', installerOptions);
+ }
+
+ protected async downloadTool(): Promise {
+ return {
+ version: FloatingJavaBase.actualVersion,
+ path: path.join(
+ 'toolcache',
+ this.toolcacheFolderName,
+ FloatingJavaBase.actualVersion.replace('+', '-'),
+ this.architecture
+ )
+ };
+ }
+
+ protected async findPackageForDownload(): Promise {
+ return {
+ version: '21',
+ url: 'https://example.com/java/21/latest/jdk-21.tar.gz',
+ checksum: FloatingJavaBase.checksum
+ ? {
+ algorithm: 'sha256',
+ value: FloatingJavaBase.checksum
+ }
+ : undefined,
+ floating: true,
+ fingerprint: FloatingJavaBase.fingerprint
+ };
+ }
+
+ protected requiresRemoteResolution(): boolean {
+ return true;
+ }
}
describe('findInToolcache', () => {
@@ -53,12 +196,12 @@ describe('findInToolcache', () => {
const javaPath = path.join('Java_Empty_jdk', actualJavaVersion, 'x64');
let mockJavaBase: EmptyJavaBase;
- let spyGetToolcachePath: jest.SpyInstance;
- let spyTcFindAllVersions: jest.SpyInstance;
+ let spyGetToolcachePath: any;
+ let spyTcFindAllVersions: any;
beforeEach(() => {
- spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
- spyTcFindAllVersions = jest.spyOn(tc, 'findAllVersions');
+ spyGetToolcachePath = util.getToolcachePath as jest.Mock;
+ spyTcFindAllVersions = tc.findAllVersions as jest.Mock;
});
afterEach(() => {
@@ -241,16 +384,21 @@ describe('setupJava', () => {
let mockJavaBase: EmptyJavaBase;
- let spyGetToolcachePath: jest.SpyInstance;
- let spyTcFindAllVersions: jest.SpyInstance;
- let spyCoreDebug: jest.SpyInstance;
- let spyCoreInfo: jest.SpyInstance;
- let spyCoreExportVariable: jest.SpyInstance;
- let spyCoreAddPath: jest.SpyInstance;
- let spyCoreSetOutput: jest.SpyInstance;
+ let spyGetToolcachePath: any;
+ let spyTcFindAllVersions: any;
+ let spyCoreDebug: any;
+ let spyCoreInfo: any;
+ let spyCoreExportVariable: any;
+ let spyCoreAddPath: any;
+ let spyCoreSetOutput: any;
+ let spyCoreError: any;
beforeEach(() => {
- spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
+ (jdkCache.getJdkVerificationIdentity as jest.Mock).mockImplementation(
+ (verified: boolean, key?: string) =>
+ verified ? (key ? 'verified:custom' : 'verified:bundled') : 'unverified'
+ );
+ spyGetToolcachePath = util.getToolcachePath as jest.Mock;
spyGetToolcachePath.mockImplementation(
(toolname: string, javaVersion: string, architecture: string) => {
const semverVersion = new semver.Range(javaVersion);
@@ -268,26 +416,31 @@ describe('setupJava', () => {
}
);
- spyTcFindAllVersions = jest.spyOn(tc, 'findAllVersions');
+ spyTcFindAllVersions = tc.findAllVersions as jest.Mock;
spyTcFindAllVersions.mockReturnValue([installedJavaVersion]);
// Spy on core methods
- spyCoreDebug = jest.spyOn(core, 'debug');
+ spyCoreDebug = core.debug as jest.Mock;
spyCoreDebug.mockImplementation(() => undefined);
- spyCoreInfo = jest.spyOn(core, 'info');
+ spyCoreInfo = core.info as jest.Mock;
spyCoreInfo.mockImplementation(() => undefined);
- spyCoreAddPath = jest.spyOn(core, 'addPath');
+ spyCoreAddPath = core.addPath as jest.Mock;
spyCoreAddPath.mockImplementation(() => undefined);
- spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
+ spyCoreExportVariable = core.exportVariable as jest.Mock;
spyCoreExportVariable.mockImplementation(() => undefined);
- spyCoreSetOutput = jest.spyOn(core, 'setOutput');
+ spyCoreSetOutput = core.setOutput as jest.Mock;
spyCoreSetOutput.mockImplementation(() => undefined);
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => undefined);
+
jest.spyOn(os, 'arch').mockReturnValue('x86' as ReturnType);
+ FloatingJavaBase.fingerprint = undefined;
});
afterEach(() => {
@@ -344,6 +497,438 @@ describe('setupJava', () => {
expect(spyCoreInfo).not.toHaveBeenCalledWith('Trying to download...');
});
+ it('should resolve the latest version from remote when java-version is "latest", even if a version is cached', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: 'latest',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: actualJavaVersion,
+ path: javaPathInstalled
+ });
+
+ // `latest` must bypass the tool-cache short-circuit and always resolve remotely
+ expect(spyCoreInfo).toHaveBeenCalledWith(
+ 'Trying to resolve the latest version from remote'
+ );
+ expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...');
+ expect(spyCoreInfo).not.toHaveBeenCalledWith(
+ `Resolved Java ${installedJavaVersion} from tool-cache`
+ );
+ });
+
+ describe('floating tool-cache reuse', () => {
+ let toolCacheRoot: string;
+
+ const installVersion = (toolcacheVersion: string): string => {
+ const architecturePath = path.join(
+ toolCacheRoot,
+ 'Java_Floating_jdk',
+ toolcacheVersion,
+ 'x64'
+ );
+ fs.mkdirSync(architecturePath, {recursive: true});
+ fs.writeFileSync(`${architecturePath}.complete`, '');
+ return architecturePath;
+ };
+
+ beforeEach(() => {
+ toolCacheRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-java-tc-'));
+ process.env['RUNNER_TOOL_CACHE'] = toolCacheRoot;
+ FloatingJavaBase.actualVersion = '21.0.8+9';
+ FloatingJavaBase.checksum = 'artifact-one';
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
+ spyTcFindAllVersions.mockReturnValue([]);
+ });
+
+ afterEach(() => {
+ fs.rmSync(toolCacheRoot, {recursive: true, force: true});
+ delete process.env['RUNNER_TOOL_CACHE'];
+ });
+
+ const createDistribution = (forceDownload = false) =>
+ new FloatingJavaBase({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true,
+ forceDownload
+ });
+
+ it('reuses a tool-cache installation once the resolution cache identifies the floating version', async () => {
+ const installedPath = installVersion('21.0.8-9');
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
+ release: {version: '21.0.8+9'}
+ });
+ const distribution = createDistribution();
+ const downloadTool = jest.spyOn(distribution as any, 'downloadTool');
+
+ await expect(distribution.setupJava()).resolves.toEqual({
+ version: '21.0.8+9',
+ path: installedPath
+ });
+
+ // The artifact behind the mutable URL is already installed, so neither a
+ // download nor a cache round-trip is needed.
+ expect(downloadTool).not.toHaveBeenCalled();
+ expect(jdkCache.restoreJdk).not.toHaveBeenCalled();
+ });
+
+ it('ignores a tool-cache installation of a version the resolution cache did not vouch for', async () => {
+ installVersion('21.0.7-6');
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
+ release: {version: '21.0.8+9'}
+ });
+ const distribution = createDistribution();
+ const downloadTool = jest.spyOn(distribution as any, 'downloadTool');
+
+ await distribution.setupJava();
+
+ expect(downloadTool).toHaveBeenCalled();
+ });
+
+ it('never reuses the tool-cache for a floating artifact the resolution cache cannot identify', async () => {
+ installVersion('21.0.8-9');
+ spyTcFindAllVersions.mockReturnValue(['21.0.8-9']);
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue(
+ undefined
+ );
+ const distribution = createDistribution();
+ const downloadTool = jest.spyOn(distribution as any, 'downloadTool');
+
+ await distribution.setupJava();
+
+ // Nothing ties the installed bytes to what the URL serves right now.
+ expect(downloadTool).toHaveBeenCalled();
+ });
+
+ it('still downloads a resolution-cache-identified version when force-download is set', async () => {
+ installVersion('21.0.8-9');
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
+ release: {version: '21.0.8+9'}
+ });
+ const distribution = createDistribution(true);
+ const downloadTool = jest.spyOn(distribution as any, 'downloadTool');
+
+ await distribution.setupJava();
+
+ expect(downloadTool).toHaveBeenCalled();
+ });
+ });
+
+ it('uses the concrete versions of two different floating artifacts under the same major', async () => {
+ spyTcFindAllVersions.mockReturnValue(['21.0.8-9']);
+ spyGetToolcachePath.mockImplementation(
+ (_toolname: string, version: string, architecture: string) =>
+ path.join('toolcache', 'Java_Floating_jdk', version, architecture)
+ );
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue(
+ undefined
+ );
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
+
+ FloatingJavaBase.actualVersion = '21.0.8+9';
+ FloatingJavaBase.checksum = 'artifact-one';
+ const first = new FloatingJavaBase({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true
+ });
+ await expect(first.setupJava()).resolves.toEqual({
+ version: '21.0.8+9',
+ path: path.join('toolcache', 'Java_Floating_jdk', '21.0.8-9', 'x64')
+ });
+
+ FloatingJavaBase.actualVersion = '21.0.9+7';
+ FloatingJavaBase.checksum = 'artifact-two';
+ const second = new FloatingJavaBase({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true
+ });
+ await expect(second.setupJava()).resolves.toEqual({
+ version: '21.0.9+7',
+ path: path.join('toolcache', 'Java_Floating_jdk', '21.0.9-7', 'x64')
+ });
+
+ expect(spyCoreSetOutput).toHaveBeenNthCalledWith(3, 'version', '21.0.8+9');
+ expect(spyCoreSetOutput).toHaveBeenNthCalledWith(6, 'version', '21.0.9+7');
+ expect(jdkCache.registerJdk).toHaveBeenNthCalledWith(
+ 1,
+ expect.objectContaining({
+ version: '21.0.8+9',
+ source: 'sha256:artifact-one'
+ })
+ );
+ expect(jdkCache.registerJdk).toHaveBeenNthCalledWith(
+ 2,
+ expect.objectContaining({
+ version: '21.0.9+7',
+ source: 'sha256:artifact-two'
+ })
+ );
+ expect(jdkResolutionCache.registerJdkResolution).toHaveBeenNthCalledWith(
+ 2,
+ expect.objectContaining({source: 'sha256:artifact-two'}),
+ expect.objectContaining({version: '21.0.9+7', floating: true})
+ );
+ });
+
+ it('does not trust a matching tool-cache version for a floating artifact', async () => {
+ spyTcFindAllVersions.mockReturnValue(['21.0.8-9']);
+ spyGetToolcachePath.mockReturnValue(
+ path.join('toolcache', 'Java_Floating_jdk', '21.0.8-9', 'x64')
+ );
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
+ release: {
+ version: '21.0.8+9',
+ url: 'https://example.com/java/21/latest/jdk-21.tar.gz',
+ checksum: {algorithm: 'sha256', value: 'artifact-republished'},
+ floating: true
+ },
+ fresh: true
+ });
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
+ FloatingJavaBase.actualVersion = '21.0.8+9';
+ FloatingJavaBase.checksum = 'artifact-republished';
+ const distribution = new FloatingJavaBase({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true
+ });
+ const downloadTool = jest.spyOn(distribution as any, 'downloadTool');
+
+ await distribution.setupJava();
+
+ expect(jdkCache.restoreJdk).toHaveBeenCalled();
+ expect(downloadTool).toHaveBeenCalled();
+ });
+
+ it('does not cache a floating artifact with no way to identify its bytes', async () => {
+ spyTcFindAllVersions.mockReturnValue(['21.0.8-9']);
+ spyGetToolcachePath.mockReturnValue(
+ path.join('toolcache', 'Java_Floating_jdk', '21.0.8-9', 'x64')
+ );
+ FloatingJavaBase.actualVersion = '21.0.8+9';
+ FloatingJavaBase.checksum = undefined;
+ FloatingJavaBase.fingerprint = undefined;
+ const distribution = new FloatingJavaBase({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true
+ });
+
+ await distribution.setupJava();
+
+ expect(jdkResolutionCache.restoreJdkResolution).not.toHaveBeenCalled();
+ expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
+ expect(jdkCache.restoreJdk).not.toHaveBeenCalled();
+ expect(jdkCache.registerJdk).not.toHaveBeenCalled();
+ });
+
+ it('caches a checksum-less floating artifact identified by its response fingerprint', async () => {
+ spyTcFindAllVersions.mockReturnValue([]);
+ spyGetToolcachePath.mockReturnValue(
+ path.join('toolcache', 'Java_Floating_jdk', '21.0.8-9', 'x64')
+ );
+ FloatingJavaBase.actualVersion = '21.0.8+9';
+ FloatingJavaBase.checksum = undefined;
+ FloatingJavaBase.fingerprint = 'etag:"artifact-one"';
+ const distribution = new FloatingJavaBase({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true
+ });
+
+ await distribution.setupJava();
+
+ // The fingerprint changes when the vendor republishes, so it is a safe
+ // identity even though no checksum is available.
+ expect(jdkResolutionCache.registerJdkResolution).toHaveBeenCalledWith(
+ expect.objectContaining({source: 'etag:"artifact-one"'}),
+ expect.objectContaining({version: '21.0.8+9'})
+ );
+ expect(jdkCache.registerJdk).toHaveBeenCalledWith(
+ expect.objectContaining({source: 'etag:"artifact-one"'})
+ );
+ });
+
+ it('separates the cache identities of two builds served by the same floating URL', async () => {
+ const sources: string[] = [];
+ (jdkCache.registerJdk as jest.Mock).mockImplementation((entry: any) => {
+ sources.push(entry.source);
+ });
+ spyTcFindAllVersions.mockReturnValue([]);
+ spyGetToolcachePath.mockReturnValue(
+ path.join('toolcache', 'Java_Floating_jdk', '21.0.8-9', 'x64')
+ );
+ FloatingJavaBase.actualVersion = '21.0.8+9';
+ FloatingJavaBase.checksum = undefined;
+
+ for (const fingerprint of ['etag:"before"', 'etag:"after"']) {
+ FloatingJavaBase.fingerprint = fingerprint;
+ await new FloatingJavaBase({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true
+ }).setupJava();
+ }
+
+ expect(sources).toEqual(['etag:"before"', 'etag:"after"']);
+ });
+
+ it('should download java when force-download is enabled, even if the version is cached', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: actualJavaVersion,
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ forceDownload: true,
+ cacheJdk: true
+ });
+
+ const findInToolcache = jest.fn(() => ({
+ version: actualJavaVersion,
+ path: javaPathInstalled
+ }));
+ mockJavaBase['findInToolcache'] = findInToolcache;
+
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: actualJavaVersion,
+ path: javaPathInstalled
+ });
+
+ expect(findInToolcache).not.toHaveBeenCalled();
+ expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...');
+ expect(spyCoreInfo).toHaveBeenCalledWith(
+ `Java ${actualJavaVersion} was downloaded`
+ );
+ expect(spyCoreInfo).not.toHaveBeenCalledWith(
+ `Resolved Java ${actualJavaVersion} from tool-cache`
+ );
+ expect(jdkCache.restoreJdk).not.toHaveBeenCalled();
+ expect(jdkCache.registerJdk).toHaveBeenCalledWith(
+ expect.objectContaining({
+ version: actualJavaVersion,
+ verification: 'unverified'
+ })
+ );
+ });
+
+ it.each([
+ [false, false, false, false],
+ [false, true, true, true],
+ [true, false, false, false],
+ [true, true, false, true]
+ ])(
+ 'handles force-download=%s and cache-jdk=%s',
+ async (forceDownload, cacheJdkEnabled, restores, registers) => {
+ mockJavaBase = new EmptyJavaBase({
+ version: actualJavaVersion,
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: true,
+ forceDownload,
+ cacheJdk: cacheJdkEnabled
+ });
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
+
+ await mockJavaBase.setupJava();
+
+ expect(jdkCache.restoreJdk).toHaveBeenCalledTimes(restores ? 1 : 0);
+ expect(jdkCache.registerJdk).toHaveBeenCalledTimes(registers ? 1 : 0);
+ }
+ );
+
+ it('restores the exact resolved JDK before downloading', async () => {
+ const toolCachePath = path.join('toolcache');
+ jest.replaceProperty(process, 'env', {
+ ...process.env,
+ RUNNER_TOOL_CACHE: toolCachePath
+ });
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: true,
+ cacheJdk: true
+ });
+ const downloadTool = jest.spyOn(mockJavaBase as any, 'downloadTool');
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(true);
+ jest
+ .spyOn(mockJavaBase as any, 'getRestoredJdkPath')
+ .mockReturnValue(javaPathInstalled);
+
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: actualJavaVersion,
+ path: javaPathInstalled
+ });
+
+ expect(jdkCache.restoreJdk).toHaveBeenCalledWith({
+ distribution: 'Empty',
+ packageType: 'jdk',
+ architecture: 'x86',
+ version: actualJavaVersion,
+ source: `some/random_url/java/${actualJavaVersion}`,
+ verification: 'unverified',
+ path: path.join(toolCachePath, 'Java_Empty_jdk', actualJavaVersion)
+ });
+ expect(downloadTool).not.toHaveBeenCalled();
+ expect(spyCoreInfo).not.toHaveBeenCalledWith('Trying to download...');
+ // A restored entry is already stored under its key; it must not be
+ // re-registered for a post-job save.
+ expect(jdkCache.registerJdk).not.toHaveBeenCalled();
+ });
+
+ it('registers the downloaded JDK identity after a JDK cache miss', async () => {
+ const toolCachePath = path.join('toolcache');
+ jest.replaceProperty(process, 'env', {
+ ...process.env,
+ RUNNER_TOOL_CACHE: toolCachePath
+ });
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: true,
+ cacheJdk: true
+ });
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
+
+ await mockJavaBase.setupJava();
+
+ const expectedIdentity = {
+ distribution: 'Empty',
+ packageType: 'jdk',
+ architecture: 'x86',
+ version: actualJavaVersion,
+ source: `some/random_url/java/${actualJavaVersion}`,
+ verification: 'unverified',
+ path: path.join(toolCachePath, 'Java_Empty_jdk', actualJavaVersion)
+ };
+ expect(jdkCache.restoreJdk).toHaveBeenCalledWith(expectedIdentity);
+ // Registration happens after the installation exists, so the post-job save
+ // can detect a later step replacing it.
+ expect(jdkCache.registerJdk).toHaveBeenCalledWith(expectedIdentity);
+ expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...');
+ });
+
it.each([
[
{
@@ -459,6 +1044,49 @@ describe('setupJava', () => {
}
);
+ it('should fail when verify-signature is enabled for unsupported distributions', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true
+ });
+
+ await expect(mockJavaBase.setupJava()).rejects.toThrow(
+ "Input 'verify-signature' is not supported for distribution 'Empty'."
+ );
+ expect(spyTcFindAllVersions).not.toHaveBeenCalled();
+ expect(spyCoreAddPath).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).not.toHaveBeenCalled();
+ expect(spyCoreSetOutput).not.toHaveBeenCalled();
+ });
+
+ it('should not repeat version resolution when downloadTool fails', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ forceDownload: true
+ });
+ const findPackageForDownload = jest.fn(async () => ({
+ version: '11.0.9',
+ url: 'https://example.com/jdk.tar.gz'
+ }));
+ const downloadError = new Error('download failed');
+ const downloadTool = jest.fn(async () => {
+ throw downloadError;
+ });
+ mockJavaBase['findPackageForDownload'] = findPackageForDownload;
+ mockJavaBase['downloadTool'] = downloadTool;
+
+ await expect(mockJavaBase.setupJava()).rejects.toBe(downloadError);
+
+ expect(findPackageForDownload).toHaveBeenCalledTimes(1);
+ expect(downloadTool).toHaveBeenCalledTimes(1);
+ });
+
it.each([
[
{
@@ -530,30 +1158,604 @@ describe('setupJava', () => {
checkLatest: false
}
]
- ])(
- 'should throw an error for Available version not found for %s',
- async input => {
- mockJavaBase = new EmptyJavaBase(input);
+ ])('should throw an error for version not found for %s', async input => {
+ mockJavaBase = new EmptyJavaBase(input);
+ await expect(mockJavaBase.setupJava()).rejects.toThrow(
+ `No matching version found for SemVer '${input.version}'`
+ );
+ expect(spyTcFindAllVersions).toHaveBeenCalled();
+ expect(spyCoreAddPath).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).not.toHaveBeenCalled();
+ expect(spyCoreSetOutput).not.toHaveBeenCalled();
+ });
+
+ it('should not set JAVA_HOME and PATH when setDefault is false', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ setDefault: false
+ });
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: installedJavaVersion,
+ path: javaPath
+ });
+ expect(spyCoreExportVariable).not.toHaveBeenCalledWith(
+ 'JAVA_HOME',
+ expect.anything()
+ );
+ expect(spyCoreAddPath).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'JAVA_HOME_11_X86',
+ javaPath
+ );
+ expect(spyCoreSetOutput).toHaveBeenCalledWith(
+ 'version',
+ installedJavaVersion
+ );
+ expect(spyCoreSetOutput).toHaveBeenCalledWith('path', javaPath);
+ expect(spyCoreSetOutput).toHaveBeenCalledWith('distribution', 'Empty');
+ expect(spyCoreInfo).toHaveBeenCalledWith(
+ `Installing Java ${installedJavaVersion} (not setting as default)`
+ );
+ });
+
+ it('should set JAVA_HOME and PATH when setDefault is true', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ setDefault: true
+ });
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: installedJavaVersion,
+ path: javaPath
+ });
+ expect(spyCoreExportVariable).toHaveBeenCalledWith('JAVA_HOME', javaPath);
+ expect(spyCoreAddPath).toHaveBeenCalledWith(path.join(javaPath, 'bin'));
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'JAVA_HOME_11_X86',
+ javaPath
+ );
+ expect(spyCoreInfo).toHaveBeenCalledWith(
+ `Setting Java ${installedJavaVersion} as the default`
+ );
+ });
+
+ it('should default to setting as default when setDefault is not specified', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: installedJavaVersion,
+ path: javaPath
+ });
+ expect(spyCoreExportVariable).toHaveBeenCalledWith('JAVA_HOME', javaPath);
+ expect(spyCoreAddPath).toHaveBeenCalledWith(path.join(javaPath, 'bin'));
+ expect(spyCoreInfo).toHaveBeenCalledWith(
+ `Setting Java ${installedJavaVersion} as the default`
+ );
+ });
+
+ it('should download and not set default when setDefault is false', async () => {
+ mockJavaBase = new EmptyJavaBase({
+ version: '11',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ setDefault: false
+ });
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: '11.0.9',
+ path: path.join('toolcache', 'Java_Empty_jdk', '11.0.9', 'x64')
+ });
+ expect(spyCoreExportVariable).not.toHaveBeenCalledWith(
+ 'JAVA_HOME',
+ expect.anything()
+ );
+ expect(spyCoreAddPath).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'JAVA_HOME_11_X64',
+ path.join('toolcache', 'Java_Empty_jdk', '11.0.9', 'x64')
+ );
+ expect(spyCoreSetOutput).toHaveBeenCalledWith('version', '11.0.9');
+ expect(spyCoreSetOutput).toHaveBeenCalledWith(
+ 'path',
+ path.join('toolcache', 'Java_Empty_jdk', '11.0.9', 'x64')
+ );
+ expect(spyCoreInfo).toHaveBeenCalledWith(
+ 'Installing Java 11.0.9 (not setting as default)'
+ );
+ });
+
+ describe('resolution cache', () => {
+ // 11.0.9 is not in the mocked tool-cache, so the tool-cache short-circuit
+ // misses and the release has to be resolved, exactly as it does for every
+ // distribution that is not preinstalled on hosted runners.
+ const options: JavaInstallerOptions = {
+ version: '11.0.9',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ cacheJdk: true
+ };
+ const cachedRelease = {
+ version: '11.0.9',
+ url: 'https://example.com/java/11.0.9'
+ };
+
+ const expectedRequest = {
+ distribution: 'Empty',
+ packageType: 'jdk',
+ platform: getJavaPlatformIdentity(),
+ architecture: 'x86',
+ versionSpec: '11.0.9',
+ stable: true
+ };
+
+ beforeEach(() => {
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue(
+ undefined
+ );
+ });
+
+ it('skips the metadata API on a fresh cached resolution', async () => {
+ mockJavaBase = new EmptyJavaBase(options);
+ const findPackageForDownload = jest.spyOn(
+ mockJavaBase as any,
+ 'findPackageForDownload'
+ );
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
+ release: cachedRelease,
+ fresh: true
+ });
+
+ await mockJavaBase.setupJava();
+
+ expect(jdkResolutionCache.restoreJdkResolution).toHaveBeenCalledWith(
+ expectedRequest
+ );
+ expect(findPackageForDownload).not.toHaveBeenCalled();
+ expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
+ expect(spyCoreInfo).toHaveBeenCalledWith(
+ 'Resolved Empty 11.0.9 from the resolution cache'
+ );
+ });
+
+ it('re-resolves and records the release on a miss', async () => {
+ mockJavaBase = new EmptyJavaBase(options);
+
+ await mockJavaBase.setupJava();
+
+ expect(jdkResolutionCache.registerJdkResolution).toHaveBeenCalledWith(
+ expectedRequest,
+ {version: '11.0.9', url: 'some/random_url/java/11.0.9'}
+ );
+ });
+
+ it('re-resolves when the cached resolution is stale', async () => {
+ mockJavaBase = new EmptyJavaBase(options);
+ const findPackageForDownload = jest.spyOn(
+ mockJavaBase as any,
+ 'findPackageForDownload'
+ );
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
+ release: cachedRelease,
+ fresh: false
+ });
+
+ await mockJavaBase.setupJava();
+
+ expect(findPackageForDownload).toHaveBeenCalled();
+ expect(jdkResolutionCache.registerJdkResolution).toHaveBeenCalled();
+ });
+
+ it('falls back to a stale resolution when the metadata API fails', async () => {
+ mockJavaBase = new EmptyJavaBase(options);
+ const downloadTool = jest
+ .spyOn(mockJavaBase as any, 'downloadTool')
+ .mockResolvedValue({version: '11.0.9', path: javaPathInstalled});
+ jest
+ .spyOn(mockJavaBase as any, 'findPackageForDownload')
+ .mockRejectedValue(new Error('503 Service Unavailable'));
+ (jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
+ release: cachedRelease,
+ fresh: false
+ });
+
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: '11.0.9',
+ path: javaPathInstalled
+ });
+
+ expect(downloadTool).toHaveBeenCalledWith(cachedRelease);
+ expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
+ expect(core.warning).toHaveBeenCalledWith(
+ expect.stringContaining('falling back to the cached resolution')
+ );
+ });
+
+ it('fails when the metadata API fails and nothing was cached', async () => {
+ mockJavaBase = new EmptyJavaBase(options);
+ jest
+ .spyOn(mockJavaBase as any, 'findPackageForDownload')
+ .mockRejectedValue(new Error('503 Service Unavailable'));
+
await expect(mockJavaBase.setupJava()).rejects.toThrow(
- 'Available version not found'
+ '503 Service Unavailable'
+ );
+ });
+
+ it('records the concrete version for a checksum-bound floating release', async () => {
+ mockJavaBase = new EmptyJavaBase(options);
+ jest
+ .spyOn(mockJavaBase as any, 'findPackageForDownload')
+ .mockResolvedValue({
+ version: '11.0.9',
+ url: 'https://example.com/java/11/latest/jdk-11.tar.gz',
+ checksum: {algorithm: 'sha256', value: 'abc'},
+ floating: true
+ });
+
+ await mockJavaBase.setupJava();
+
+ expect(jdkResolutionCache.registerJdkResolution).toHaveBeenCalledWith(
+ {
+ distribution: 'Empty',
+ packageType: 'jdk',
+ platform: getJavaPlatformIdentity(),
+ architecture: 'x86',
+ versionSpec: '11.0.9',
+ stable: true,
+ source: 'sha256:abc'
+ },
+ {
+ version: '11.0.9',
+ url: 'https://example.com/java/11/latest/jdk-11.tar.gz',
+ checksum: {algorithm: 'sha256', value: 'abc'},
+ floating: true
+ }
+ );
+ });
+
+ it.each([
+ ['cache-jdk is disabled', {cacheJdk: false}],
+ ['check-latest is enabled', {checkLatest: true}],
+ ['force-download is enabled', {forceDownload: true}],
+ ['java-version is "latest"', {version: 'latest'}]
+ ])('is bypassed when %s', async (_name, overrides) => {
+ mockJavaBase = new EmptyJavaBase({...options, ...overrides});
+
+ await mockJavaBase.setupJava();
+
+ expect(jdkResolutionCache.restoreJdkResolution).not.toHaveBeenCalled();
+ expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
+ });
+ });
+});
+
+describe('downloadAndVerify', () => {
+ const options: JavaInstallerOptions = {
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ };
+ let temporaryDirectory: string;
+ let archivePath: string;
+
+ beforeEach(async () => {
+ temporaryDirectory = await fs.promises.mkdtemp(
+ path.join(os.tmpdir(), 'setup-java-base-')
+ );
+ archivePath = path.join(temporaryDirectory, 'archive');
+ await fs.promises.writeFile(archivePath, 'downloaded archive');
+ (tc.downloadTool as jest.Mock).mockResolvedValue(archivePath);
+ });
+
+ afterEach(async () => {
+ await fs.promises.rm(temporaryDirectory, {recursive: true, force: true});
+ jest.resetAllMocks();
+ });
+
+ it('returns a download after successful verification', async () => {
+ const distribution = new EmptyJavaBase(options);
+ const result = await distribution.downloadRelease({
+ version: '21.0.8',
+ url: 'https://vendor.example/jdk.tar.gz',
+ checksum: {
+ algorithm: 'sha256',
+ value: createHash('sha256').update('downloaded archive').digest('hex')
+ }
+ });
+
+ expect(result).toBe(archivePath);
+ expect(fs.existsSync(archivePath)).toBe(true);
+ expect(core.debug).toHaveBeenCalledWith(
+ 'Verified sha256 checksum for Empty version 21.0.8.'
+ );
+ });
+
+ it('removes the download after verification failure', async () => {
+ const distribution = new EmptyJavaBase(options);
+
+ await expect(
+ distribution.downloadRelease({
+ version: '21.0.8',
+ url: 'https://vendor.example/jdk.tar.gz?token=secret',
+ checksum: {algorithm: 'sha256', value: 'a'.repeat(64)}
+ })
+ ).rejects.toThrow('Checksum verification failed for Empty version 21.0.8');
+
+ expect(fs.existsSync(archivePath)).toBe(false);
+ });
+
+ it('preserves the verification error when removing the download fails', async () => {
+ const distribution = new EmptyJavaBase(options);
+ const cleanupError = new Error('cleanup failed');
+ jest.spyOn(fs.promises, 'rm').mockRejectedValueOnce(cleanupError);
+
+ const result = distribution.downloadRelease({
+ version: '21.0.8',
+ url: 'https://vendor.example/jdk.tar.gz',
+ checksum: {algorithm: 'sha256', value: 'a'.repeat(64)}
+ });
+
+ await expect(result).rejects.toMatchObject({
+ message: expect.stringContaining(
+ 'Failed to remove the downloaded archive after verification failure: cleanup failed'
+ ),
+ cause: expect.objectContaining({
+ message: expect.stringContaining(
+ 'Checksum verification failed for Empty version 21.0.8'
+ )
+ })
+ });
+ });
+
+ it('logs when authoritative checksum metadata is unavailable', async () => {
+ const distribution = new EmptyJavaBase(options);
+
+ await expect(
+ distribution.downloadRelease({
+ version: '21.0.8',
+ url: 'https://vendor.example/jdk.tar.gz'
+ })
+ ).resolves.toBe(archivePath);
+
+ expect(core.debug).toHaveBeenCalledWith(
+ 'No authoritative checksum is available for Empty version 21.0.8; skipping checksum verification.'
+ );
+ });
+
+ it.each([undefined, '', ' '])(
+ 'skips verification when the vendor digest is %p',
+ async value => {
+ const distribution = new EmptyJavaBase(options);
+
+ await expect(
+ distribution.downloadRelease({
+ version: '21.0.8',
+ url: 'https://vendor.example/jdk.tar.gz',
+ checksum: {
+ algorithm: 'sha256',
+ value
+ } as JavaDownloadRelease['checksum']
+ })
+ ).resolves.toBe(archivePath);
+
+ expect(core.debug).toHaveBeenCalledWith(
+ 'No authoritative checksum is available for Empty version 21.0.8; skipping checksum verification.'
);
- expect(spyTcFindAllVersions).toHaveBeenCalled();
- expect(spyCoreAddPath).not.toHaveBeenCalled();
- expect(spyCoreExportVariable).not.toHaveBeenCalled();
- expect(spyCoreSetOutput).not.toHaveBeenCalled();
}
);
});
+describe('fetchChecksum', () => {
+ const options: JavaInstallerOptions = {
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ };
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ function mockGet(statusCode: number, body: string) {
+ return jest.spyOn(HttpClient.prototype, 'get').mockResolvedValue({
+ message: {statusCode},
+ readBody: async () => body
+ } as any);
+ }
+
+ it('parses a bare hex digest', async () => {
+ const digest = 'a'.repeat(64);
+ const spy = mockGet(200, digest);
+ const distribution = new EmptyJavaBase(options);
+
+ const checksum = await distribution.fetchChecksumForTest(
+ 'https://vendor.example/jdk.tar.gz.sha256',
+ 'sha256'
+ );
+
+ expect(spy).toHaveBeenCalledWith(
+ 'https://vendor.example/jdk.tar.gz.sha256'
+ );
+ expect(checksum).toEqual({
+ algorithm: 'sha256',
+ value: digest,
+ source: 'https://vendor.example/jdk.tar.gz.sha256'
+ });
+ });
+
+ it('parses only the first token of a GNU-style checksum file', async () => {
+ const digest = 'b'.repeat(128);
+ mockGet(200, `${digest} jbrsdk-21.0.3-linux-x64-b465.3.tar.gz\n`);
+ const distribution = new EmptyJavaBase(options);
+
+ const checksum = await distribution.fetchChecksumForTest(
+ 'https://vendor.example/jdk.tar.gz.checksum',
+ 'sha512'
+ );
+
+ expect(checksum).toEqual({
+ algorithm: 'sha512',
+ value: digest,
+ source: 'https://vendor.example/jdk.tar.gz.checksum'
+ });
+ });
+
+ it('trims surrounding whitespace and newlines', async () => {
+ const digest = 'c'.repeat(64);
+ mockGet(200, `\n ${digest} \n`);
+ const distribution = new EmptyJavaBase(options);
+
+ const checksum = await distribution.fetchChecksumForTest(
+ 'https://vendor.example/jdk.tar.gz.sha256',
+ 'sha256'
+ );
+
+ expect(checksum.value).toBe(digest);
+ });
+
+ it('skips verification when the sibling checksum is not published', async () => {
+ mockGet(404, 'Not Found');
+ const distribution = new EmptyJavaBase(options);
+
+ await expect(
+ distribution.fetchChecksumForTest(
+ 'https://vendor.example/jdk.tar.gz.sha256',
+ 'sha256'
+ )
+ ).resolves.toBeUndefined();
+ expect(core.debug).toHaveBeenCalledWith(
+ 'No authoritative sha256 checksum is available for Empty from https://vendor.example/jdk.tar.gz.sha256; skipping checksum verification.'
+ );
+ });
+
+ it('surfaces unexpected HTTP failures without query parameters', async () => {
+ mockGet(500, 'Server Error');
+ const distribution = new EmptyJavaBase(options);
+
+ await expect(
+ distribution.fetchChecksumForTest(
+ 'https://vendor.example/jdk.tar.gz.sha256?token=secret',
+ 'sha256'
+ )
+ ).rejects.toThrow(
+ 'Failed to fetch the authoritative sha256 checksum for Empty from https://vendor.example/jdk.tar.gz.sha256 (HTTP 500).'
+ );
+ });
+
+ it('rejects an empty successful checksum response', async () => {
+ mockGet(200, ' \n');
+ const distribution = new EmptyJavaBase(options);
+
+ await expect(
+ distribution.fetchChecksumForTest(
+ 'https://vendor.example/jdk.tar.gz.sha256',
+ 'sha256'
+ )
+ ).rejects.toThrow(
+ 'Received an empty authoritative sha256 checksum for Empty from https://vendor.example/jdk.tar.gz.sha256.'
+ );
+ });
+
+ describe('with a list of candidate algorithms', () => {
+ it('infers sha512 when the digest is 128 hex characters', async () => {
+ const digest = 'd'.repeat(128);
+ mockGet(200, `${digest} jbrsdk.tar.gz\n`);
+ const distribution = new EmptyJavaBase(options);
+
+ const checksum = await distribution.fetchChecksumForTest(
+ 'https://vendor.example/jbrsdk.tar.gz.checksum',
+ ['sha512', 'sha256']
+ );
+
+ expect(checksum).toEqual({
+ algorithm: 'sha512',
+ value: digest,
+ source: 'https://vendor.example/jbrsdk.tar.gz.checksum'
+ });
+ });
+
+ it('infers sha256 when the digest is 64 hex characters, even though sha512 was preferred', async () => {
+ // Reproduces older JetBrains JBR builds (e.g. JBR 11), which publish a
+ // SHA-256 digest at the generic `.checksum` sibling instead of SHA-512.
+ const digest = 'e'.repeat(64);
+ mockGet(200, `${digest} jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz\n`);
+ const distribution = new EmptyJavaBase(options);
+
+ const checksum = await distribution.fetchChecksumForTest(
+ 'https://vendor.example/jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz.checksum',
+ ['sha512', 'sha256']
+ );
+
+ expect(checksum).toEqual({
+ algorithm: 'sha256',
+ value: digest,
+ source:
+ 'https://vendor.example/jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz.checksum'
+ });
+ });
+
+ it('falls back to the first candidate algorithm when the digest length matches none of them', async () => {
+ const digest = 'f'.repeat(40); // e.g. sha1, not supported
+ mockGet(200, `${digest} jbrsdk.tar.gz\n`);
+ const distribution = new EmptyJavaBase(options);
+
+ const checksum = await distribution.fetchChecksumForTest(
+ 'https://vendor.example/jbrsdk.tar.gz.checksum',
+ ['sha512', 'sha256']
+ );
+
+ // No candidate algorithm matches, so the first-listed one is kept;
+ // downstream verification will reject it as malformed.
+ expect(checksum.algorithm).toBe('sha512');
+ expect(checksum.value).toBe(digest);
+ });
+
+ it('reports the checksum as unavailable using a combined algorithm label on 404', async () => {
+ mockGet(404, 'Not Found');
+ const distribution = new EmptyJavaBase(options);
+
+ await expect(
+ distribution.fetchChecksumForTest(
+ 'https://vendor.example/jbrsdk.tar.gz.checksum',
+ ['sha512', 'sha256']
+ )
+ ).resolves.toBeUndefined();
+ expect(core.debug).toHaveBeenCalledWith(
+ 'No authoritative sha512 or sha256 checksum is available for Empty from https://vendor.example/jbrsdk.tar.gz.checksum; skipping checksum verification.'
+ );
+ });
+ });
+});
+
describe('normalizeVersion', () => {
const DummyJavaBase = JavaBase as any;
it.each([
- ['11', {version: '11', stable: true}],
- ['11.0', {version: '11.0', stable: true}],
- ['11.0.10', {version: '11.0.10', stable: true}],
- ['11-ea', {version: '11', stable: false}],
- ['11.0.2-ea', {version: '11.0.2', stable: false}]
+ ['11', {version: '11', stable: true, latest: false}],
+ ['11.0', {version: '11.0', stable: true, latest: false}],
+ ['11.0.10', {version: '11.0.10', stable: true, latest: false}],
+ ['11-ea', {version: '11', stable: false, latest: false}],
+ ['11.0.2-ea', {version: '11.0.2', stable: false, latest: false}],
+ ['18.0.1.1', {version: '18.0.1+1', stable: true, latest: false}],
+ ['11.0.9.1', {version: '11.0.9+1', stable: true, latest: false}],
+ ['12.0.2.1.0', {version: '12.0.2+1.0', stable: true, latest: false}],
+ ['18.0.1.1-ea', {version: '18.0.1+1', stable: false, latest: false}],
+ ['latest', {version: 'x', stable: true, latest: true}],
+ ['LATEST', {version: 'x', stable: true, latest: true}],
+ [' Latest ', {version: 'x', stable: true, latest: true}]
])('normalizeVersion from %s to %s', (input, expected) => {
expect(DummyJavaBase.prototype.normalizeVersion.call(null, input)).toEqual(
expected
@@ -568,6 +1770,108 @@ describe('normalizeVersion', () => {
`The string '${version}' is not valid SemVer notation for a Java version. Please check README file for code snippets and more detailed information`
);
});
+
+ it.each(['latest-ea', 'latest.1', 'LATEST-EA', ' latest-ea '])(
+ 'normalizeVersion should throw a targeted error for latest combined with a qualifier (%s)',
+ version => {
+ expect(
+ DummyJavaBase.prototype.normalizeVersion.bind(null, version)
+ ).toThrow(
+ `The 'latest' alias resolves stable (GA) releases only and cannot be combined with '-ea' or other qualifiers (received '${version}'). Use 'latest' on its own, or specify a concrete version.`
+ );
+ }
+ );
+});
+
+describe('createVersionNotFoundError', () => {
+ it('should include all required fields in error message without available versions', () => {
+ const mockJavaBase = new EmptyJavaBase({
+ version: '17.0.5',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const error = (mockJavaBase as any).createVersionNotFoundError('17.0.5');
+
+ expect(error.message).toContain(
+ "No matching version found for SemVer '17.0.5'"
+ );
+ expect(error.message).toContain('Distribution: Empty');
+ expect(error.message).toContain('Package type: jdk');
+ expect(error.message).toContain('Architecture: x64');
+ });
+
+ it('should include available versions when provided', () => {
+ const mockJavaBase = new EmptyJavaBase({
+ version: '17.0.5',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const availableVersions = ['11.0.1', '11.0.2', '17.0.1', '17.0.2'];
+ const error = (mockJavaBase as any).createVersionNotFoundError(
+ '17.0.5',
+ availableVersions
+ );
+
+ expect(error.message).toContain(
+ "No matching version found for SemVer '17.0.5'"
+ );
+ expect(error.message).toContain('Distribution: Empty');
+ expect(error.message).toContain('Package type: jdk');
+ expect(error.message).toContain('Architecture: x64');
+ expect(error.message).toContain(
+ 'Available versions: 11.0.1, 11.0.2, 17.0.1, 17.0.2'
+ );
+ });
+
+ it('should truncate available versions when there are many', () => {
+ const mockJavaBase = new EmptyJavaBase({
+ version: '17.0.5',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ // Create 60 versions to test truncation
+ const availableVersions = Array.from({length: 60}, (_, i) => `11.0.${i}`);
+ const error = (mockJavaBase as any).createVersionNotFoundError(
+ '17.0.5',
+ availableVersions
+ );
+
+ expect(error.message).toContain('Available versions:');
+ expect(error.message).toContain('...');
+ expect(error.message).toContain('(showing first 50 of 60 versions');
+ });
+
+ it('should include additional context when provided', () => {
+ const mockJavaBase = new EmptyJavaBase({
+ version: '17.0.5',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const availableVersions = ['11.0.1', '11.0.2'];
+ const additionalContext = 'Platform: linux';
+ const error = (mockJavaBase as any).createVersionNotFoundError(
+ '17.0.5',
+ availableVersions,
+ additionalContext
+ );
+
+ expect(error.message).toContain(
+ "No matching version found for SemVer '17.0.5'"
+ );
+ expect(error.message).toContain('Distribution: Empty');
+ expect(error.message).toContain('Package type: jdk');
+ expect(error.message).toContain('Architecture: x64');
+ expect(error.message).toContain('Platform: linux');
+ expect(error.message).toContain('Available versions: 11.0.1, 11.0.2');
+ });
});
describe('getToolcacheVersionName', () => {
diff --git a/__tests__/distributors/corretto-installer.test.ts b/__tests__/distributors/corretto-installer.test.ts
index 0604603f2..bc24a532b 100644
--- a/__tests__/distributors/corretto-installer.test.ts
+++ b/__tests__/distributors/corretto-installer.test.ts
@@ -1,16 +1,63 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import fs from 'fs';
+import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
import {HttpClient} from '@actions/http-client';
-import {JavaInstallerOptions} from '../../src/distributions/base-models';
-import {CorrettoDistribution} from '../../src/distributions/corretto/installer';
-import * as util from '../../src/util';
import os from 'os';
-import {isGeneratorFunction} from 'util/types';
-import manifestData from '../data/corretto.json';
+import manifestData from '../data/corretto.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ getDownloadArchiveExtension: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {CorrettoDistribution} =
+ await import('../../src/distributions/corretto/installer.js');
+const util = await import('../../src/util.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
- let spyGetDownloadArchiveExtension: jest.SpyInstance;
+ let spyHttpClient: ReturnType;
+ let spyGetDownloadArchiveExtension: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -19,10 +66,12 @@ describe('getAvailableVersions', () => {
headers: {},
result: manifestData
});
- spyGetDownloadArchiveExtension = jest.spyOn(
- util,
- 'getDownloadArchiveExtension'
- );
+ spyGetDownloadArchiveExtension =
+ util.getDownloadArchiveExtension as jest.Mock;
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -150,11 +199,34 @@ describe('getAvailableVersions', () => {
});
mockPlatform(distribution, platform);
- const availableVersion = await distribution['findPackageForDownload'](
- version
- );
+ const availableVersion =
+ await distribution['findPackageForDownload'](version);
expect(availableVersion).not.toBeNull();
expect(availableVersion.url).toBe(expectedLink);
+ expect(availableVersion.checksum).toEqual({
+ algorithm: 'sha256',
+ value: expect.stringMatching(/^[a-f0-9]{64}$/),
+ source:
+ 'https://corretto.github.io/corretto-downloads/latest_links/indexmap_with_checksum.json'
+ });
+ });
+
+ it('with latest resolves to the newest available major version', async () => {
+ const distribution = new CorrettoDistribution({
+ version: 'latest',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ mockPlatform(distribution, 'linux');
+
+ const availableVersion =
+ await distribution['findPackageForDownload']('x');
+ expect(availableVersion).not.toBeNull();
+ // 18 is the newest major present in the mocked Corretto index
+ expect(availableVersion.url).toBe(
+ 'https://corretto.aws/downloads/resources/18.0.0.37.1/amazon-corretto-18.0.0.37.1-linux-x64.tar.gz'
+ );
});
it('with unstable version expect to throw not supported error', async () => {
@@ -199,7 +271,7 @@ describe('getAvailableVersions', () => {
await expect(
distribution['findPackageForDownload'](version)
- ).rejects.toThrow("Could not find satisfied version for SemVer '4'");
+ ).rejects.toThrow("No matching version found for SemVer '4'");
});
it.each([
@@ -222,17 +294,29 @@ describe('getAvailableVersions', () => {
const expectedLink = `https://corretto.aws/downloads/resources/17.0.2.8.1/amazon-corretto-17.0.2.8.1-macosx-${distroArch}.tar.gz`;
- const availableVersion = await distribution['findPackageForDownload'](
- '17'
- );
+ const availableVersion =
+ await distribution['findPackageForDownload']('17');
expect(availableVersion).not.toBeNull();
expect(availableVersion.url).toBe(expectedLink);
}
);
+
+ it('keeps the canonical ARM runner value separate from the vendor value', () => {
+ jest.spyOn(os, 'arch').mockReturnValue('arm');
+ const distribution = new CorrettoDistribution({
+ version: '11',
+ architecture: '',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ expect(distribution['architecture']).toBe('armv7');
+ expect(distribution['distributionArchitecture']()).toBe('arm');
+ });
});
const mockPlatform = (
- distribution: CorrettoDistribution,
+ distribution: InstanceType,
platform: string
) => {
distribution['getPlatformOption'] = () => platform;
@@ -240,3 +324,50 @@ describe('getAvailableVersions', () => {
spyGetDownloadArchiveExtension.mockReturnValue(mockedExtension);
};
});
+
+describe('Corretto getPlatformOption libc selection', () => {
+ const originalPlatform = Object.getOwnPropertyDescriptor(
+ process,
+ 'platform'
+ ) as PropertyDescriptor;
+
+ const setPlatform = (platform: NodeJS.Platform) =>
+ Object.defineProperty(process, 'platform', {
+ ...originalPlatform,
+ value: platform
+ });
+
+ const distribution = new CorrettoDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ afterEach(() => {
+ Object.defineProperty(process, 'platform', originalPlatform);
+ jest.restoreAllMocks();
+ });
+
+ it('selects the musl artifacts on Alpine', () => {
+ setPlatform('linux');
+ jest.spyOn(fs, 'existsSync').mockReturnValue(true);
+
+ expect(distribution['getPlatformOption']()).toBe('alpine');
+ });
+
+ it('selects the glibc artifacts on other Linux runners', () => {
+ setPlatform('linux');
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+
+ expect(distribution['getPlatformOption']()).toBe('linux');
+ });
+
+ it('does not probe for Alpine off Linux', () => {
+ setPlatform('darwin');
+ const existsSync = jest.spyOn(fs, 'existsSync');
+
+ expect(distribution['getPlatformOption']()).toBe('macos');
+ expect(existsSync).not.toHaveBeenCalled();
+ });
+});
diff --git a/__tests__/distributors/distribution-factory.lazy-loading.test.ts b/__tests__/distributors/distribution-factory.lazy-loading.test.ts
new file mode 100644
index 000000000..a87cc13bb
--- /dev/null
+++ b/__tests__/distributors/distribution-factory.lazy-loading.test.ts
@@ -0,0 +1,23 @@
+import {jest, describe, it, expect} from '@jest/globals';
+
+jest.unstable_mockModule('../../src/distributions/zulu/installer.js', () => {
+ throw new Error(
+ 'Zulu installer module must not be imported on the Temurin fast path'
+ );
+});
+
+const {getJavaDistribution} =
+ await import('../../src/distributions/distribution-factory.js');
+
+describe('distribution factory lazy loading', () => {
+ it('does not load non-selected distribution installers for Temurin', async () => {
+ const distribution = await getJavaDistribution('temurin', {
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ expect(distribution).not.toBeNull();
+ });
+});
diff --git a/__tests__/distributors/distribution-factory.test.ts b/__tests__/distributors/distribution-factory.test.ts
new file mode 100644
index 000000000..c473373a4
--- /dev/null
+++ b/__tests__/distributors/distribution-factory.test.ts
@@ -0,0 +1,160 @@
+import {getJavaDistribution} from '../../src/distributions/distribution-factory.js';
+import {RetryingHttpClient} from '../../src/retrying-http-client.js';
+import {
+ JAVA_PACKAGE_CAPABILITIES,
+ JavaDistribution
+} from '../../src/distributions/package-types.js';
+import os from 'os';
+import {validateJavaPlatform} from '../../src/distributions/platform-types.js';
+import {normalizeArchitecture} from '../../src/distributions/platform-types.js';
+
+const supportedDistributionsOnCurrentPlatform = Object.values(
+ JavaDistribution
+).filter(distributionName => {
+ try {
+ validateJavaPlatform(distributionName, process.platform, 'x64', '25');
+ return distributionName !== JavaDistribution.JdkFile;
+ } catch {
+ return false;
+ }
+});
+
+const installerOptions = (packageType: string, version = '25') => ({
+ version,
+ architecture: 'x64',
+ packageType,
+ checkLatest: false
+});
+
+describe('getJavaDistribution', () => {
+ it.each(supportedDistributionsOnCurrentPlatform)(
+ 'uses the shared retrying HTTP client for %s',
+ async distributionName => {
+ const distribution = await getJavaDistribution(distributionName, {
+ version: '25',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ expect(distribution).not.toBeNull();
+ expect(distribution!['http']).toBeInstanceOf(RetryingHttpClient);
+ }
+ );
+
+ it.each(
+ Object.entries(JAVA_PACKAGE_CAPABILITIES).flatMap(
+ ([distributionName, packageTypes]) =>
+ supportedDistributionsOnCurrentPlatform.includes(
+ distributionName as JavaDistribution
+ ) || distributionName === JavaDistribution.JdkFile
+ ? packageTypes.map(packageType => [distributionName, packageType])
+ : []
+ )
+ )(
+ 'accepts %s with java-package %s',
+ async (distributionName, packageType) => {
+ expect(
+ await getJavaDistribution(
+ distributionName,
+ installerOptions(packageType as string)
+ )
+ ).not.toBeNull();
+ }
+ );
+
+ it.each(Object.entries(JAVA_PACKAGE_CAPABILITIES))(
+ 'rejects unsupported java-package values for %s',
+ async (distributionName, packageTypes) => {
+ await expect(
+ getJavaDistribution(distributionName, installerOptions('jdk+typo'))
+ ).rejects.toThrow(
+ `Java package 'jdk+typo' is not supported for distribution '${distributionName}'. Supported package types: ${packageTypes.join(', ')}.`
+ );
+ }
+ );
+
+ it("rejects java-package 'jdk+jmods' for non-Temurin distributions", async () => {
+ await expect(
+ getJavaDistribution('zulu', installerOptions('jdk+jmods'))
+ ).rejects.toThrow(
+ "Java package 'jdk+jmods' is not supported for distribution 'zulu'. Supported package types: jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac."
+ );
+ });
+
+ it.each(['8', '23.x', '23.0.1.1', '<24'])(
+ "rejects Temurin java-package 'jdk+jmods' for version %s",
+ async version => {
+ await expect(
+ getJavaDistribution(
+ JavaDistribution.Temurin,
+ installerOptions('jdk+jmods', version)
+ )
+ ).rejects.toThrow(
+ `Java package 'jdk+jmods' is not supported for distribution 'temurin'. Supported package types: jdk, jre, jdk+jmods. Package 'jdk+jmods' requires Java 24 or later; requested version '${version}'.`
+ );
+ }
+ );
+
+ it.each(['24', '24.0.1.1', '25-ea', '>=21', 'latest'])(
+ "accepts Temurin java-package 'jdk+jmods' for version %s",
+ async version => {
+ expect(
+ await getJavaDistribution(
+ JavaDistribution.Temurin,
+ installerOptions('jdk+jmods', version)
+ )
+ ).not.toBeNull();
+ }
+ );
+
+ it('preserves unsupported distribution handling', async () => {
+ expect(
+ await getJavaDistribution(
+ 'not-a-distribution',
+ installerOptions('not-a-package')
+ )
+ ).toBeNull();
+ });
+
+ it.each(['adopt', 'adopt-hotspot', 'adopt-openj9'])(
+ 'does not support legacy Adopt distribution %s',
+ async distributionName => {
+ expect(
+ await getJavaDistribution(distributionName, installerOptions('jdk'))
+ ).toBeNull();
+ }
+ );
+
+ it.each([
+ ['amd64', 'x64'],
+ ['ia32', 'x86'],
+ ['arm64', 'aarch64']
+ ])('passes normalized architecture %s as %s', async (input, expected) => {
+ const normalized = await getJavaDistribution(JavaDistribution.JdkFile, {
+ ...installerOptions('jdk'),
+ architecture: input
+ });
+
+ expect(normalized!['architecture']).toBe(expected);
+ });
+
+ it('uses the runner architecture when the input is empty', async () => {
+ const distribution = await getJavaDistribution(JavaDistribution.Temurin, {
+ ...installerOptions('jdk'),
+ architecture: ''
+ });
+
+ const expected = normalizeArchitecture(os.arch());
+ expect(distribution!['architecture']).toBe(expected);
+ });
+
+ it('rejects an unsupported combination before creating an HTTP client', async () => {
+ await expect(
+ getJavaDistribution(JavaDistribution.Oracle, {
+ ...installerOptions('jdk'),
+ architecture: 'x86'
+ })
+ ).rejects.toThrow(/does not support operating system/);
+ });
+});
diff --git a/__tests__/distributors/dragonwell-installer.test.ts b/__tests__/distributors/dragonwell-installer.test.ts
index 4a680d8f3..143d82666 100644
--- a/__tests__/distributors/dragonwell-installer.test.ts
+++ b/__tests__/distributors/dragonwell-installer.test.ts
@@ -1,12 +1,60 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import fs from 'fs';
import {HttpClient} from '@actions/http-client';
-import {DragonwellDistribution} from '../../src/distributions/dragonwell/installer';
-import * as utils from '../../src/util';
-import manifestData from '../data/dragonwell.json';
+import manifestData from '../data/dragonwell.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ getDownloadArchiveExtension: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {DragonwellDistribution} =
+ await import('../../src/distributions/dragonwell/installer.js');
+const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
- let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyUtilGetDownloadArchiveExtension: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -16,11 +64,13 @@ describe('getAvailableVersions', () => {
result: manifestData
});
- spyUtilGetDownloadArchiveExtension = jest.spyOn(
- utils,
- 'getDownloadArchiveExtension'
- );
+ spyUtilGetDownloadArchiveExtension =
+ utils.getDownloadArchiveExtension as jest.Mock;
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -30,7 +80,7 @@ describe('getAvailableVersions', () => {
});
const mockPlatform = (
- distribution: DragonwellDistribution,
+ distribution: InstanceType,
platform: string
) => {
distribution['getPlatformOption'] = () => platform;
@@ -206,11 +256,14 @@ describe('getAvailableVersions', () => {
});
mockPlatform(distribution, platform);
- const availableVersion = await distribution['findPackageForDownload'](
- jdkVersion
- );
+ const availableVersion =
+ await distribution['findPackageForDownload'](jdkVersion);
expect(availableVersion).not.toBeNull();
expect(availableVersion.url).toBe(expectedLink);
+ expect(availableVersion.checksum).toEqual({
+ algorithm: 'sha256',
+ value: expect.stringMatching(/^[a-f0-9]{64}$/)
+ });
}
);
@@ -220,7 +273,7 @@ describe('getAvailableVersions', () => {
['11', 'macos', 'aarch64'],
['17', 'linux', 'riscv']
])(
- 'should throw when required version of JDK can not be found in the JSON',
+ 'should throw when required version of JDK cannot be found in the JSON',
async (jdkVersion: string, platform: string, arch: string) => {
const distribution = new DragonwellDistribution({
version: jdkVersion,
@@ -233,7 +286,7 @@ describe('getAvailableVersions', () => {
await expect(
distribution['findPackageForDownload'](jdkVersion)
).rejects.toThrow(
- `Couldn't find any satisfied version for the specified java-version: "${jdkVersion}" and architecture: "${arch}".`
+ `No matching version found for SemVer '${jdkVersion}'`
);
}
);
@@ -255,3 +308,50 @@ describe('getAvailableVersions', () => {
});
});
});
+
+describe('Dragonwell getPlatformOption libc selection', () => {
+ const originalPlatform = Object.getOwnPropertyDescriptor(
+ process,
+ 'platform'
+ ) as PropertyDescriptor;
+
+ const setPlatform = (platform: NodeJS.Platform) =>
+ Object.defineProperty(process, 'platform', {
+ ...originalPlatform,
+ value: platform
+ });
+
+ const distribution = new DragonwellDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ afterEach(() => {
+ Object.defineProperty(process, 'platform', originalPlatform);
+ jest.restoreAllMocks();
+ });
+
+ it('selects the musl artifacts on Alpine', () => {
+ setPlatform('linux');
+ jest.spyOn(fs, 'existsSync').mockReturnValue(true);
+
+ expect(distribution['getPlatformOption']()).toBe('alpine-linux');
+ });
+
+ it('selects the glibc artifacts on other Linux runners', () => {
+ setPlatform('linux');
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+
+ expect(distribution['getPlatformOption']()).toBe('linux');
+ });
+
+ it('does not probe for Alpine off Linux', () => {
+ setPlatform('win32');
+ const existsSync = jest.spyOn(fs, 'existsSync');
+
+ expect(distribution['getPlatformOption']()).toBe('windows');
+ expect(existsSync).not.toHaveBeenCalled();
+ });
+});
diff --git a/__tests__/distributors/graalvm-installer.test.ts b/__tests__/distributors/graalvm-installer.test.ts
index 479f34526..16b2c42cb 100644
--- a/__tests__/distributors/graalvm-installer.test.ts
+++ b/__tests__/distributors/graalvm-installer.test.ts
@@ -1,156 +1,1471 @@
-import {GraalVMDistribution} from '../../src/distributions/graalvm/installer';
-import os from 'os';
-import * as core from '@actions/core';
-import {getDownloadArchiveExtension} from '../../src/util';
-import {HttpClient} from '@actions/http-client';
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import path from 'path';
-describe('findPackageForDownload', () => {
- let distribution: GraalVMDistribution;
- let spyDebug: jest.SpyInstance;
- let spyHttpClient: jest.SpyInstance;
+// Mock @actions modules
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+jest.unstable_mockModule('@actions/tool-cache', () => ({
+ find: jest.fn(),
+ findAllVersions: jest.fn(),
+ downloadTool: jest.fn(),
+ extractZip: jest.fn(),
+ extractTar: jest.fn(),
+ extract7z: jest.fn(),
+ extractXar: jest.fn(),
+ cacheDir: jest.fn(),
+ cacheFile: jest.fn(),
+ getManifestFromRepo: jest.fn(),
+ findFromManifest: jest.fn(),
+ evaluateVersions: jest.fn()
+}));
+
+jest.unstable_mockModule('@actions/http-client', () => ({
+ HttpClient: jest.fn().mockImplementation(() => ({
+ getJson: jest.fn(),
+ head: jest.fn(),
+ get: jest.fn()
+ })),
+ HttpClientError: class HttpClientError extends Error {
+ statusCode: number;
+ constructor(message: string, statusCode: number) {
+ super(message);
+ this.statusCode = statusCode;
+ }
+ },
+ HttpCodes: {OK: 200, NotFound: 404, Unauthorized: 401, Forbidden: 403}
+}));
+
+// Get real util first, then mock specific functions
+const realUtil = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...realUtil,
+ extractJdkFile: jest.fn(),
+ getDownloadArchiveExtension: jest.fn(),
+ getJavaVersionFromReleaseFile: jest.fn(),
+ renameWinArchive: jest.fn(),
+ getGitHubHttpHeaders: jest.fn().mockReturnValue({Accept: 'application/json'})
+}));
+
+const real_fs_module = await import('fs');
+jest.unstable_mockModule('fs', () => ({
+ ...real_fs_module,
+ default: {
+ ...real_fs_module.default,
+ readdirSync: jest.fn(),
+ existsSync: jest.fn()
+ },
+ readdirSync: jest.fn(),
+ existsSync: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const tc = await import('@actions/tool-cache');
+const http = await import('@actions/http-client');
+const fs = (await import('fs')).default;
+const util = await import('../../src/util.js');
+const {GraalVMCommunityDistribution, GraalVMDistribution} =
+ await import('../../src/distributions/graalvm/installer.js');
+const {getJavaDistribution} =
+ await import('../../src/distributions/distribution-factory.js');
+
+import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
+
+beforeAll(() => {
+ process.env.NODE_ENV = 'test';
+ console.log('✅ All external dependencies are properly mocked');
+});
+
+describe('GraalVMDistribution', () => {
+ let distribution: InstanceType;
+ let communityDistribution: InstanceType;
+ let mockHttpClient: any;
+ let spyCoreError: any;
+
+ const defaultOptions: JavaInstallerOptions = {
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ };
beforeEach(() => {
- distribution = new GraalVMDistribution({
- version: '',
- architecture: 'x64',
- packageType: 'jdk',
- checkLatest: false
- });
+ jest.clearAllMocks();
- spyDebug = jest.spyOn(core, 'debug');
- spyDebug.mockImplementation(() => {});
- });
+ distribution = new GraalVMDistribution(defaultOptions);
+ communityDistribution = new GraalVMCommunityDistribution(defaultOptions);
- it.each([
- [
- '21',
- '21',
- 'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}'
- ],
- [
- '21.0.4',
- '21.0.4',
- 'https://download.oracle.com/graalvm/21/archive/graalvm-jdk-21.0.4_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}'
- ],
- [
- '17',
- '17',
- 'https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}'
- ],
- [
- '17.0.12',
- '17.0.12',
- 'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.12_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}'
- ]
- ])('version is %s -> %s', async (input, expectedVersion, expectedUrl) => {
- /* Needed only for this particular test because /latest/ urls tend to change */
- spyHttpClient = jest.spyOn(HttpClient.prototype, 'head');
- spyHttpClient.mockReturnValue(
- Promise.resolve({
- message: {
- statusCode: 200
- }
- })
+ mockHttpClient = new (http.HttpClient as any)();
+ (distribution as any).http = mockHttpClient;
+ (communityDistribution as any).http = mockHttpClient;
+
+ // Default checksum sibling response for `${url}.sha256` requests made by
+ // GraalVM (Oracle) and GraalVM EA. Individual tests override this when
+ // they need to assert the exact URL/digest contract.
+ mockHttpClient.get.mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: jest.fn().mockResolvedValue('a'.repeat(64))
+ });
+
+ (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue(
+ 'tar.gz'
);
- const result = await distribution['findPackageForDownload'](input);
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
+ });
+ afterAll(() => {
jest.restoreAllMocks();
-
- expect(result.version).toBe(expectedVersion);
- const osType = distribution.getPlatform();
- const archiveType = getDownloadArchiveExtension();
- const url = expectedUrl
- .replace('{{OS_TYPE}}', osType)
- .replace('{{ARCHIVE_TYPE}}', archiveType);
- expect(result.url).toBe(url);
+ jest.clearAllMocks();
});
- it.each([
- [
- '24-ea',
- /^https:\/\/github\.com\/graalvm\/oracle-graalvm-ea-builds\/releases\/download\/jdk-24\.0\.0-ea\./
- ]
- ])('version is %s -> %s', async (version, expectedUrlPrefix) => {
- /* Needed only for this particular test because /latest/ urls tend to change */
- spyHttpClient = jest.spyOn(HttpClient.prototype, 'head');
- spyHttpClient.mockReturnValue(
- Promise.resolve({
- message: {
- statusCode: 200
- }
- })
- );
+ describe('getPlatform', () => {
+ it('should map darwin to macos', () => {
+ const result = distribution.getPlatform('darwin');
+ expect(result).toBe('macos');
+ });
- const eaDistro = new GraalVMDistribution({
- version,
- architecture: '', // to get default value
- packageType: 'jdk',
- checkLatest: false
+ it('should map win32 to windows', () => {
+ const result = distribution.getPlatform('win32');
+ expect(result).toBe('windows');
});
- const versionWithoutEA = version.split('-')[0];
- const result = await eaDistro['findPackageForDownload'](versionWithoutEA);
+ it('should map linux to linux', () => {
+ const result = distribution.getPlatform('linux');
+ expect(result).toBe('linux');
+ });
- jest.restoreAllMocks();
+ it('should throw error for unsupported platform', () => {
+ expect(() => distribution.getPlatform('aix' as NodeJS.Platform)).toThrow(
+ "Platform 'aix' is not supported. Supported platforms: 'linux', 'macos', 'windows'"
+ );
+ });
+ });
+
+ describe('setJavaDefault', () => {
+ it('should set GRAALVM_HOME for Oracle GraalVM', () => {
+ (distribution as any).setJavaDefault('17.0.5', '/cached/java/path');
+
+ expect(core.exportVariable).toHaveBeenCalledWith(
+ 'GRAALVM_HOME',
+ '/cached/java/path'
+ );
+ });
- expect(result.url).toEqual(expect.stringMatching(expectedUrlPrefix));
+ it('should set GRAALVM_HOME for GraalVM Community', () => {
+ (communityDistribution as any).setJavaDefault(
+ '17.0.5',
+ '/cached/java/path'
+ );
+
+ expect(core.exportVariable).toHaveBeenCalledWith(
+ 'GRAALVM_HOME',
+ '/cached/java/path'
+ );
+ });
});
- it.each([
- ['amd64', ['x64', 'amd64']],
- ['arm64', ['aarch64', 'arm64']]
- ])(
- 'defaults to os.arch(): %s mapped to distro arch: %s',
- async (osArch: string, distroArchs: string[]) => {
+ describe('downloadTool', () => {
+ const javaRelease = {
+ version: '17.0.5',
+ url: 'https://example.com/graalvm.tar.gz'
+ };
+
+ beforeEach(() => {
+ (tc.downloadTool as any).mockResolvedValue('/tmp/archive.tar.gz');
+ (tc.cacheDir as any).mockResolvedValue('/cached/java/path');
+
+ (util.extractJdkFile as any).mockResolvedValue('/tmp/extracted');
+
+ // Mock renameWinArchive - it returns the same path (no renaming)
+ (util.renameWinArchive as any).mockImplementation((p: string) => p);
+
+ (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue(
+ 'tar.gz'
+ );
+
+ // Mock fs.existsSync to return true for extracted path
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
+
+ (fs.readdirSync as jest.Mock).mockReturnValue([
+ 'graalvm-jdk-17.0.5'
+ ]);
+
jest
- .spyOn(os, 'arch')
- .mockReturnValue(osArch as ReturnType);
+ .spyOn(distribution as any, 'getToolcacheVersionName')
+ .mockImplementation(version => version);
+ });
+
+ it('should download, extract and cache the tool successfully', async () => {
+ const result = await (distribution as any).downloadTool(javaRelease);
+
+ // Verify the download was initiated
+ expect(tc.downloadTool).toHaveBeenCalledWith(javaRelease.url);
+
+ // The implementation uses the original path for extraction
+ expect(util.extractJdkFile).toHaveBeenCalledWith(
+ '/tmp/archive.tar.gz', // Original path
+ 'tar.gz'
+ );
+
+ // Verify path existence check
+ expect(fs.existsSync).toHaveBeenCalledWith('/tmp/extracted');
+
+ // Verify directory reading
+ expect(fs.readdirSync).toHaveBeenCalledWith('/tmp/extracted');
+
+ // Verify caching with correct parameters
+ expect(tc.cacheDir).toHaveBeenCalledWith(
+ path.join('/tmp/extracted', 'graalvm-jdk-17.0.5'),
+ 'Java_GraalVM_jdk',
+ '17.0.5',
+ 'x64'
+ );
+
+ // Verify the result
+ expect(result).toEqual({
+ version: '17.0.5',
+ path: '/cached/java/path'
+ });
+
+ // Verify logging
+ expect(core.info).toHaveBeenCalledWith(
+ 'Downloading Java 17.0.5 (GraalVM) from https://example.com/graalvm.tar.gz ...'
+ );
+ expect(core.info).toHaveBeenCalledWith('Extracting Java archive...');
+ });
+
+ it('should throw error when extracted path does not exist', async () => {
+ (fs.existsSync as jest.Mock).mockReturnValue(false);
+
+ await expect(
+ (distribution as any).downloadTool(javaRelease)
+ ).rejects.toThrow(
+ 'Extraction failed: path /tmp/extracted does not exist'
+ );
+
+ expect(core.error).toHaveBeenCalledWith(
+ expect.stringContaining('Failed to download and extract GraalVM:')
+ );
+ });
+
+ it('should throw error when extracted directory is empty', async () => {
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
+ (fs.readdirSync as jest.Mock).mockReturnValue([]);
+
+ await expect(
+ (distribution as any).downloadTool(javaRelease)
+ ).rejects.toThrow(
+ 'Extraction failed: no files found in extracted directory'
+ );
+
+ expect(core.error).toHaveBeenCalledWith(
+ expect.stringContaining('Failed to download and extract GraalVM:')
+ );
+ });
+
+ it('should handle download errors', async () => {
+ const downloadError = new Error('Network error during download');
+ (tc.downloadTool as any).mockRejectedValue(downloadError);
+
+ await expect(
+ (distribution as any).downloadTool(javaRelease)
+ ).rejects.toThrow('Network error during download');
+
+ expect(core.error).toHaveBeenCalledWith(
+ 'Failed to download and extract GraalVM: Error: Network error during download'
+ );
+ });
+
+ it('should handle extraction errors', async () => {
+ const extractError = new Error('Failed to extract archive');
+ (util.extractJdkFile as any).mockRejectedValue(extractError);
+
+ await expect(
+ (distribution as any).downloadTool(javaRelease)
+ ).rejects.toThrow('Failed to extract archive');
+
+ expect(core.error).toHaveBeenCalledWith(
+ 'Failed to download and extract GraalVM: Error: Failed to extract archive'
+ );
+ });
+
+ it('should handle different archive extensions', async () => {
+ // Test with a .zip file
+ (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue(
+ 'zip'
+ );
+ (tc.downloadTool as any).mockResolvedValue('/tmp/archive.zip');
- const distribution = new GraalVMDistribution({
+ const zipRelease = {
+ version: '17.0.5',
+ url: 'https://example.com/graalvm.zip'
+ };
+
+ const result = await (distribution as any).downloadTool(zipRelease);
+
+ expect(util.extractJdkFile).toHaveBeenCalledWith(
+ '/tmp/archive.zip',
+ 'zip'
+ );
+
+ expect(result).toEqual({
+ version: '17.0.5',
+ path: '/cached/java/path'
+ });
+ });
+
+ it('should use a dedicated toolcache folder for GraalVM Community', async () => {
+ const result = await (communityDistribution as any).downloadTool(
+ javaRelease
+ );
+
+ expect(tc.cacheDir).toHaveBeenCalledWith(
+ path.join('/tmp/extracted', 'graalvm-jdk-17.0.5'),
+ 'Java_GraalVM_Community_jdk',
+ '17.0.5',
+ 'x64'
+ );
+ expect(result).toEqual({
+ version: '17.0.5',
+ path: '/cached/java/path'
+ });
+ });
+
+ it('caches Oracle GraalVM floating artifacts under their installed version', async () => {
+ (util.getJavaVersionFromReleaseFile as jest.Mock).mockReturnValue(
+ '21.0.9+7'
+ );
+ const floatingRelease = {
version: '21',
- architecture: '', // to get default value
- packageType: 'jdk',
- checkLatest: false
+ url: 'https://example.com/graalvm/latest/graalvm-jdk-21.tar.gz',
+ floating: true
+ };
+
+ const result = await (distribution as any).downloadTool(floatingRelease);
+
+ expect(tc.cacheDir).toHaveBeenCalledWith(
+ path.join('/tmp/extracted', 'graalvm-jdk-17.0.5'),
+ 'Java_GraalVM_jdk',
+ '21.0.9+7',
+ 'x64'
+ );
+ expect(result).toEqual({
+ version: '21.0.9+7',
+ path: '/cached/java/path'
+ });
+ });
+ });
+
+ describe('findPackageForDownload', () => {
+ beforeEach(() => {
+ jest.spyOn(distribution, 'getPlatform').mockReturnValue('linux');
+ });
+
+ describe('input validation', () => {
+ it('should throw error for null version range', async () => {
+ await expect(
+ (distribution as any).findPackageForDownload(null)
+ ).rejects.toThrow('Version range is required and must be a string');
+ });
+
+ it('should throw error for undefined version range', async () => {
+ await expect(
+ (distribution as any).findPackageForDownload(undefined)
+ ).rejects.toThrow('Version range is required and must be a string');
+ });
+
+ it('should throw error for empty string version range', async () => {
+ await expect(
+ (distribution as any).findPackageForDownload('')
+ ).rejects.toThrow('Version range is required and must be a string');
+ });
+
+ it('should throw error for non-string version range', async () => {
+ await expect(
+ (distribution as any).findPackageForDownload(123)
+ ).rejects.toThrow('Version range is required and must be a string');
+ });
+
+ it('should throw error for invalid version format', async () => {
+ await expect(
+ (distribution as any).findPackageForDownload('abc')
+ ).rejects.toThrow('Invalid version format: abc');
+ });
+ });
+
+ describe('stable builds', () => {
+ it('should construct correct URL for specific version', async () => {
+ const mockResponse = {
+ message: {statusCode: 200}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ const result = await (distribution as any).findPackageForDownload(
+ '17.0.5'
+ );
+
+ expect(result).toEqual({
+ url: 'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.5_linux-x64_bin.tar.gz',
+ version: '17.0.5',
+ checksum: {
+ algorithm: 'sha256',
+ value: 'a'.repeat(64),
+ source:
+ 'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.5_linux-x64_bin.tar.gz.sha256'
+ },
+ floating: false
+ });
+ expect(mockHttpClient.head).toHaveBeenCalledWith(result.url);
+ expect(mockHttpClient.get).toHaveBeenCalledWith(`${result.url}.sha256`);
+ });
+
+ it('should construct correct URL for major version (latest)', async () => {
+ const mockResponse = {
+ message: {statusCode: 200}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ const result = await (distribution as any).findPackageForDownload('21');
+
+ expect(result).toEqual({
+ url: 'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-x64_bin.tar.gz',
+ version: '21',
+ checksum: {
+ algorithm: 'sha256',
+ value: 'a'.repeat(64),
+ source:
+ 'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-x64_bin.tar.gz.sha256'
+ },
+ // A major-only range resolves to the floating `/latest/` URL, so the
+ // release must not be reused by a later job.
+ floating: true
+ });
+ });
+
+ it.each([
+ ['21', 'etag:"graalvm-latest"'],
+ ['17.0.5', undefined]
+ ])(
+ 'fingerprints only the floating artifact for version %s',
+ async (input, expected) => {
+ mockHttpClient.head.mockResolvedValue({
+ message: {statusCode: 200, headers: {etag: '"graalvm-latest"'}}
+ } as any);
+
+ const result = await (distribution as any).findPackageForDownload(
+ input
+ );
+
+ // Without a fingerprint the constant `/latest/` URL would key a cache
+ // entry that never invalidates when Oracle republishes the artifact.
+ expect(result.fingerprint).toBe(expected);
+ }
+ );
+
+ it('always resolves Oracle GraalVM major-only requests remotely', () => {
+ expect((distribution as any).requiresRemoteResolution()).toBe(true);
+ expect((communityDistribution as any).requiresRemoteResolution()).toBe(
+ false
+ );
+ });
+
+ it('should throw error for unsupported architecture', async () => {
+ distribution = new GraalVMDistribution({
+ ...defaultOptions,
+ architecture: 'x86'
+ });
+ (distribution as any).http = mockHttpClient;
+
+ await expect(
+ (distribution as any).findPackageForDownload('17')
+ ).rejects.toThrow(
+ 'Unsupported architecture: x86. Supported architectures are: x64, aarch64'
+ );
+ });
+
+ describe('latest alias', () => {
+ it('resolves the newest major version from the Adoptium API', async () => {
+ const latestDistribution = new GraalVMDistribution({
+ ...defaultOptions,
+ version: 'latest'
+ });
+ (latestDistribution as any).http = mockHttpClient;
+ jest
+ .spyOn(latestDistribution, 'getPlatform')
+ .mockReturnValue('linux');
+ mockHttpClient.getJson.mockResolvedValue({
+ statusCode: 200,
+ result: {most_recent_feature_release: 25},
+ headers: {}
+ });
+ mockHttpClient.head.mockResolvedValue({
+ message: {statusCode: 200}
+ });
+
+ const result = await (
+ latestDistribution as any
+ ).findPackageForDownload('x');
+
+ expect(result).toEqual({
+ url: 'https://download.oracle.com/graalvm/25/latest/graalvm-jdk-25_linux-x64_bin.tar.gz',
+ version: '25',
+ checksum: {
+ algorithm: 'sha256',
+ value: 'a'.repeat(64),
+ source:
+ 'https://download.oracle.com/graalvm/25/latest/graalvm-jdk-25_linux-x64_bin.tar.gz.sha256'
+ },
+ floating: true
+ });
+ });
+
+ it('throws an actionable error when the latest major is not yet available', async () => {
+ const latestDistribution = new GraalVMDistribution({
+ ...defaultOptions,
+ version: 'latest'
+ });
+ (latestDistribution as any).http = mockHttpClient;
+ jest
+ .spyOn(latestDistribution, 'getPlatform')
+ .mockReturnValue('linux');
+ mockHttpClient.getJson.mockResolvedValue({
+ statusCode: 200,
+ result: {most_recent_feature_release: 25},
+ headers: {}
+ });
+ mockHttpClient.head.mockResolvedValue({
+ message: {statusCode: 404}
+ });
+
+ await expect(
+ (latestDistribution as any).findPackageForDownload('x')
+ ).rejects.toThrow(
+ /is not yet available for the GraalVM distribution/
+ );
+ });
+ });
+
+ it('should throw error for JDK versions less than 17', async () => {
+ await expect(
+ (distribution as any).findPackageForDownload('11')
+ ).rejects.toThrow(
+ 'GraalVM is only supported for JDK 17 and later. Requested version: 11'
+ );
+ });
+
+ it('should throw error for non-jdk package types', async () => {
+ distribution = new GraalVMDistribution({
+ ...defaultOptions,
+ packageType: 'jre'
+ });
+ (distribution as any).http = mockHttpClient;
+
+ await expect(
+ (distribution as any).findPackageForDownload('17')
+ ).rejects.toThrow('GraalVM provides only the `jdk` package type');
+ });
+
+ it('should throw error when file not found (404)', async () => {
+ const mockResponse = {
+ message: {statusCode: 404}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ // Verify the error is thrown with the expected message
+ await expect(
+ (distribution as any).findPackageForDownload('17.0.99')
+ ).rejects.toThrow("No matching version found for SemVer '17.0.99'");
+ // Verify distribution info is included
+ await expect(
+ (distribution as any).findPackageForDownload('17.0.99')
+ ).rejects.toThrow('GraalVM');
+
+ // Verify the hint about checking the base URL is included
+ await expect(
+ (distribution as any).findPackageForDownload('17.0.99')
+ ).rejects.toThrow('https://www.graalvm.org/downloads/');
+ });
+
+ it('should throw error for unauthorized access (401)', async () => {
+ const mockResponse = {
+ message: {statusCode: 401}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ await expect(
+ (distribution as any).findPackageForDownload('17')
+ ).rejects.toThrow(
+ 'Access denied when downloading GraalVM. Status code: 401. Please check your credentials or permissions.'
+ );
+ });
+
+ it('should throw error for forbidden access (403)', async () => {
+ const mockResponse = {
+ message: {statusCode: 403}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ await expect(
+ (distribution as any).findPackageForDownload('17')
+ ).rejects.toThrow(
+ 'Access denied when downloading GraalVM. Status code: 403. Please check your credentials or permissions.'
+ );
+ });
+
+ it('should throw error for other HTTP errors with status message', async () => {
+ const mockResponse = {
+ message: {
+ statusCode: 500,
+ statusMessage: 'Internal Server Error'
+ }
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ await expect(
+ (distribution as any).findPackageForDownload('17')
+ ).rejects.toThrow(
+ 'HTTP request for GraalVM failed with status code: 500 (Internal Server Error)'
+ );
+ });
+
+ it('should throw error for other HTTP errors without status message', async () => {
+ const mockResponse = {
+ message: {statusCode: 500}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ await expect(
+ (distribution as any).findPackageForDownload('17')
+ ).rejects.toThrow(
+ 'HTTP request for GraalVM failed with status code: 500 (Unknown error)'
+ );
+ });
+ });
+
+ describe('EA builds', () => {
+ beforeEach(() => {
+ distribution = new GraalVMDistribution(defaultOptions);
+ (distribution as any).http = mockHttpClient;
+ (distribution as any).stable = false;
+ });
+
+ it('should delegate to findEABuildDownloadUrl for unstable versions', async () => {
+ const currentPlatform =
+ process.platform === 'win32' ? 'windows' : process.platform;
+
+ const mockEAVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'x64',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz'
+ },
+ {
+ arch: 'aarch64',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-aarch64_bin.tar.gz'
+ }
+ ]
+ }
+ ];
+
+ mockHttpClient.getJson.mockResolvedValue({
+ result: mockEAVersions,
+ statusCode: 200,
+ headers: {}
+ });
+
+ jest
+ .spyOn(distribution as any, 'distributionArchitecture')
+ .mockReturnValue('x64');
+
+ const result = await (distribution as any).findPackageForDownload('23');
+
+ expect(result).toEqual({
+ url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz',
+ version: '23-ea-20240716',
+ checksum: {
+ algorithm: 'sha256',
+ value: 'a'.repeat(64),
+ source:
+ 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz.sha256'
+ }
+ });
+
+ expect(mockHttpClient.getJson).toHaveBeenCalledWith(
+ 'https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/23-ea.json?ref=main',
+ {Accept: 'application/json'}
+ );
+ expect(mockHttpClient.get).toHaveBeenCalledWith(`${result.url}.sha256`);
});
- const osType = distribution.getPlatform();
- if (osType === 'windows' && distroArchs.includes('aarch64')) {
- return; // skip, aarch64 is not available for Windows
+ it('should throw error when no latest EA version found', async () => {
+ const currentPlatform =
+ process.platform === 'win32' ? 'windows' : process.platform;
+
+ const mockEAVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: false,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'x64',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz'
+ }
+ ]
+ }
+ ];
+
+ mockHttpClient.getJson.mockResolvedValue({
+ result: mockEAVersions,
+ statusCode: 200,
+ headers: {}
+ });
+
+ jest
+ .spyOn(distribution as any, 'distributionArchitecture')
+ .mockReturnValue('x64');
+
+ await expect(
+ (distribution as any).findPackageForDownload('23')
+ ).rejects.toThrow("No matching version found for SemVer '23-ea'");
+
+ await expect(
+ (distribution as any).findPackageForDownload('23')
+ ).rejects.toThrow(
+ 'Note: No EA build is marked as latest for this version.'
+ );
+
+ await expect(
+ (distribution as any).findPackageForDownload('23')
+ ).rejects.toThrow('23-ea-20240716');
+
+ // Verify error logging - removed as we now use the helper method which doesn't call core.error
+ });
+
+ it('should throw error when no matching file for architecture in EA build', async () => {
+ const currentPlatform =
+ process.platform === 'win32' ? 'windows' : process.platform;
+
+ const mockEAVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'arm64',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-arm64_bin.tar.gz'
+ }
+ ]
+ }
+ ];
+
+ mockHttpClient.getJson.mockResolvedValue({
+ result: mockEAVersions,
+ statusCode: 200,
+ headers: {}
+ });
+
+ jest
+ .spyOn(distribution as any, 'distributionArchitecture')
+ .mockReturnValue('x64');
+
+ await expect(
+ (distribution as any).findPackageForDownload('23')
+ ).rejects.toThrow(
+ `Unable to find file for architecture 'x64' and platform '${currentPlatform}'`
+ );
+
+ // Verify error logging
+ expect(core.error).toHaveBeenCalledWith(
+ expect.stringContaining('Available files for architecture x64:')
+ );
+ });
+
+ it('should throw error when no matching platform in EA build', async () => {
+ const mockEAVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'x64',
+ platform: 'different-platform',
+ filename: 'graalvm-jdk-23_different-x64_bin.tar.gz'
+ }
+ ]
+ }
+ ];
+
+ mockHttpClient.getJson.mockResolvedValue({
+ result: mockEAVersions,
+ statusCode: 200,
+ headers: {}
+ });
+
+ jest
+ .spyOn(distribution as any, 'distributionArchitecture')
+ .mockReturnValue('x64');
+
+ const currentPlatform =
+ process.platform === 'win32' ? 'windows' : process.platform;
+
+ await expect(
+ (distribution as any).findPackageForDownload('23')
+ ).rejects.toThrow(
+ `Unable to find file for architecture 'x64' and platform '${currentPlatform}'`
+ );
+ });
+
+ it('should throw error when filename does not start with graalvm-jdk-', async () => {
+ const currentPlatform =
+ process.platform === 'win32' ? 'windows' : process.platform;
+
+ const mockEAVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'x64',
+ platform: currentPlatform,
+ filename: 'wrong-prefix-23_linux-x64_bin.tar.gz'
+ }
+ ]
+ }
+ ];
+
+ mockHttpClient.getJson.mockResolvedValue({
+ result: mockEAVersions,
+ statusCode: 200,
+ headers: {}
+ });
+
+ jest
+ .spyOn(distribution as any, 'distributionArchitecture')
+ .mockReturnValue('x64');
+
+ await expect(
+ (distribution as any).findPackageForDownload('23')
+ ).rejects.toThrow(
+ "Invalid filename format: wrong-prefix-23_linux-x64_bin.tar.gz. Expected to start with 'graalvm-jdk-'"
+ );
+ });
+
+ it('should throw error when EA version JSON is not found', async () => {
+ mockHttpClient.getJson.mockResolvedValue({
+ result: null,
+ statusCode: 404,
+ headers: {}
+ });
+
+ await expect(
+ (distribution as any).findPackageForDownload('23')
+ ).rejects.toThrow(
+ "No GraalVM EA build found for version '23-ea'. Please check if the version is correct."
+ );
+ });
+ });
+ });
+
+ describe('findEABuildDownloadUrl', () => {
+ const currentPlatform =
+ process.platform === 'win32' ? 'windows' : process.platform;
+
+ const mockEAVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'x64',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz'
+ },
+ {
+ arch: 'aarch64',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-aarch64_bin.tar.gz'
+ }
+ ]
+ },
+ {
+ version: '23-ea-20240709',
+ latest: false,
+ download_base_url: 'https://example.com/old/',
+ files: [
+ {
+ arch: 'x64',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz'
+ }
+ ]
}
- const archiveType = getDownloadArchiveExtension();
- const result = await distribution['findPackageForDownload']('21');
+ ];
- const expectedUrls = distroArchs.map(
- distroArch =>
- `https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_${osType}-${distroArch}_bin.${archiveType}`
+ let fetchEASpy: any;
+
+ beforeEach(() => {
+ fetchEASpy = jest.spyOn(distribution as any, 'fetchEAJson');
+ jest
+ .spyOn(distribution as any, 'distributionArchitecture')
+ .mockReturnValue('x64');
+ });
+
+ it('should find latest version and return correct URL', async () => {
+ fetchEASpy.mockResolvedValue(mockEAVersions);
+
+ const result = await (distribution as any).findEABuildDownloadUrl(
+ '23-ea'
);
- expect(expectedUrls).toContain(result.url);
- }
- );
+ expect(fetchEASpy).toHaveBeenCalledWith('23-ea');
+ expect(result).toEqual({
+ url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz',
+ version: '23-ea-20240716',
+ checksum: {
+ algorithm: 'sha256',
+ value: 'a'.repeat(64),
+ source:
+ 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz.sha256'
+ }
+ });
+ expect(mockHttpClient.get).toHaveBeenCalledWith(`${result.url}.sha256`);
- it('should throw an error', async () => {
- await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
- /GraalVM is only supported for JDK 17 and later/
- );
- await expect(distribution['findPackageForDownload']('11')).rejects.toThrow(
- /GraalVM is only supported for JDK 17 and later/
- );
- await expect(distribution['findPackageForDownload']('18')).rejects.toThrow(
- /Could not find GraalVM for SemVer */
- );
+ // Verify debug logging
+ expect(core.debug).toHaveBeenCalledWith('Searching for EA build: 23-ea');
+ expect(core.debug).toHaveBeenCalledWith('Found 2 EA versions');
+ expect(core.debug).toHaveBeenCalledWith(
+ 'Latest version found: 23-ea-20240716'
+ );
+ expect(core.debug).toHaveBeenCalledWith(
+ 'Download URL: https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz'
+ );
+ });
+
+ it('should throw error when no latest version found', async () => {
+ const noLatestVersions = mockEAVersions.map(v => ({...v, latest: false}));
+ fetchEASpy.mockResolvedValue(noLatestVersions);
+
+ await expect(
+ (distribution as any).findEABuildDownloadUrl('23-ea')
+ ).rejects.toThrow("No matching version found for SemVer '23-ea'");
+
+ await expect(
+ (distribution as any).findEABuildDownloadUrl('23-ea')
+ ).rejects.toThrow(
+ 'Note: No EA build is marked as latest for this version.'
+ );
+
+ await expect(
+ (distribution as any).findEABuildDownloadUrl('23-ea')
+ ).rejects.toThrow('23-ea-20240716');
+
+ // Verify error logging - removed as we now use the helper method which doesn't call core.error
+ });
+
+ it('should throw error when no matching file for architecture', async () => {
+ const wrongArchVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'arm',
+ platform: currentPlatform,
+ filename: 'graalvm-jdk-23_linux-arm_bin.tar.gz'
+ }
+ ]
+ }
+ ];
+ fetchEASpy.mockResolvedValue(wrongArchVersions);
+
+ await expect(
+ (distribution as any).findEABuildDownloadUrl('23-ea')
+ ).rejects.toThrow(
+ `Unable to find file for architecture 'x64' and platform '${currentPlatform}'`
+ );
+
+ expect(core.error).toHaveBeenCalledWith(
+ expect.stringContaining('Available files for architecture x64:')
+ );
+ });
+
+ it('should throw error when filename does not start with graalvm-jdk-', async () => {
+ const badFilenameVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'x64',
+ platform: currentPlatform,
+ filename: 'wrong-name.tar.gz'
+ }
+ ]
+ }
+ ];
+ fetchEASpy.mockResolvedValue(badFilenameVersions);
+
+ await expect(
+ (distribution as any).findEABuildDownloadUrl('23-ea')
+ ).rejects.toThrow(
+ "Invalid filename format: wrong-name.tar.gz. Expected to start with 'graalvm-jdk-'"
+ );
+ });
+
+ it('should work with aarch64 architecture', async () => {
+ jest
+ .spyOn(distribution as any, 'distributionArchitecture')
+ .mockReturnValue('aarch64');
+
+ fetchEASpy.mockResolvedValue(mockEAVersions);
+
+ const result = await (distribution as any).findEABuildDownloadUrl(
+ '23-ea'
+ );
+
+ expect(result).toEqual({
+ url: 'https://example.com/download/graalvm-jdk-23_linux-aarch64_bin.tar.gz',
+ version: '23-ea-20240716',
+ checksum: {
+ algorithm: 'sha256',
+ value: 'a'.repeat(64),
+ source:
+ 'https://example.com/download/graalvm-jdk-23_linux-aarch64_bin.tar.gz.sha256'
+ }
+ });
+ });
+
+ it('should throw error when platform does not match', async () => {
+ const wrongPlatformVersions = [
+ {
+ version: '23-ea-20240716',
+ latest: true,
+ download_base_url: 'https://example.com/download/',
+ files: [
+ {
+ arch: 'x64',
+ platform: 'different-platform',
+ filename: 'graalvm-jdk-23_different-x64_bin.tar.gz'
+ }
+ ]
+ }
+ ];
+ fetchEASpy.mockResolvedValue(wrongPlatformVersions);
+
+ await expect(
+ (distribution as any).findEABuildDownloadUrl('23-ea')
+ ).rejects.toThrow(
+ `Unable to find file for architecture 'x64' and platform '${currentPlatform}'`
+ );
+ });
+ });
+
+ describe('fetchEAJson', () => {
+ it('should fetch and return EA version data', async () => {
+ const mockData = [{version: '23-ea', files: []}];
+ mockHttpClient.getJson.mockResolvedValue({
+ result: mockData,
+ statusCode: 200,
+ headers: {}
+ });
+
+ const result = await (distribution as any).fetchEAJson('23-ea');
- const unavailableEADistro = new GraalVMDistribution({
- version: '17-ea',
- architecture: '', // to get default value
- packageType: 'jdk',
- checkLatest: false
+ expect(mockHttpClient.getJson).toHaveBeenCalledWith(
+ 'https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/23-ea.json?ref=main',
+ {Accept: 'application/json'}
+ );
+ expect(result).toEqual(mockData);
+ expect(core.debug).toHaveBeenCalled();
+ });
+
+ it('should throw error when no data returned', async () => {
+ mockHttpClient.getJson.mockResolvedValue({
+ result: null,
+ statusCode: 200,
+ headers: {}
+ });
+
+ await expect((distribution as any).fetchEAJson('23-ea')).rejects.toThrow(
+ "No GraalVM EA build found for version '23-ea'. Please check if the version is correct."
+ );
+ });
+
+ it('should handle 404 errors with specific message', async () => {
+ const error404 = new Error('Not Found: 404');
+ mockHttpClient.getJson.mockRejectedValue(error404);
+
+ await expect((distribution as any).fetchEAJson('23-ea')).rejects.toThrow(
+ "GraalVM EA version '23-ea' not found. Please verify the version exists in the EA builds repository."
+ );
});
- await expect(
- unavailableEADistro['findPackageForDownload']('17')
- ).rejects.toThrow(
- /No GraalVM EA build found\. Are you sure java-version: '17-ea' is correct\?/
+
+ it('should handle generic HTTP errors with context', async () => {
+ const networkError = new Error('Network timeout');
+ mockHttpClient.getJson.mockRejectedValue(networkError);
+
+ await expect((distribution as any).fetchEAJson('23-ea')).rejects.toThrow(
+ "Failed to fetch GraalVM EA version information for '23-ea': Network timeout"
+ );
+ });
+
+ it('should handle non-Error exceptions', async () => {
+ mockHttpClient.getJson.mockRejectedValue('String error');
+
+ await expect((distribution as any).fetchEAJson('23-ea')).rejects.toThrow(
+ "Failed to fetch GraalVM EA version information for '23-ea'"
+ );
+ });
+ });
+
+ describe('Integration tests', () => {
+ it('should handle different architectures correctly', async () => {
+ const architectures = ['x64', 'aarch64'];
+
+ for (const arch of architectures) {
+ distribution = new GraalVMDistribution({
+ ...defaultOptions,
+ architecture: arch
+ });
+ (distribution as any).http = mockHttpClient;
+
+ const mockResponse = {
+ message: {statusCode: 200}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ const result = await (distribution as any).findPackageForDownload('17');
+ expect(result.url).toContain(arch);
+ }
+ });
+
+ it('should handle different platforms correctly', async () => {
+ const platforms = [
+ {process: 'darwin', expected: 'macos'},
+ {process: 'win32', expected: 'windows'},
+ {process: 'linux', expected: 'linux'}
+ ];
+
+ const originalPlatform = process.platform;
+
+ for (const {process: proc, expected} of platforms) {
+ Object.defineProperty(process, 'platform', {
+ value: proc,
+ configurable: true
+ });
+
+ distribution = new GraalVMDistribution(defaultOptions);
+ (distribution as any).http = mockHttpClient;
+
+ const mockResponse = {
+ message: {statusCode: 200}
+ } as any;
+ mockHttpClient.head.mockResolvedValue(mockResponse);
+
+ const result = await (distribution as any).findPackageForDownload('17');
+ expect(result.url).toContain(expected);
+ }
+
+ Object.defineProperty(process, 'platform', {
+ value: originalPlatform,
+ configurable: true
+ });
+ });
+
+ describe('GraalVMCommunityDistribution', () => {
+ beforeEach(() => {
+ jest
+ .spyOn(communityDistribution, 'getPlatform')
+ .mockReturnValue('linux');
+ });
+
+ it('should resolve an exact GraalVM Community version from GitHub releases', async () => {
+ mockHttpClient.getJson.mockResolvedValue({
+ result: [
+ {
+ draft: false,
+ prerelease: false,
+ assets: [
+ {
+ name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ browser_download_url:
+ 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
+ }
+ ]
+ }
+ ],
+ statusCode: 200,
+ headers: {}
+ });
+
+ const result = await (
+ communityDistribution as any
+ ).findPackageForDownload('21.0.2');
+
+ expect(result).toEqual({
+ url: 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ version: '21.0.2'
+ });
+ // The asset had no `digest` field, so no checksum should be attached,
+ // and the checksum sibling-URL fetch path (used by Oracle GraalVM)
+ // must not be consulted for GraalVM Community.
+ expect(result.checksum).toBeUndefined();
+ expect(mockHttpClient.get).not.toHaveBeenCalled();
+ });
+
+ it('strips the `sha256:` prefix from a GitHub release asset digest', async () => {
+ const digest = 'd'.repeat(64);
+ mockHttpClient.getJson.mockResolvedValue({
+ result: [
+ {
+ draft: false,
+ prerelease: false,
+ assets: [
+ {
+ name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ browser_download_url:
+ 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ digest: `sha256:${digest}`
+ }
+ ]
+ }
+ ],
+ statusCode: 200,
+ headers: {}
+ });
+
+ const result = await (
+ communityDistribution as any
+ ).findPackageForDownload('21.0.2');
+
+ expect(result.checksum).toEqual({
+ algorithm: 'sha256',
+ value: digest,
+ source:
+ 'https://api.github.com/repos/graalvm/graalvm-ce-builds/releases?per_page=100'
+ });
+ // The digest came from the release listing itself, so no additional
+ // HTTP request should be made to resolve the checksum.
+ expect(mockHttpClient.get).not.toHaveBeenCalled();
+ });
+
+ it('safely skips a missing or malformed release asset digest', async () => {
+ mockHttpClient.getJson.mockResolvedValue({
+ result: [
+ {
+ draft: false,
+ prerelease: false,
+ assets: [
+ {
+ name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ browser_download_url:
+ 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ digest: 'md5:not-a-sha256-digest'
+ }
+ ]
+ }
+ ],
+ statusCode: 200,
+ headers: {}
+ });
+
+ const result = await (
+ communityDistribution as any
+ ).findPackageForDownload('21.0.2');
+
+ expect(result.checksum).toBeUndefined();
+ expect(mockHttpClient.get).not.toHaveBeenCalled();
+ expect(core.debug).toHaveBeenCalledWith(
+ expect.stringContaining(
+ 'No authoritative sha256 digest is available for graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
+ )
+ );
+ });
+
+ it('should resolve the latest GraalVM Community release for a major version', async () => {
+ mockHttpClient.getJson.mockResolvedValue({
+ result: [
+ {
+ draft: false,
+ prerelease: false,
+ assets: [
+ {
+ name: 'graalvm-community-jdk-21.0.1_linux-x64_bin.tar.gz',
+ browser_download_url:
+ 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.1/graalvm-community-jdk-21.0.1_linux-x64_bin.tar.gz'
+ }
+ ]
+ },
+ {
+ draft: false,
+ prerelease: false,
+ assets: [
+ {
+ name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ browser_download_url:
+ 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
+ }
+ ]
+ }
+ ],
+ statusCode: 200,
+ headers: {}
+ });
+
+ const result = await (
+ communityDistribution as any
+ ).findPackageForDownload('21');
+
+ expect(result).toEqual({
+ url: 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ version: '21.0.2'
+ });
+ });
+
+ it('resolves latest to the newest GA across all Community majors without calling Adoptium', async () => {
+ const latestCommunity = new GraalVMCommunityDistribution({
+ ...defaultOptions,
+ version: 'latest'
+ });
+ (latestCommunity as any).http = mockHttpClient;
+ jest.spyOn(latestCommunity, 'getPlatform').mockReturnValue('linux');
+
+ mockHttpClient.getJson.mockResolvedValue({
+ result: [
+ {
+ draft: false,
+ prerelease: false,
+ assets: [
+ {
+ name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
+ browser_download_url:
+ 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
+ }
+ ]
+ },
+ {
+ draft: false,
+ prerelease: false,
+ assets: [
+ {
+ name: 'graalvm-community-jdk-24.0.1_linux-x64_bin.tar.gz',
+ browser_download_url:
+ 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-24.0.1/graalvm-community-jdk-24.0.1_linux-x64_bin.tar.gz'
+ }
+ ]
+ }
+ ],
+ statusCode: 200,
+ headers: {}
+ });
+
+ const result = await (latestCommunity as any).findPackageForDownload(
+ 'x'
+ );
+
+ expect(result).toEqual({
+ url: 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-24.0.1/graalvm-community-jdk-24.0.1_linux-x64_bin.tar.gz',
+ version: '24.0.1'
+ });
+ // The Community release list is authoritative, so the Adoptium
+ // most_recent_feature_release endpoint must not be consulted.
+ expect(mockHttpClient.getJson).toHaveBeenCalledTimes(1);
+ expect(mockHttpClient.getJson).toHaveBeenCalledWith(
+ expect.stringContaining('graalvm-ce-builds/releases'),
+ expect.anything()
+ );
+ });
+
+ it('should reject GraalVM Community early access requests', async () => {
+ (communityDistribution as any).stable = false;
+
+ await expect(
+ (communityDistribution as any).findPackageForDownload('23')
+ ).rejects.toThrow(
+ 'GraalVM Community does not provide early access builds'
+ );
+ });
+
+ it('should surface an error when the releases listing is not an array', async () => {
+ mockHttpClient.getJson.mockResolvedValue({
+ result: {message: 'API rate limit exceeded'},
+ statusCode: 403,
+ headers: {}
+ });
+
+ await expect(
+ (communityDistribution as any).findPackageForDownload('21')
+ ).rejects.toThrow(
+ /Unexpected response while listing GraalVM Community releases.*HTTP status code: 403/s
+ );
+ });
+ });
+ });
+});
+
+describe('distribution factory', () => {
+ const defaultOptions: JavaInstallerOptions = {
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ };
+
+ it('should map graalvm-community to the community installer', async () => {
+ const community = await getJavaDistribution(
+ 'graalvm-community',
+ defaultOptions
);
+
+ expect(community).toBeInstanceOf(GraalVMCommunityDistribution);
});
});
diff --git a/__tests__/distributors/jetbrains-installer.test.ts b/__tests__/distributors/jetbrains-installer.test.ts
index 241843cca..e9b49f76a 100644
--- a/__tests__/distributors/jetbrains-installer.test.ts
+++ b/__tests__/distributors/jetbrains-installer.test.ts
@@ -1,23 +1,108 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
import https from 'https';
-import {HttpClient} from '@actions/http-client';
-import {JetBrainsDistribution} from '../../src/distributions/jetbrains/installer';
+import {HttpClient, HttpClientResponse} from '@actions/http-client';
+import type {IncomingMessage} from 'http';
+import {Readable} from 'stream';
-import manifestData from '../data/jetbrains.json';
+import manifestData from '../data/jetbrains.json' with {type: 'json'};
import os from 'os';
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {JetBrainsDistribution} =
+ await import('../../src/distributions/jetbrains/installer.js');
+const {RetryingHttpClient} = await import('../../src/retrying-http-client.js');
+const {MAX_PAGINATION_PAGES} = await import('../../src/util.js');
+
+const JETBRAINS_RELEASES_URL =
+ 'https://api.github.com/repos/JetBrains/JetBrainsRuntime/releases?per_page=100';
+
+function release(tagName: string, prerelease: boolean) {
+ return {
+ tag_name: tagName,
+ name: tagName,
+ prerelease
+ };
+}
+
+function nextPageHeader(page: number) {
+ return {
+ link: `<${JETBRAINS_RELEASES_URL}&page=${page}>; rel="next"`
+ };
+}
+
+function response(
+ statusCode: number,
+ body = '',
+ headers: IncomingMessage['headers'] = {}
+): HttpClientResponse {
+ const message = Readable.from([Buffer.from(body)]) as IncomingMessage;
+ message.statusCode = statusCode;
+ message.headers = headers;
+ return new HttpClientResponse(message);
+}
+
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
+ const originalGitHubToken = process.env.GITHUB_TOKEN;
beforeEach(() => {
+ delete process.env.GITHUB_TOKEN;
+ (core.getInput as jest.Mock).mockReturnValue('');
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {},
result: []
});
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
+ if (originalGitHubToken === undefined) {
+ delete process.env.GITHUB_TOKEN;
+ } else {
+ process.env.GITHUB_TOKEN = originalGitHubToken;
+ }
jest.resetAllMocks();
jest.clearAllMocks();
jest.restoreAllMocks();
@@ -25,11 +110,17 @@ describe('getAvailableVersions', () => {
it('load available versions', async () => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
- spyHttpClient.mockReturnValueOnce({
- statusCode: 200,
- headers: {},
- result: manifestData as any
- });
+ spyHttpClient
+ .mockReturnValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: manifestData as any
+ })
+ .mockReturnValue({
+ statusCode: 200,
+ headers: {},
+ result: []
+ });
const distribution = new JetBrainsDistribution({
version: '17',
@@ -44,9 +135,284 @@ describe('getAvailableVersions', () => {
os.platform() === 'win32' ? manifestData.length : manifestData.length + 2;
expect(availableVersions.length).toBe(length);
}, 10_000);
+
+ it('continues a stable request after an all-prerelease page', async () => {
+ jest.spyOn(HttpClient.prototype, 'head').mockResolvedValue({
+ message: {statusCode: 200}
+ } as any);
+ spyHttpClient
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: nextPageHeader(2),
+ result: [release('jbr-release-26.0.0b1.1', true)]
+ })
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: [release('jbr-release-21.0.11b1163.116', false)]
+ });
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const availableVersions = await distribution['getAvailableVersions']();
+
+ expect(availableVersions.map(version => version.tag_name)).toContain(
+ 'jbr-release-21.0.11b1163.116'
+ );
+ expect(availableVersions.map(version => version.tag_name)).not.toContain(
+ 'jbr-release-26.0.0b1.1'
+ );
+ expect(spyHttpClient).toHaveBeenCalledTimes(2);
+ });
+
+ it('continues an EA request after an all-stable page', async () => {
+ jest.spyOn(HttpClient.prototype, 'head').mockResolvedValue({
+ message: {statusCode: 200}
+ } as any);
+ spyHttpClient
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: nextPageHeader(2),
+ result: [release('jbr-release-21.0.11b1163.116', false)]
+ })
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: [release('jbr-release-26.0.0b1.1', true)]
+ });
+ const distribution = new JetBrainsDistribution({
+ version: '26-ea',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const availableVersions = await distribution['getAvailableVersions']();
+
+ expect(availableVersions.map(version => version.tag_name)).toEqual([
+ 'jbr-release-26.0.0b1.1'
+ ]);
+ expect(spyHttpClient).toHaveBeenCalledTimes(2);
+ });
+
+ it('uses the token input for every paginated GitHub Releases request', async () => {
+ (core.getInput as jest.Mock).mockReturnValue('input-token');
+ spyHttpClient
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: nextPageHeader(2),
+ result: [release('jbr-release-21.0.11b1163.116', false)]
+ })
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: [release('jbr-release-21.0.10b1087.6', false)]
+ });
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenNthCalledWith(1, JETBRAINS_RELEASES_URL, {
+ Accept: 'application/vnd.github+json',
+ Authorization: 'Bearer input-token'
+ });
+ expect(spyHttpClient).toHaveBeenNthCalledWith(
+ 2,
+ `${JETBRAINS_RELEASES_URL}&page=2`,
+ {
+ Accept: 'application/vnd.github+json',
+ Authorization: 'Bearer input-token'
+ }
+ );
+ });
+
+ it('prefers the token input over the environment fallback', async () => {
+ (core.getInput as jest.Mock).mockReturnValue('input-token');
+ process.env.GITHUB_TOKEN = 'environment-token';
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenCalledWith(JETBRAINS_RELEASES_URL, {
+ Accept: 'application/vnd.github+json',
+ Authorization: 'Bearer input-token'
+ });
+ });
+
+ it('falls back to GITHUB_TOKEN when the token input is empty', async () => {
+ process.env.GITHUB_TOKEN = 'environment-token';
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenCalledWith(JETBRAINS_RELEASES_URL, {
+ Accept: 'application/vnd.github+json',
+ Authorization: 'Bearer environment-token'
+ });
+ });
+
+ it('omits authorization when no GitHub token is available', async () => {
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenCalledWith(JETBRAINS_RELEASES_URL, {
+ Accept: 'application/vnd.github+json'
+ });
+ });
+
+ it('stops pagination when a raw GitHub page is empty', async () => {
+ spyHttpClient
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: nextPageHeader(2),
+ result: [release('jbr-release-21.0.11b1163.116', false)]
+ })
+ .mockResolvedValueOnce({
+ statusCode: 200,
+ headers: nextPageHeader(3),
+ result: []
+ });
+ const distribution = new JetBrainsDistribution({
+ version: '26-ea',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenCalledTimes(2);
+ });
+
+ it('stops at the pagination safeguard', async () => {
+ spyHttpClient.mockResolvedValue({
+ statusCode: 200,
+ headers: nextPageHeader(2),
+ result: [release('jbr-release-21.0.11b1163.116', false)]
+ });
+ const distribution = new JetBrainsDistribution({
+ version: '26-ea',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const availableVersions = await distribution['getAvailableVersions']();
+
+ expect(availableVersions).toEqual([]);
+ expect(spyHttpClient).toHaveBeenCalledTimes(MAX_PAGINATION_PAGES);
+ expect(core.warning).toHaveBeenCalledWith(
+ `Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing JetBrains Runtime releases.`
+ );
+ });
+
+ it('ignores pagination links with an unexpected origin', async () => {
+ spyHttpClient.mockResolvedValueOnce({
+ statusCode: 200,
+ headers: {
+ link: '; rel="next"'
+ },
+ result: [release('jbr-release-21.0.11b1163.116', false)]
+ });
+ const distribution = new JetBrainsDistribution({
+ version: '26-ea',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenCalledTimes(1);
+ expect(core.warning).toHaveBeenCalledWith(
+ 'Ignoring pagination link with unexpected origin: https://example.com/releases?page=2'
+ );
+ });
+
+ it('retries a GitHub rate limit using Retry-After', async () => {
+ spyHttpClient.mockRestore();
+ const sleep = jest.fn(async () => undefined);
+ const requestRaw = jest
+ .spyOn(HttpClient.prototype, 'requestRaw')
+ .mockResolvedValueOnce(response(429, '', {'retry-after': '2'}))
+ .mockResolvedValueOnce(response(200, '[]'))
+ .mockResolvedValueOnce(response(200))
+ .mockResolvedValueOnce(response(200));
+ const distribution = new JetBrainsDistribution({
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['http'] = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0
+ });
+
+ const availableVersions = await distribution['getAvailableVersions']();
+
+ expect(availableVersions).toHaveLength(2);
+ expect(requestRaw).toHaveBeenCalledTimes(4);
+ expect(requestRaw.mock.calls[0][0].options.path).toBe(
+ requestRaw.mock.calls[1][0].options.path
+ );
+ expect(requestRaw.mock.calls[0][0].options.path).toContain(
+ '/repos/JetBrains/JetBrainsRuntime/releases'
+ );
+ expect(sleep).toHaveBeenCalledWith(2000);
+ expect(core.info).toHaveBeenCalledWith(
+ 'Request attempt 1 of 4 failed (HTTP 429); retrying in 2000 ms'
+ );
+ });
});
describe('findPackageForDownload', () => {
+ let spyHttpClientGet: any;
+
+ const JETBRAINS_CHECKSUM = 'c'.repeat(128);
+
+ beforeEach(() => {
+ // Every resolved release fetches `${url}.checksum` (sha512, GNU
+ // ` ` format); stub it so tests never reach the real
+ // network, except the dedicated 'version %s can be downloaded' test
+ // below which intentionally exercises real HTTPS HEAD requests.
+ spyHttpClientGet = jest
+ .spyOn(HttpClient.prototype, 'get')
+ .mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () => `${JETBRAINS_CHECKSUM} jbrsdk.tar.gz\n`
+ } as any);
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
it.each([
['17', '17.0.11+1207.24'],
['11.0', '11.0.16+2043.64'],
@@ -76,16 +442,31 @@ describe('findPackageForDownload', () => {
checkLatest: false
});
distribution['getAvailableVersions'] = async () => manifestData as any;
- const resolvedVersion = await distribution['findPackageForDownload'](
- input
- );
+ const resolvedVersion =
+ await distribution['findPackageForDownload'](input);
const url = resolvedVersion.url;
const options = {method: 'HEAD'};
- https.request(url, options, res => {
- // JetBrains uses 403 for inexistent packages
- expect(res.statusCode).not.toBe(403);
- res.resume();
+ await new Promise((resolve, reject) => {
+ const request = https.request(url, options, res => {
+ let assertionError: unknown;
+
+ try {
+ // JetBrains uses 403 for non-existent packages
+ expect(res.statusCode).not.toBe(403);
+ } catch (error) {
+ assertionError = error;
+ }
+
+ res.resume();
+ res.once('error', reject);
+ res.once('end', () =>
+ assertionError ? reject(assertionError as Error) : resolve()
+ );
+ });
+
+ request.on('error', reject);
+ request.end();
});
}
);
@@ -99,7 +480,7 @@ describe('findPackageForDownload', () => {
});
distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(distribution['findPackageForDownload']('8.x')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
+ /No matching version found for SemVer */
);
});
@@ -112,7 +493,75 @@ describe('findPackageForDownload', () => {
});
distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
+ /No matching version found for SemVer */
);
});
+
+ it('fetches the authoritative sha512 checksum only for the resolved version', async () => {
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getAvailableVersions'] = async () => manifestData as any;
+
+ const result = await distribution['findPackageForDownload']('21');
+
+ expect(result.checksum).toEqual({
+ algorithm: 'sha512',
+ value: JETBRAINS_CHECKSUM,
+ source: `${result.url}.checksum`
+ });
+ // Only the single resolved/winning version's checksum is requested,
+ // not one per candidate considered during version resolution.
+ expect(spyHttpClientGet).toHaveBeenCalledWith(`${result.url}.checksum`);
+ expect(spyHttpClientGet).toHaveBeenCalledTimes(1);
+ });
+
+ it('parses only the first whitespace-delimited token from the GNU checksum payload', async () => {
+ spyHttpClientGet.mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () => `${JETBRAINS_CHECKSUM} jbrsdk-21.tar.gz\n`
+ } as any);
+
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getAvailableVersions'] = async () => manifestData as any;
+
+ const result = await distribution['findPackageForDownload']('21');
+
+ expect(result.checksum?.value).toBe(JETBRAINS_CHECKSUM);
+ });
+
+ it('falls back to a sha256 checksum for older JBR builds that only publish one', async () => {
+ // Older JBR 11 builds (e.g. jbrsdk_nomod-11_0_16-*-b2043.64.tar.gz) publish
+ // a SHA-256 digest at the generic `.checksum` sibling instead of SHA-512.
+ const sha256Checksum = 'a'.repeat(64);
+ spyHttpClientGet.mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () =>
+ `${sha256Checksum} jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz\n`
+ } as any);
+
+ const distribution = new JetBrainsDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getAvailableVersions'] = async () => manifestData as any;
+
+ const result = await distribution['findPackageForDownload']('21');
+
+ expect(result.checksum).toEqual({
+ algorithm: 'sha256',
+ value: sha256Checksum,
+ source: `${result.url}.checksum`
+ });
+ });
});
diff --git a/__tests__/distributors/kona-installer.test.ts b/__tests__/distributors/kona-installer.test.ts
new file mode 100644
index 000000000..ba5a83266
--- /dev/null
+++ b/__tests__/distributors/kona-installer.test.ts
@@ -0,0 +1,265 @@
+import {KonaDistribution} from '../../src/distributions/kona/installer.js';
+
+import manifestData from '../data/kona.json' with {type: 'json'};
+
+function mockDistr(
+ version: string,
+ os: string,
+ arch: string,
+ packageType: string
+): KonaDistribution {
+ const distribution = new KonaDistribution({
+ version: version,
+ architecture: arch,
+ packageType: packageType,
+ checkLatest: false
+ });
+
+ distribution['getOs'] = () => os;
+ distribution['fetchReleaseInfo'] = async () => manifestData;
+
+ return distribution;
+}
+
+describe('Check getAvailableReleases', () => {
+ it.each([
+ ['8', 'linux', 'aarch64', 'linux-aarch64'],
+ ['8.0.20', 'macos', 'x86_64', 'macosx-x86_64'],
+ ['11', 'linux', 'x86_64', 'linux-x86_64'],
+ ['11.0.25', 'macos', 'aarch64', 'macosx-aarch64'],
+ ['17.0.13', 'windows', 'x86_64', 'windows-x86_64'],
+ ['21.0.5', 'linux', 'x86_64', 'linux-x86_64'],
+ ['25', 'linux', 'aarch64', 'linux-aarch64'],
+ ['25.0.3', 'macos', 'x86_64', 'macosx-x86_64']
+ ])(
+ 'should get releases with the specified version "%s", OS "%s" and arch "%s"',
+ async (
+ version: string,
+ os: string,
+ arch: string,
+ expectedPattern: string
+ ) => {
+ const distribution = mockDistr(version, os, arch, 'jdk');
+
+ const releases = await distribution['getAvailableReleases']();
+ expect(releases).not.toBeNull();
+ expect(releases.length).toBe(5);
+ releases.forEach(release =>
+ expect(release.downloadUrl).toContain(expectedPattern)
+ );
+ }
+ );
+});
+
+describe('Check findPackageForDownload', () => {
+ it.each([
+ [
+ '8',
+ 'linux',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_linux-aarch64_8u432.tar.gz'
+ ],
+ [
+ '8.0.20',
+ 'linux',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_linux-x86_64_8u432.tar.gz'
+ ],
+ [
+ '8.0.20',
+ 'macos',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_macosx-aarch64_8u432_notarized.tar.gz'
+ ],
+ [
+ '8.0.20',
+ 'macos',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_macosx-x86_64_8u432_notarized.tar.gz'
+ ],
+ [
+ '8.0.20',
+ 'windows',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_windows-x86_64_8u432_signed.zip'
+ ],
+
+ [
+ '11',
+ 'linux',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1-jdk_linux-aarch64.tar.gz'
+ ],
+ [
+ '11.0.25',
+ 'linux',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1-jdk_linux-x86_64.tar.gz'
+ ],
+ [
+ '11.0.25',
+ 'macos',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1_jdk_macosx-aarch64_notarized.tar.gz'
+ ],
+ [
+ '11.0.25',
+ 'macos',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1_jdk_macosx-x86_64_notarized.tar.gz'
+ ],
+ [
+ '11.0.25',
+ 'windows',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1_jdk_windows-x86_64_signed.zip'
+ ],
+
+ [
+ '17',
+ 'linux',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1-jdk_linux-aarch64.tar.gz'
+ ],
+ [
+ '17.0.13',
+ 'linux',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1-jdk_linux-x86_64.tar.gz'
+ ],
+ [
+ '17.0.13',
+ 'macos',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1_jdk_macosx-aarch64_notarized.tar.gz'
+ ],
+ [
+ '17.0.13',
+ 'macos',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1_jdk_macosx-x86_64_notarized.tar.gz'
+ ],
+ [
+ '17.0.13',
+ 'windows',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1_jdk_windows-x86_64_signed.zip'
+ ],
+
+ [
+ '21',
+ 'linux',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1-jdk_linux-aarch64.tar.gz'
+ ],
+ [
+ '21.0.5',
+ 'linux',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1-jdk_linux-x86_64.tar.gz'
+ ],
+ [
+ '21.0.5',
+ 'macos',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1_jdk_macosx-aarch64_notarized.tar.gz'
+ ],
+ [
+ '21.0.5',
+ 'macos',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1_jdk_macosx-x86_64_notarized.tar.gz'
+ ],
+ [
+ '21.0.5',
+ 'windows',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1_jdk_windows-x86_64_signed.zip'
+ ],
+
+ [
+ '25',
+ 'linux',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1-jdk_linux-aarch64.tar.gz'
+ ],
+ [
+ '25.0.3',
+ 'linux',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1-jdk_linux-x86_64.tar.gz'
+ ],
+ [
+ '25.0.3',
+ 'macos',
+ 'aarch64',
+ 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_macosx-aarch64_notarized.tar.gz'
+ ],
+ [
+ '25.0.3',
+ 'macos',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_macosx-x86_64_notarized.tar.gz'
+ ],
+ [
+ '25.0.3',
+ 'windows',
+ 'x86_64',
+ 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_windows-x86_64_signed.zip'
+ ]
+ ])(
+ 'should return the download URL with the specified version "%s", OS "%s" and arch "%s"',
+ async (version: string, os: string, arch: string, expectedUrl: string) => {
+ const distribution = mockDistr(version, os, arch, 'jdk');
+
+ const availableRelease =
+ await distribution['findPackageForDownload'](version);
+ expect(availableRelease).not.toBeNull();
+ expect(availableRelease.url).toBe(expectedUrl);
+ if (availableRelease.checksum) {
+ expect(availableRelease.checksum).toEqual({
+ algorithm: 'sha256',
+ value: expect.stringMatching(/^[a-f0-9]{64}$/),
+ source: 'https://tencent.github.io/konajdk/releases/kona-v1.json'
+ });
+ } else {
+ expect(version).toBe('8.0.20');
+ }
+ }
+ );
+});
+
+describe('No release is found', () => {
+ it.each([
+ ['8', 'linux', 'x86'],
+ ['8.0.0', 'linux', 'x86_64'],
+ ['11', 'linux', 'ppc64'],
+ ['17', 'solaris', 'x86_64'],
+ ['17', 'windows', 'aarch64'],
+ ['22', 'macos', 'x86_64']
+ ])(
+ `should throw an error due to no release with the specified version "%s", os "%s" and arch "%s"`,
+ async (version: string, os: string, arch: string) => {
+ const distribution = mockDistr(version, os, arch, 'jdk');
+
+ await expect(
+ distribution['findPackageForDownload'](version)
+ ).rejects.toThrow(
+ `No Kona release for the specified version "${version}" on OS "${os}" and arch "${arch}".`
+ );
+ }
+ );
+});
+
+describe('The package type must be jdk', () => {
+ it('should throw an error due to the specified package type is not jdk', async () => {
+ const version = '8.0.20';
+ const os = 'linux';
+ const arch = 'x86_64';
+ const distribution = mockDistr(version, os, arch, 'jre');
+
+ await expect(
+ distribution['findPackageForDownload'](version)
+ ).rejects.toThrow('Kona provides jdk only');
+ });
+});
diff --git a/__tests__/distributors/liberica-installer.test.ts b/__tests__/distributors/liberica-installer.test.ts
index 5e664d5f3..ab1b72b2d 100644
--- a/__tests__/distributors/liberica-installer.test.ts
+++ b/__tests__/distributors/liberica-installer.test.ts
@@ -1,15 +1,57 @@
-import {LibericaDistributions} from '../../src/distributions/liberica/installer';
import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import fs from 'fs';
+import type {
ArchitectureOptions,
LibericaVersion
-} from '../../src/distributions/liberica/models';
+} from '../../src/distributions/liberica/models.js';
import {HttpClient} from '@actions/http-client';
import os from 'os';
-import manifestData from '../data/liberica.json';
+import manifestData from '../data/liberica.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {LibericaDistributions} =
+ await import('../../src/distributions/liberica/installer.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +60,10 @@ describe('getAvailableVersions', () => {
headers: {},
result: manifestData as LibericaVersion[]
});
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -178,7 +224,7 @@ describe('getArchitectureOptions', () => {
});
describe('findPackageForDownload', () => {
- let distribution: LibericaDistributions;
+ let distribution: InstanceType;
beforeEach(() => {
distribution = new LibericaDistributions({
@@ -209,12 +255,22 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('17')).rejects.toThrow(
- /Could not find satisfied version for semver */
+ /No matching version found for SemVer/
);
});
});
describe('getPlatformOption', () => {
+ beforeEach(() => {
+ // The linux row below is glibc, so pin the Alpine probe rather than
+ // letting it depend on the machine running the suite.
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
const distributions = new LibericaDistributions({
architecture: 'x64',
version: '11',
@@ -290,3 +346,35 @@ describe('convertVersionToSemver', () => {
expect(actual).toEqual(expected);
});
});
+
+describe('Liberica getPlatformOption libc selection', () => {
+ const distributions = new LibericaDistributions({
+ architecture: 'x64',
+ version: '11',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('selects the musl artifacts on Alpine', () => {
+ jest.spyOn(fs, 'existsSync').mockReturnValue(true);
+
+ expect(distributions['getPlatformOption']('linux')).toBe('linux-musl');
+ });
+
+ it('selects the glibc artifacts on other Linux runners', () => {
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+
+ expect(distributions['getPlatformOption']('linux')).toBe('linux');
+ });
+
+ it('does not probe for Alpine off Linux', () => {
+ const existsSync = jest.spyOn(fs, 'existsSync');
+
+ expect(distributions['getPlatformOption']('darwin')).toBe('macos');
+ expect(existsSync).not.toHaveBeenCalled();
+ });
+});
diff --git a/__tests__/distributors/liberica-linux-installer.test.ts b/__tests__/distributors/liberica-linux-installer.test.ts
index 58c4e4781..8ecb5b452 100644
--- a/__tests__/distributors/liberica-linux-installer.test.ts
+++ b/__tests__/distributors/liberica-linux-installer.test.ts
@@ -1,15 +1,56 @@
-import {LibericaDistributions} from '../../src/distributions/liberica/installer';
import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import type {
ArchitectureOptions,
LibericaVersion
-} from '../../src/distributions/liberica/models';
+} from '../../src/distributions/liberica/models.js';
import {HttpClient} from '@actions/http-client';
import os from 'os';
-import manifestData from '../data/liberica-linux.json';
+import manifestData from '../data/liberica-linux.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {LibericaDistributions} =
+ await import('../../src/distributions/liberica/installer.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +59,10 @@ describe('getAvailableVersions', () => {
headers: {},
result: manifestData as LibericaVersion[]
});
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -178,7 +223,7 @@ describe('getArchitectureOptions', () => {
});
describe('findPackageForDownload', () => {
- let distribution: LibericaDistributions;
+ let distribution: InstanceType;
beforeEach(() => {
distribution = new LibericaDistributions({
@@ -209,7 +254,7 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('18')).rejects.toThrow(
- /Could not find satisfied version for semver */
+ /No matching version found for SemVer/
);
});
});
diff --git a/__tests__/distributors/liberica-nik-installer.test.ts b/__tests__/distributors/liberica-nik-installer.test.ts
new file mode 100644
index 000000000..8f1c9ae22
--- /dev/null
+++ b/__tests__/distributors/liberica-nik-installer.test.ts
@@ -0,0 +1,262 @@
+import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
+import fs from 'fs';
+import type {
+ ArchitectureOptions,
+ NikVersion
+} from '../../src/distributions/liberica-nik/models.js';
+import {HttpClient} from '@actions/http-client';
+
+import manifestData from '../data/liberica-nik.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const {LibericaNikDistributions} =
+ await import('../../src/distributions/liberica-nik/installer.js');
+
+const ADDITIONAL_PARAMS =
+ '&installation-type=archive&fields=downloadUrl%2Cversion%2Ccomponents%2Ccomponent%2Cembedded';
+
+describe('getAvailableVersions', () => {
+ let spyHttpClient: any;
+
+ beforeEach(() => {
+ spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
+ spyHttpClient.mockReturnValue({
+ statusCode: 200,
+ headers: {},
+ result: manifestData as NikVersion[]
+ });
+ });
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ jest.clearAllMocks();
+ jest.restoreAllMocks();
+ });
+
+ it.each([
+ [
+ {version: '21', architecture: 'x64', packageType: 'jdk'},
+ 'bundle-type=standard&bitness=64&arch=x86&build-type=all'
+ ],
+ [
+ {version: '21-ea', architecture: 'x64', packageType: 'jdk'},
+ 'bundle-type=standard&bitness=64&arch=x86&build-type=ea'
+ ],
+ [
+ {version: '21', architecture: 'aarch64', packageType: 'jdk'},
+ 'bundle-type=standard&bitness=64&arch=arm&build-type=all'
+ ],
+ [
+ {version: '21', architecture: 'x64', packageType: 'jdk+fx'},
+ 'bundle-type=full&bitness=64&arch=x86&build-type=all'
+ ]
+ ])('build correct url for %s -> %s', async (input, urlParams) => {
+ const distribution = new LibericaNikDistributions({
+ ...input,
+ checkLatest: false
+ });
+ distribution['getPlatformOption'] = () => 'linux';
+ const buildUrl = `https://api.bell-sw.com/v1/nik/releases?os=linux&${urlParams}${ADDITIONAL_PARAMS}`;
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient.mock.calls).toHaveLength(1);
+ expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
+ });
+
+ it('load available versions', async () => {
+ const distribution = new LibericaNikDistributions({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ const availableVersions = await distribution['getAvailableVersions']();
+ expect(availableVersions).toEqual(manifestData);
+ });
+});
+
+describe('getArchitectureOptions', () => {
+ it.each([
+ ['x64', {bitness: '64', arch: 'x86'}],
+ ['aarch64', {bitness: '64', arch: 'arm'}]
+ ] as [string, ArchitectureOptions][])(
+ 'parse architecture %s -> %s',
+ (input, expected) => {
+ const distributions = new LibericaNikDistributions({
+ architecture: input,
+ checkLatest: false,
+ packageType: 'jdk',
+ version: '21'
+ });
+
+ expect(distributions['getArchitectureOptions']()).toEqual(expected);
+ }
+ );
+
+ it.each(['x86', 'armv7', 's390x'])('not support architecture %s', input => {
+ const distributions = new LibericaNikDistributions({
+ architecture: input,
+ checkLatest: false,
+ packageType: 'jdk',
+ version: '21'
+ });
+
+ expect(() => distributions['getArchitectureOptions']()).toThrow(
+ /Architecture '\w+' is not supported\. Supported architectures: .*/
+ );
+ });
+});
+
+describe('findPackageForDownload', () => {
+ let distribution: InstanceType;
+
+ beforeEach(() => {
+ distribution = new LibericaNikDistributions({
+ version: '',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getAvailableVersions'] = async () => manifestData;
+ });
+
+ // The user's java-version resolves against the embedded JDK version, not
+ // NIK's own GraalVM version.
+ it.each([
+ ['21', '21.0.11+12'],
+ ['17', '17.0.19+12'],
+ ['25', '25.0.3+12'],
+ ['11', '11.0.22+12'],
+ ['21.0.2', '21.0.2+14'],
+ ['23', '23.0.2+9'],
+ ['20.x', '20.0.2+10'],
+ ['25.0.1', '25.0.1+16']
+ ])('version is %s -> %s', async (input, expected) => {
+ const result = await distribution['findPackageForDownload'](input);
+ expect(result.version).toBe(expected);
+ });
+
+ it('should throw an error', async () => {
+ await expect(distribution['findPackageForDownload']('7')).rejects.toThrow(
+ /No matching version found for SemVer/
+ );
+ });
+});
+
+describe('getPlatformOption', () => {
+ beforeEach(() => {
+ // The linux row below is glibc, so pin the Alpine probe rather than
+ // letting it depend on the machine running the suite.
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ const distributions = new LibericaNikDistributions({
+ architecture: 'x64',
+ version: '21',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ it.each([
+ ['linux', 'linux'],
+ ['darwin', 'macos'],
+ ['win32', 'windows'],
+ ['cygwin', 'windows']
+ ])('os version %s -> %s', (input, expected) => {
+ const actual = distributions['getPlatformOption'](input as NodeJS.Platform);
+
+ expect(actual).toEqual(expected);
+ });
+
+ it.each(['sunos', 'aix', 'android', 'freebsd'])(
+ 'not support os version %s',
+ input => {
+ expect(() =>
+ distributions['getPlatformOption'](input as NodeJS.Platform)
+ ).toThrow(/Platform '\w+' is not supported\. Supported platforms: .+/);
+ }
+ );
+});
+
+describe('convertVersionToSemver', () => {
+ const distributions = new LibericaNikDistributions({
+ architecture: 'x64',
+ version: '21',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ it.each([
+ ['25.0.1+16', '25.0.1+16'],
+ ['21+37', '21.0.0+37'],
+ ['23+38', '23.0.0+38'],
+ ['11.0.15.1+2', '11.0.15+1.2'],
+ ['17.0.5', '17.0.5']
+ ])('%s -> %s', (input, expected) => {
+ const actual = distributions['convertVersionToSemver'](input);
+ expect(actual).toEqual(expected);
+ });
+});
+
+describe('Liberica NIK getPlatformOption libc selection', () => {
+ const distributions = new LibericaNikDistributions({
+ architecture: 'x64',
+ version: '21',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('selects the musl artifacts on Alpine', () => {
+ jest.spyOn(fs, 'existsSync').mockReturnValue(true);
+
+ expect(distributions['getPlatformOption']('linux')).toBe('linux-musl');
+ });
+
+ it('selects the glibc artifacts on other Linux runners', () => {
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+
+ expect(distributions['getPlatformOption']('linux')).toBe('linux');
+ });
+
+ it('does not probe for Alpine off Linux', () => {
+ const existsSync = jest.spyOn(fs, 'existsSync');
+
+ expect(distributions['getPlatformOption']('darwin')).toBe('macos');
+ expect(existsSync).not.toHaveBeenCalled();
+ });
+});
diff --git a/__tests__/distributors/liberica-windows-installer.test.ts b/__tests__/distributors/liberica-windows-installer.test.ts
index 22d287410..a4fe5f591 100644
--- a/__tests__/distributors/liberica-windows-installer.test.ts
+++ b/__tests__/distributors/liberica-windows-installer.test.ts
@@ -1,15 +1,56 @@
-import {LibericaDistributions} from '../../src/distributions/liberica/installer';
import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import type {
ArchitectureOptions,
LibericaVersion
-} from '../../src/distributions/liberica/models';
+} from '../../src/distributions/liberica/models.js';
import {HttpClient} from '@actions/http-client';
import os from 'os';
-import manifestData from '../data/liberica-windows.json';
+import manifestData from '../data/liberica-windows.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {LibericaDistributions} =
+ await import('../../src/distributions/liberica/installer.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +59,9 @@ describe('getAvailableVersions', () => {
headers: {},
result: manifestData as LibericaVersion[]
});
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -178,7 +222,7 @@ describe('getArchitectureOptions', () => {
});
describe('findPackageForDownload', () => {
- let distribution: LibericaDistributions;
+ let distribution: InstanceType;
beforeEach(() => {
distribution = new LibericaDistributions({
@@ -209,7 +253,7 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('18')).rejects.toThrow(
- /Could not find satisfied version for semver */
+ /No matching version found for SemVer/
);
});
});
diff --git a/__tests__/distributors/local-installer.test.ts b/__tests__/distributors/local-installer.test.ts
index 8e9d5d437..f20ff6ad4 100644
--- a/__tests__/distributors/local-installer.test.ts
+++ b/__tests__/distributors/local-installer.test.ts
@@ -1,36 +1,114 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
import fs from 'fs';
-import * as tc from '@actions/tool-cache';
-import * as core from '@actions/core';
-
import path from 'path';
import * as semver from 'semver';
-import * as util from '../../src/util';
-
-import {LocalDistribution} from '../../src/distributions/local/installer';
+import os from 'os';
+
+const realStatSync = fs.statSync;
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+jest.unstable_mockModule('@actions/tool-cache', () => ({
+ find: jest.fn(),
+ findAllVersions: jest.fn(),
+ downloadTool: jest.fn(),
+ extractZip: jest.fn(),
+ extractTar: jest.fn(),
+ extract7z: jest.fn(),
+ extractXar: jest.fn(),
+ cacheDir: jest.fn(),
+ cacheFile: jest.fn(),
+ getManifestFromRepo: jest.fn(),
+ findFromManifest: jest.fn(),
+ evaluateVersions: jest.fn()
+}));
+
+jest.unstable_mockModule('../../src/jdk-cache.js', () => ({
+ getJdkVerificationIdentity: jest.fn(() => 'unverified'),
+ registerJdk: jest.fn(),
+ restoreJdk: jest.fn()
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ extractJdkFile: jest.fn(),
+ getDownloadArchiveExtension: jest.fn(),
+ getToolcachePath: jest.fn(),
+ isJobStatusSuccess: jest.fn(),
+ renameWinArchive: jest.fn(),
+ isVersionSatisfies: real_util_module.isVersionSatisfies,
+ getTempDir: real_util_module.getTempDir
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const tc = await import('@actions/tool-cache');
+const util = await import('../../src/util.js');
+const jdkCache = await import('../../src/jdk-cache.js');
+const {LocalDistribution} =
+ await import('../../src/distributions/local/installer.js');
describe('setupJava', () => {
const actualJavaVersion = '11.1.10';
const javaPath = path.join('Java_jdkfile_jdk', actualJavaVersion, 'x86');
- let mockJavaBase: LocalDistribution;
-
- let spyGetToolcachePath: jest.SpyInstance;
- let spyTcCacheDir: jest.SpyInstance;
- let spyTcFindAllVersions: jest.SpyInstance;
- let spyCoreDebug: jest.SpyInstance;
- let spyCoreInfo: jest.SpyInstance;
- let spyCoreExportVariable: jest.SpyInstance;
- let spyCoreAddPath: jest.SpyInstance;
- let spyCoreSetOutput: jest.SpyInstance;
- let spyFsStat: jest.SpyInstance;
- let spyFsReadDir: jest.SpyInstance;
- let spyUtilsExtractJdkFile: jest.SpyInstance;
- let spyPathResolve: jest.SpyInstance;
+ let mockJavaBase: InstanceType;
+
+ let spyGetToolcachePath: any;
+ let spyTcCacheDir: any;
+ let spyTcFindAllVersions: any;
+ let spyCoreDebug: any;
+ let spyCoreInfo: any;
+ let spyCoreExportVariable: any;
+ let spyCoreAddPath: any;
+ let spyCoreSetOutput: any;
+ let spyFsStat: any;
+ let spyFsReadDir: any;
+ let spyUtilsExtractJdkFile: any;
+ let spyPathResolve: any;
+ let spyCoreError: any;
const expectedJdkFile = 'JavaLocalJdkFile';
beforeEach(() => {
- spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
+ (jdkCache.getJdkVerificationIdentity as jest.Mock).mockReturnValue(
+ 'unverified'
+ );
+ spyGetToolcachePath = util.getToolcachePath as jest.Mock;
spyGetToolcachePath.mockImplementation(
(toolname: string, javaVersion: string, architecture: string) => {
const semverVersion = new semver.Range(javaVersion);
@@ -48,7 +126,7 @@ describe('setupJava', () => {
}
);
- spyTcCacheDir = jest.spyOn(tc, 'cacheDir');
+ spyTcCacheDir = tc.cacheDir as jest.Mock;
spyTcCacheDir.mockImplementation(
(
archivePath: string,
@@ -58,23 +136,23 @@ describe('setupJava', () => {
) => path.join(toolcacheFolderName, version, architecture)
);
- spyTcFindAllVersions = jest.spyOn(tc, 'findAllVersions');
+ spyTcFindAllVersions = tc.findAllVersions as jest.Mock;
spyTcFindAllVersions.mockReturnValue([actualJavaVersion]);
// Spy on core methods
- spyCoreDebug = jest.spyOn(core, 'debug');
+ spyCoreDebug = core.debug as jest.Mock;
spyCoreDebug.mockImplementation(() => undefined);
- spyCoreInfo = jest.spyOn(core, 'info');
+ spyCoreInfo = core.info as jest.Mock;
spyCoreInfo.mockImplementation(() => undefined);
- spyCoreAddPath = jest.spyOn(core, 'addPath');
+ spyCoreAddPath = core.addPath as jest.Mock;
spyCoreAddPath.mockImplementation(() => undefined);
- spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
+ spyCoreExportVariable = core.exportVariable as jest.Mock;
spyCoreExportVariable.mockImplementation(() => undefined);
- spyCoreSetOutput = jest.spyOn(core, 'setOutput');
+ spyCoreSetOutput = core.setOutput as jest.Mock;
spyCoreSetOutput.mockImplementation(() => undefined);
// Spy on fs methods
@@ -87,12 +165,16 @@ describe('setupJava', () => {
});
// Spy on util methods
- spyUtilsExtractJdkFile = jest.spyOn(util, 'extractJdkFile');
+ spyUtilsExtractJdkFile = util.extractJdkFile as jest.Mock;
spyUtilsExtractJdkFile.mockImplementation(() => 'some/random/path/');
// Spy on path methods
spyPathResolve = jest.spyOn(path, 'resolve');
spyPathResolve.mockImplementation((path: string) => path);
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -101,6 +183,20 @@ describe('setupJava', () => {
jest.restoreAllMocks();
});
+ it('throws for the latest alias since jdkfile has no version list', async () => {
+ const inputs = {
+ version: 'latest',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false
+ };
+
+ mockJavaBase = new LocalDistribution(inputs, expectedJdkFile);
+ await expect(mockJavaBase.setupJava()).rejects.toThrow(
+ "The 'latest' version alias is not supported for the 'jdkfile' distribution. Please specify a concrete version."
+ );
+ });
+
it('java is resolved from toolcache, jdkfile is untouched', async () => {
const inputs = {
version: actualJavaVersion,
@@ -125,6 +221,95 @@ describe('setupJava', () => {
);
});
+ it('java is unpacked from jdkfile when force-download is enabled', async () => {
+ const inputs = {
+ version: actualJavaVersion,
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ forceDownload: true
+ };
+
+ mockJavaBase = new LocalDistribution(inputs, expectedJdkFile);
+ await expect(mockJavaBase.setupJava()).resolves.toEqual({
+ version: actualJavaVersion,
+ path: javaPath
+ });
+
+ expect(spyGetToolcachePath).not.toHaveBeenCalled();
+ expect(spyUtilsExtractJdkFile).toHaveBeenCalledWith(expectedJdkFile);
+ expect(spyTcCacheDir).toHaveBeenCalled();
+ expect(spyCoreInfo).not.toHaveBeenCalledWith(
+ `Resolved Java ${actualJavaVersion} from tool-cache`
+ );
+ });
+
+ it.each([
+ [false, true, true],
+ [true, false, true]
+ ])(
+ 'handles jdkfile caching with force-download=%s',
+ async (forceDownload, restores, registers) => {
+ const temporaryDirectory = fs.mkdtempSync(
+ path.join(os.tmpdir(), 'setup-java-local-cache-')
+ );
+ const jdkFile = path.join(temporaryDirectory, 'java.tar.gz');
+ fs.writeFileSync(jdkFile, 'jdk archive');
+ spyGetToolcachePath.mockReturnValue('');
+ spyFsStat.mockImplementation((file: string) => realStatSync(file));
+ (jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
+
+ try {
+ mockJavaBase = new LocalDistribution(
+ {
+ version: actualJavaVersion,
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ forceDownload,
+ cacheJdk: true
+ },
+ jdkFile
+ );
+
+ await mockJavaBase.setupJava();
+
+ expect(jdkCache.restoreJdk).toHaveBeenCalledTimes(restores ? 1 : 0);
+ expect(jdkCache.registerJdk).toHaveBeenCalledTimes(registers ? 1 : 0);
+ expect(
+ (jdkCache.restoreJdk as jest.Mock).mock.calls[0]?.[0] ??
+ (jdkCache.registerJdk as jest.Mock).mock.calls[0]?.[0]
+ ).toEqual(
+ expect.objectContaining({
+ distribution: 'jdkfile',
+ version: actualJavaVersion,
+ verification: 'unverified'
+ })
+ );
+ } finally {
+ fs.rmSync(temporaryDirectory, {recursive: true});
+ }
+ }
+ );
+
+ it('rejects signature verification for jdkfile archives', async () => {
+ mockJavaBase = new LocalDistribution(
+ {
+ version: actualJavaVersion,
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true
+ },
+ expectedJdkFile
+ );
+
+ await expect(mockJavaBase.setupJava()).rejects.toThrow(
+ "Input 'verify-signature' is not supported for distribution 'jdkfile'."
+ );
+ expect(spyGetToolcachePath).not.toHaveBeenCalled();
+ });
+
it("java is resolved from toolcache, jdkfile doesn't exist", async () => {
const inputs = {
version: actualJavaVersion,
@@ -214,7 +399,7 @@ describe('setupJava', () => {
);
});
- it('java is resolved from toolcache including Contents/Home on MacOS', async () => {
+ it('java is resolved from toolcache including Contents/Home on macOS', async () => {
const inputs = {
version: actualJavaVersion,
architecture: 'x86',
@@ -257,7 +442,7 @@ describe('setupJava', () => {
});
});
- it('java is unpacked from jdkfile including Contents/Home on MacOS', async () => {
+ it('java is unpacked from jdkfile including Contents/Home on macOS', async () => {
const inputs = {
version: '11.0.289',
architecture: 'x86',
diff --git a/__tests__/distributors/microsoft-installer.test.ts b/__tests__/distributors/microsoft-installer.test.ts
index 3e22b9021..8e0747ac5 100644
--- a/__tests__/distributors/microsoft-installer.test.ts
+++ b/__tests__/distributors/microsoft-installer.test.ts
@@ -1,15 +1,118 @@
-import {MicrosoftDistributions} from '../../src/distributions/microsoft/installer';
-import os from 'os';
-import data from '../data/microsoft.json';
-import * as httpm from '@actions/http-client';
-import * as core from '@actions/core';
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import {HttpClient} from '@actions/http-client';
+import data from '../data/microsoft.json' with {type: 'json'};
+
+const mockOsArch = jest.fn(() => 'x64');
+const mockOsPlatform = jest.fn(() => 'linux');
+
+const real_os_module = await import('os');
+jest.unstable_mockModule('os', () => ({
+ ...real_os_module,
+ default: {
+ ...real_os_module.default,
+ arch: mockOsArch,
+ platform: mockOsPlatform,
+ homedir: real_os_module.default.homedir
+ },
+ arch: mockOsArch,
+ platform: mockOsPlatform
+}));
+
+const real_fs_module = await import('fs');
+const mockReaddirSync = jest.fn();
+jest.unstable_mockModule('fs', () => ({
+ ...real_fs_module,
+ default: {
+ ...real_fs_module.default,
+ readdirSync: mockReaddirSync
+ },
+ readdirSync: mockReaddirSync
+}));
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_tc_module = await import('@actions/tool-cache');
+jest.unstable_mockModule('@actions/tool-cache', () => ({
+ ...real_tc_module,
+ downloadTool: jest.fn(),
+ cacheDir: jest.fn(),
+ cacheFile: jest.fn()
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ extractJdkFile: jest.fn(),
+ getDownloadArchiveExtension: jest.fn(),
+ getToolcachePath: jest.fn(),
+ isJobStatusSuccess: jest.fn(),
+ renameWinArchive: jest.fn(),
+ isVersionSatisfies: real_util_module.isVersionSatisfies,
+ getTempDir: real_util_module.getTempDir
+}));
+
+jest.unstable_mockModule('../../src/gpg.js', () => ({
+ importKey: jest.fn(),
+ removeGpgHome: jest.fn(),
+ verifyPackageSignature: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const gpg = await import('../../src/gpg.js');
+const tc = await import('@actions/tool-cache');
+const os = (await import('os')).default;
+const fs = (await import('fs')).default;
+const {MicrosoftDistributions, MICROSOFT_PUBLIC_KEY} =
+ await import('../../src/distributions/microsoft/installer.js');
+const util = await import('../../src/util.js');
describe('findPackageForDownload', () => {
- let distribution: MicrosoftDistributions;
- let spyGetManifestFromRepo: jest.SpyInstance;
- let spyDebug: jest.SpyInstance;
+ let distribution: InstanceType;
+ let spyGetManifestFromRepo: any;
+ let spyHttpClientGet: any;
+ let spyDebug: any;
+ let spyCoreError: any;
+
+ const MICROSOFT_CHECKSUM = 'b'.repeat(64);
beforeEach(() => {
+ mockOsArch.mockReturnValue('x64');
+ mockOsPlatform.mockReturnValue(process.platform);
+
distribution = new MicrosoftDistributions({
version: '',
architecture: 'x64',
@@ -17,33 +120,56 @@ describe('findPackageForDownload', () => {
checkLatest: false
});
- spyGetManifestFromRepo = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
+ spyGetManifestFromRepo = jest.spyOn(HttpClient.prototype, 'getJson');
spyGetManifestFromRepo.mockReturnValue({
result: data,
statusCode: 200,
headers: {}
});
- spyDebug = jest.spyOn(core, 'debug');
+ // Every resolved release fetches `${download_url}.sha256sum.txt`; stub
+ // it with a GNU-style ` ` payload so tests never reach
+ // the real network.
+ spyHttpClientGet = jest.spyOn(HttpClient.prototype, 'get');
+ spyHttpClientGet.mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () => `${MICROSOFT_CHECKSUM} microsoft-jdk.tar.gz\n`
+ });
+
+ spyDebug = core.debug as jest.Mock;
spyDebug.mockImplementation(() => {});
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
it.each([
+ [
+ '25.x',
+ '25.0.0',
+ 'https://aka.ms/download-jdk/microsoft-jdk-25.0.0-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
+ ],
[
'21.x',
'21.0.0',
'https://aka.ms/download-jdk/microsoft-jdk-21.0.0-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[
- '17.0.1',
- '17.0.1+12.1',
- 'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
+ '17.x',
+ '17.0.18',
+ 'https://aka.ms/download-jdk/microsoft-jdk-17.0.18-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[
- '17.x',
+ '17.0.7',
'17.0.7',
'https://aka.ms/download-jdk/microsoft-jdk-17.0.7-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
+ [
+ '17.0.1',
+ '17.0.1+12.1',
+ 'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
+ ],
[
'16.0.x',
'16.0.2+7.1',
@@ -87,6 +213,7 @@ describe('findPackageForDownload', () => {
.replace('{{OS_TYPE}}', os)
.replace('{{ARCHIVE_TYPE}}', archive);
expect(result.url).toBe(url);
+ expect(result.signatureUrl).toBe(`${url}.sig`);
});
it.each([
@@ -95,10 +222,8 @@ describe('findPackageForDownload', () => {
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
async (osArch: string, distroArch: string) => {
- jest
- .spyOn(os, 'arch')
- .mockReturnValue(osArch as ReturnType);
- jest.spyOn(os, 'platform').mockReturnValue('darwin');
+ mockOsArch.mockReturnValue(osArch);
+ mockOsPlatform.mockReturnValue('darwin');
const version = '17';
const distro = new MicrosoftDistributions({
@@ -109,7 +234,7 @@ describe('findPackageForDownload', () => {
});
const result = await distro['findPackageForDownload'](version);
- const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-macos-${distroArch}.tar.gz`;
+ const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-${distroArch}.tar.gz`;
expect(result.url).toBe(expectedUrl);
}
@@ -121,10 +246,8 @@ describe('findPackageForDownload', () => {
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
async (osArch: string, distroArch: string) => {
- jest
- .spyOn(os, 'arch')
- .mockReturnValue(osArch as ReturnType);
- jest.spyOn(os, 'platform').mockReturnValue('linux');
+ mockOsArch.mockReturnValue(osArch);
+ mockOsPlatform.mockReturnValue('linux');
const version = '17';
const distro = new MicrosoftDistributions({
@@ -135,7 +258,7 @@ describe('findPackageForDownload', () => {
});
const result = await distro['findPackageForDownload'](version);
- const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-linux-${distroArch}.tar.gz`;
+ const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-${distroArch}.tar.gz`;
expect(result.url).toBe(expectedUrl);
}
@@ -147,10 +270,8 @@ describe('findPackageForDownload', () => {
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
async (osArch: string, distroArch: string) => {
- jest
- .spyOn(os, 'arch')
- .mockReturnValue(osArch as ReturnType);
- jest.spyOn(os, 'platform').mockReturnValue('win32');
+ mockOsArch.mockReturnValue(osArch);
+ mockOsPlatform.mockReturnValue('win32');
const version = '17';
const distro = new MicrosoftDistributions({
@@ -161,7 +282,7 @@ describe('findPackageForDownload', () => {
});
const result = await distro['findPackageForDownload'](version);
- const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-windows-${distroArch}.zip`;
+ const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-${distroArch}.zip`;
expect(result.url).toBe(expectedUrl);
}
@@ -169,7 +290,182 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
+ /No matching version found for SemVer */
+ );
+ });
+
+ it('uses manifest-provided signature URL when available', async () => {
+ spyGetManifestFromRepo.mockReturnValue({
+ result: [
+ {
+ version: '17.0.10',
+ stable: true,
+ release_url: 'https://example.test',
+ files: [
+ {
+ filename: 'microsoft-jdk-17.0.10-linux-x64.tar.gz',
+ arch: 'x64',
+ platform: 'linux',
+ download_url: 'https://example.test/jdk.tar.gz',
+ signature_url: 'https://example.test/jdk.tar.gz.custom.sig'
+ }
+ ]
+ }
+ ],
+ statusCode: 200,
+ headers: {}
+ });
+ mockOsPlatform.mockReturnValue('linux');
+
+ const result = await distribution['findPackageForDownload']('17.0.10');
+
+ expect(result.signatureUrl).toBe(
+ 'https://example.test/jdk.tar.gz.custom.sig'
+ );
+ });
+
+ it('fetches the authoritative sha256 checksum from the GNU-style sibling file', async () => {
+ mockOsPlatform.mockReturnValue(process.platform);
+
+ const result = await distribution['findPackageForDownload']('17.0.7');
+
+ expect(result.checksum).toEqual({
+ algorithm: 'sha256',
+ value: MICROSOFT_CHECKSUM,
+ source: `${result.url}.sha256sum.txt`
+ });
+ expect(spyHttpClientGet).toHaveBeenCalledWith(
+ `${result.url}.sha256sum.txt`
);
+ expect(spyHttpClientGet).toHaveBeenCalledTimes(1);
+ });
+
+ it('parses only the first whitespace-delimited token from the GNU checksum payload', async () => {
+ spyHttpClientGet.mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () =>
+ `${MICROSOFT_CHECKSUM} microsoft-jdk-17.0.7-linux-x64.tar.gz\n`
+ });
+
+ const result = await distribution['findPackageForDownload']('17.0.7');
+
+ expect(result.checksum?.value).toBe(MICROSOFT_CHECKSUM);
+ });
+});
+
+describe('downloadTool', () => {
+ let spyDownloadTool: any;
+ let spyExtractJdkFile: any;
+ let spyCacheDir: any;
+ let spyVerifySignature: any;
+ let distribution: InstanceType;
+
+ beforeEach(() => {
+ mockOsPlatform.mockReturnValue(process.platform);
+
+ distribution = new MicrosoftDistributions({
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ spyDownloadTool = tc.downloadTool as jest.Mock;
+ spyDownloadTool.mockImplementation(async () => {
+ return '/tmp/jdk.tar.gz';
+ });
+
+ spyExtractJdkFile = util.extractJdkFile as jest.Mock;
+ spyExtractJdkFile.mockImplementation(async () => {
+ return '/tmp/unpacked';
+ });
+
+ mockReaddirSync.mockReturnValue(['jdk'] as any);
+ spyCacheDir = tc.cacheDir as jest.Mock;
+ spyCacheDir.mockImplementation(async () => {
+ return '/tmp/cached';
+ });
+
+ (util.renameWinArchive as jest.Mock).mockImplementation(
+ (archivePath: string) => `${archivePath}.zip`
+ );
+
+ spyVerifySignature = gpg.verifyPackageSignature as jest.Mock;
+ spyVerifySignature.mockImplementation(async () => {});
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('verifies signature when enabled', async () => {
+ const signedDistribution = new MicrosoftDistributions({
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true
+ });
+
+ await signedDistribution['downloadTool']({
+ version: '17.0.14+7',
+ url: 'https://example.com/jdk.tar.gz',
+ signatureUrl: 'https://example.com/jdk.tar.gz.sig'
+ });
+
+ expect(spyVerifySignature).toHaveBeenCalledWith(
+ '/tmp/jdk.tar.gz',
+ 'https://example.com/jdk.tar.gz.sig',
+ MICROSOFT_PUBLIC_KEY
+ );
+ });
+
+ it('uses custom public key when verifySignaturePublicKey is provided', async () => {
+ const customKey =
+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\ncustom\n-----END PGP PUBLIC KEY BLOCK-----';
+ const signedDistribution = new MicrosoftDistributions({
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true,
+ verifySignaturePublicKey: customKey
+ });
+
+ await signedDistribution['downloadTool']({
+ version: '17.0.14+7',
+ url: 'https://example.com/jdk.tar.gz',
+ signatureUrl: 'https://example.com/jdk.tar.gz.sig'
+ });
+
+ expect(spyVerifySignature).toHaveBeenCalledWith(
+ '/tmp/jdk.tar.gz',
+ 'https://example.com/jdk.tar.gz.sig',
+ customKey
+ );
+ });
+
+ it('fails when signature is missing and verification is enabled', async () => {
+ const signedDistribution = new MicrosoftDistributions({
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true
+ });
+
+ await expect(
+ signedDistribution['downloadTool']({
+ version: '17.0.14+7',
+ url: 'https://example.com/jdk.tar.gz'
+ })
+ ).rejects.toThrow(
+ "Input 'verify-signature' is enabled, but no signature URL was found for Microsoft Build of OpenJDK version 17.0.14+7."
+ );
+ expect(spyVerifySignature).not.toHaveBeenCalled();
+ });
+
+ it('supports signature verification', () => {
+ expect(distribution['supportsSignatureVerification']()).toBe(true);
});
});
diff --git a/__tests__/distributors/openjdk-installer.test.ts b/__tests__/distributors/openjdk-installer.test.ts
new file mode 100644
index 000000000..c1cf0faa1
--- /dev/null
+++ b/__tests__/distributors/openjdk-installer.test.ts
@@ -0,0 +1,246 @@
+import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
+import {HttpClient} from '@actions/http-client';
+
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((value: string) => value),
+ toWin32Path: jest.fn((value: string) => value),
+ toPosixPath: jest.fn((value: string) => value)
+}));
+
+const {OpenJdkDistribution} =
+ await import('../../src/distributions/openjdk/installer.js');
+const {getJavaDistribution} =
+ await import('../../src/distributions/distribution-factory.js');
+
+const homePage = `
+ JDK 26
+ JDK
+ 27
+`;
+const currentPage = `
+ tar.gz
+ tar.gz
+`;
+const earlyAccessPage = `
+ tar.gz
+`;
+const archivePage = `
+ tar.gz
+ tar.gz
+ tar.gz
+ | 9.0.4 (build 9.0.4+11) |
+ tar.gz
+`;
+const GA_CHECKSUM = 'c'.repeat(64);
+const EA_CHECKSUM = 'd'.repeat(64);
+const checksumPages: Record = {
+ 'https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz.sha256':
+ GA_CHECKSUM,
+ 'https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz.sha256':
+ EA_CHECKSUM
+};
+
+function createDistribution(
+ version = '26',
+ architecture = 'x64',
+ packageType = 'jdk',
+ useFixturePlatform = true
+) {
+ const distribution = new OpenJdkDistribution({
+ version,
+ architecture,
+ packageType,
+ checkLatest: false
+ });
+ if (useFixturePlatform) {
+ distribution['getPlatform'] = jest.fn(() => 'linux');
+ }
+ return distribution;
+}
+
+describe('OpenJdkDistribution', () => {
+ let getSpy: jest.SpiedFunction;
+
+ beforeEach(() => {
+ getSpy = jest
+ .spyOn(HttpClient.prototype, 'get')
+ .mockImplementation(async url => {
+ const pages: Record = {
+ 'https://jdk.java.net/': homePage,
+ 'https://jdk.java.net/26/': currentPage,
+ 'https://jdk.java.net/27/': earlyAccessPage,
+ 'https://jdk.java.net/archive/': archivePage
+ };
+ if (url in pages) {
+ return {
+ message: {statusCode: 200},
+ readBody: async () => pages[url]
+ } as Awaited>;
+ }
+ // Any other GET is a `${archiveUrl}.sha256` checksum sibling request.
+ return {
+ message: {statusCode: 200},
+ readBody: async () => checksumPages[url] ?? 'e'.repeat(64)
+ } as Awaited>;
+ });
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('resolves the newest matching GA release', async () => {
+ const result = await createDistribution()['findPackageForDownload']('26');
+
+ expect(result).toEqual({
+ version: '26.0.2+10',
+ url: 'https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz',
+ checksum: {
+ algorithm: 'sha256',
+ value: GA_CHECKSUM,
+ source:
+ 'https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz.sha256'
+ }
+ });
+ expect(getSpy).toHaveBeenCalledWith(`${result.url}.sha256`);
+ });
+
+ it('resolves an archived GA release', async () => {
+ const result =
+ await createDistribution('26.0.1')['findPackageForDownload']('26.0.1');
+
+ expect(result.version).toBe('26.0.1+8');
+ expect(result.url).toContain('/openjdk-26.0.1_linux-x64_bin.tar.gz');
+ });
+
+ it('resolves an exact GA build', async () => {
+ const result =
+ await createDistribution('26.0.2+10')['findPackageForDownload'](
+ '26.0.2+10'
+ );
+
+ expect(result.version).toBe('26.0.2+10');
+ });
+
+ it('resolves an exact build from a legacy archive heading', async () => {
+ const result =
+ await createDistribution('9.0.4+11')['findPackageForDownload'](
+ '9.0.4+11'
+ );
+
+ expect(result.version).toBe('9.0.4+11');
+ expect(result.url).toContain('/binaries/openjdk-9.0.4_linux-x64_bin');
+ });
+
+ it('resolves a four-field Java version', async () => {
+ const result =
+ await createDistribution('18.0.1.1')['findPackageForDownload'](
+ '18.0.1+1'
+ );
+
+ expect(result.version).toBe('18.0.1+1');
+ expect(result.url).toContain('/openjdk-18.0.1.1_linux-x64_bin.tar.gz');
+ });
+
+ it('resolves an early-access release without requesting the archive', async () => {
+ const result =
+ await createDistribution('27-ea')['findPackageForDownload']('27');
+
+ expect(result).toEqual({
+ version: '27.0.0+32',
+ url: 'https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz',
+ checksum: {
+ algorithm: 'sha256',
+ value: EA_CHECKSUM,
+ source:
+ 'https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz.sha256'
+ }
+ });
+ expect(getSpy).not.toHaveBeenCalledWith('https://jdk.java.net/archive/');
+ expect(getSpy).toHaveBeenCalledWith(`${result.url}.sha256`);
+ });
+
+ it('reports available versions when no release matches', async () => {
+ await expect(
+ createDistribution()['findPackageForDownload']('24')
+ ).rejects.toThrow(
+ "No matching version found for SemVer '24'.\nDistribution: Oracle OpenJDK"
+ );
+ });
+
+ it.each([
+ ['jre', 'Oracle OpenJDK provides only the `jdk` package type'],
+ ['jdk+fx', 'Oracle OpenJDK provides only the `jdk` package type']
+ ])('rejects the %s package type', async (packageType, message) => {
+ await expect(
+ createDistribution('26', 'x64', packageType)['findPackageForDownload'](
+ '26'
+ )
+ ).rejects.toThrow(message);
+ });
+
+ it('rejects unsupported architectures', async () => {
+ await expect(
+ createDistribution('26', 'x86')['findPackageForDownload']('26')
+ ).rejects.toThrow('Unsupported architecture: x86');
+ });
+
+ it('maps supported platforms', () => {
+ const distribution = createDistribution('26', 'x64', 'jdk', false);
+
+ expect(distribution['getPlatform']('linux')).toBe('linux');
+ expect(distribution['getPlatform']('darwin')).toBe('macos');
+ expect(distribution['getPlatform']('win32')).toBe('windows');
+ expect(() => distribution['getPlatform']('freebsd')).toThrow(
+ "Platform 'freebsd' is not supported"
+ );
+ });
+
+ it('parses legacy platform names and archive formats', () => {
+ const distribution = createDistribution();
+ const macRelease = distribution['parseReleases'](
+ 'tar.gz',
+ 'macos',
+ 'x64'
+ );
+ const windowsRelease = distribution['parseReleases'](
+ 'tar.gz',
+ 'windows',
+ 'x64'
+ );
+
+ expect(macRelease[0].version).toBe('16.0.0+7');
+ expect(windowsRelease[0].version).toBe('10.0.2+13');
+ expect(windowsRelease[0].url.endsWith('.tar.gz')).toBe(true);
+ });
+
+ it('is registered in the distribution factory', async () => {
+ const distribution = await getJavaDistribution('oracle-openjdk', {
+ version: '26',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ expect(distribution).toBeInstanceOf(OpenJdkDistribution);
+ });
+});
diff --git a/__tests__/distributors/oracle-installer.test.ts b/__tests__/distributors/oracle-installer.test.ts
index 226eca905..429b4f2e9 100644
--- a/__tests__/distributors/oracle-installer.test.ts
+++ b/__tests__/distributors/oracle-installer.test.ts
@@ -1,13 +1,56 @@
-import {OracleDistribution} from '../../src/distributions/oracle/installer';
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
import os from 'os';
-import * as core from '@actions/core';
-import {getDownloadArchiveExtension} from '../../src/util';
import {HttpClient} from '@actions/http-client';
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {OracleDistribution} =
+ await import('../../src/distributions/oracle/installer.js');
+const {getDownloadArchiveExtension} = await import('../../src/util.js');
+
describe('findPackageForDownload', () => {
- let distribution: OracleDistribution;
- let spyDebug: jest.SpyInstance;
- let spyHttpClient: jest.SpyInstance;
+ let distribution: InstanceType;
+ let spyDebug: any;
+ let spyHttpClient: any;
+ let spyHttpClientGet: any;
+ let spyCoreError: any;
+
+ const ORACLE_CHECKSUM = 'f'.repeat(64);
beforeEach(() => {
distribution = new OracleDistribution({
@@ -17,8 +60,20 @@ describe('findPackageForDownload', () => {
checkLatest: false
});
- spyDebug = jest.spyOn(core, 'debug');
+ spyDebug = core.debug as jest.Mock;
spyDebug.mockImplementation(() => {});
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
+
+ // Every resolved release fetches its `${url}.sha256` sibling checksum;
+ // stub it so tests never reach the real network.
+ spyHttpClientGet = jest.spyOn(HttpClient.prototype, 'get');
+ spyHttpClientGet.mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () => ORACLE_CHECKSUM
+ });
});
it.each([
@@ -87,6 +142,58 @@ describe('findPackageForDownload', () => {
.replace('{{OS_TYPE}}', osType)
.replace('{{ARCHIVE_TYPE}}', archiveType);
expect(result.url).toBe(url);
+ // Only the `/latest/` path serves changing contents, so only it must be
+ // excluded from the resolution cache.
+ expect(result.floating).toBe(url.includes('/latest/'));
+ });
+
+ it.each([
+ ['21', 'etag:"oracle-latest"'],
+ ['21.0.1', undefined]
+ ])(
+ 'fingerprints only the floating artifact for version %s',
+ async (input, expected) => {
+ spyHttpClient = jest.spyOn(HttpClient.prototype, 'head');
+ spyHttpClient.mockResolvedValue({
+ message: {statusCode: 200, headers: {etag: '"oracle-latest"'}}
+ });
+
+ const result = await distribution['findPackageForDownload'](input);
+
+ jest.restoreAllMocks();
+
+ // Without a fingerprint the constant `/latest/` URL would key a cache
+ // entry that never invalidates when Oracle republishes the artifact.
+ expect(result.fingerprint).toBe(expected);
+ }
+ );
+
+ it('fetches the authoritative sha256 checksum for the resolved archive', async () => {
+ spyHttpClient = jest.spyOn(HttpClient.prototype, 'head');
+ spyHttpClient.mockResolvedValue({message: {statusCode: 200}});
+
+ const result = await distribution['findPackageForDownload']('21');
+
+ jest.restoreAllMocks();
+
+ expect(result.checksum).toEqual({
+ algorithm: 'sha256',
+ value: ORACLE_CHECKSUM,
+ source: `${result.url}.sha256`
+ });
+ expect(spyHttpClientGet).toHaveBeenCalledWith(`${result.url}.sha256`);
+ expect(spyHttpClientGet).toHaveBeenCalledTimes(1);
+ });
+
+ it('always resolves major-only requests remotely', () => {
+ expect(distribution['requiresRemoteResolution']()).toBe(true);
+ const exactDistribution = new OracleDistribution({
+ version: '21.0.8',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ expect(exactDistribution['requiresRemoteResolution']()).toBe(false);
});
it.each([
@@ -130,3 +237,63 @@ describe('findPackageForDownload', () => {
);
});
});
+describe('findPackageForDownload with latest', () => {
+ let spyHttpClientHead: any;
+ let spyHttpClientGetJson: any;
+
+ beforeEach(() => {
+ (core.debug as jest.Mock).mockImplementation(() => {});
+ (core.error as jest.Mock).mockImplementation(() => {});
+ spyHttpClientGetJson = jest.spyOn(HttpClient.prototype, 'getJson');
+ spyHttpClientGetJson.mockResolvedValue({
+ statusCode: 200,
+ result: {most_recent_feature_release: 25},
+ headers: {}
+ });
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('resolves the newest major version from the Adoptium API', async () => {
+ spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
+ spyHttpClientHead.mockResolvedValue({message: {statusCode: 200}});
+ jest.spyOn(HttpClient.prototype, 'get').mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () => 'f'.repeat(64)
+ } as any);
+
+ const distribution = new OracleDistribution({
+ version: 'latest',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const result = await distribution['findPackageForDownload']('x');
+ const osType = distribution.getPlatform();
+ const archiveType = getDownloadArchiveExtension();
+
+ expect(result.version).toBe('25');
+ expect(result.url).toBe(
+ `https://download.oracle.com/java/25/latest/jdk-25_${osType}-x64_bin.${archiveType}`
+ );
+ });
+
+ it('throws an actionable error when the latest major is not yet available', async () => {
+ spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
+ spyHttpClientHead.mockResolvedValue({message: {statusCode: 404}});
+
+ const distribution = new OracleDistribution({
+ version: 'latest',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await expect(distribution['findPackageForDownload']('x')).rejects.toThrow(
+ /is not yet available for the Oracle JDK distribution/
+ );
+ });
+});
diff --git a/__tests__/distributors/sapmachine-installer.test.ts b/__tests__/distributors/sapmachine-installer.test.ts
index 4eec570a8..6eee0b945 100644
--- a/__tests__/distributors/sapmachine-installer.test.ts
+++ b/__tests__/distributors/sapmachine-installer.test.ts
@@ -1,12 +1,62 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
import {HttpClient} from '@actions/http-client';
-import {SapMachineDistribution} from '../../src/distributions/sapmachine/installer';
-import * as utils from '../../src/util';
-import manifestData from '../data/sapmachine.json';
+import manifestData from '../data/sapmachine.json' with {type: 'json'};
+import releaseClassManifestData from '../data/sapmachine-release-classes.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ getDownloadArchiveExtension: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {SapMachineDistribution} =
+ await import('../../src/distributions/sapmachine/installer.js');
+const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
- let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyHttpGet: any;
+ let spyUtilGetDownloadArchiveExtension: any;
+ let spyCoreError: any;
+ const archiveChecksum = 'f'.repeat(64);
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -15,12 +65,19 @@ describe('getAvailableVersions', () => {
headers: {},
result: manifestData
});
+ spyHttpGet = jest.spyOn(HttpClient.prototype, 'get');
+ spyHttpGet.mockResolvedValue({
+ message: {statusCode: 200},
+ readBody: async () => `${archiveChecksum} archive`
+ });
- spyUtilGetDownloadArchiveExtension = jest.spyOn(
- utils,
- 'getDownloadArchiveExtension'
- );
+ spyUtilGetDownloadArchiveExtension =
+ utils.getDownloadArchiveExtension as jest.Mock;
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -30,7 +87,7 @@ describe('getAvailableVersions', () => {
});
const mockPlatform = (
- distribution: SapMachineDistribution,
+ distribution: InstanceType,
platform: string
) => {
distribution['getPlatformOption'] = () => platform;
@@ -61,9 +118,8 @@ describe('getAvailableVersions', () => {
mockPlatform(distribution, 'linux');
- const availableVersion = await distribution['findPackageForDownload'](
- version
- );
+ const availableVersion =
+ await distribution['findPackageForDownload'](version);
expect(availableVersion).not.toBeNull();
expect(availableVersion.url).toBe(
'https://github.com/SAP/SapMachine/releases/download/sapmachine-17.0.10/sapmachine-jdk-17.0.10_linux-x64_bin.tar.gz'
@@ -77,9 +133,9 @@ describe('getAvailableVersions', () => {
['11', 'aarch64', 'linux', 54],
['17', 'riscv', 'linux', 0],
['16.0.1', 'x64', 'linux', 71],
- ['23-ea', 'x64', 'linux', 798],
+ ['23-ea', 'x64', 'linux', 727],
['23-ea', 'aarch64', 'windows', 0],
- ['23-ea', 'x64', 'windows', 750]
+ ['23-ea', 'x64', 'windows', 679]
])(
'should get right number of available versions from JSON',
async (
@@ -101,6 +157,45 @@ describe('getAvailableVersions', () => {
expect(availableVersions.length).toBe(len);
}
);
+
+ it.each([
+ [
+ '25',
+ [
+ 'https://example.test/sapmachine-25.0.2-ga.tar.gz',
+ 'https://example.test/sapmachine-25.0.1-ga.tar.gz'
+ ]
+ ],
+ [
+ '25-ea',
+ [
+ 'https://example.test/sapmachine-25-ea.11.tar.gz',
+ 'https://example.test/sapmachine-25-ea.10.tar.gz'
+ ]
+ ]
+ ])(
+ 'should classify boolean and string EA metadata for %s requests',
+ async (version: string, expectedLinks: string[]) => {
+ spyHttpClient.mockReturnValue({
+ statusCode: 200,
+ headers: {},
+ result: releaseClassManifestData
+ });
+ const distribution = new SapMachineDistribution({
+ version,
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ mockPlatform(distribution, 'linux');
+
+ const availableVersions = await distribution['getAvailableVersions']();
+
+ expect(availableVersions.map(item => item.downloadLink)).toStrictEqual(
+ expectedLinks
+ );
+ }
+ );
});
describe('findPackageForDownload', () => {
@@ -230,14 +325,56 @@ describe('getAvailableVersions', () => {
});
mockPlatform(distribution, platform);
- const availableVersion = await distribution['findPackageForDownload'](
- normalizedVersion
- );
+ const availableVersion =
+ await distribution['findPackageForDownload'](normalizedVersion);
expect(availableVersion).not.toBeNull();
expect(availableVersion.url).toBe(expectedLink);
+ expect(availableVersion.checksum).toEqual({
+ algorithm: 'sha256',
+ value: archiveChecksum,
+ source: expectedLink.replace(/\.(?:tar\.gz|zip)$/, '.sha256.txt')
+ });
}
);
+ it('uses the checksum published beside the selected EA archive', async () => {
+ const distribution = new SapMachineDistribution({
+ version: '21-ea',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ mockPlatform(distribution, 'linux');
+
+ const release = await distribution['findPackageForDownload']('21');
+
+ expect(spyHttpGet).toHaveBeenCalledWith(
+ release.url.replace(/\.(?:tar\.gz|zip)$/, '.sha256.txt')
+ );
+ expect(release.checksum?.value).toBe(archiveChecksum);
+ });
+
+ it('does not select a newer stable release for an EA request', async () => {
+ spyHttpClient.mockReturnValue({
+ statusCode: 200,
+ headers: {},
+ result: releaseClassManifestData
+ });
+ const distribution = new SapMachineDistribution({
+ version: '25-ea',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ mockPlatform(distribution, 'linux');
+
+ const release = await distribution['findPackageForDownload']('25');
+
+ expect(release.url).toBe(
+ 'https://example.test/sapmachine-25-ea.11.tar.gz'
+ );
+ });
+
it.each([
['8', 'linux', 'x64'],
['8', 'macos', 'aarch64'],
@@ -250,7 +387,7 @@ describe('getAvailableVersions', () => {
['21.0.3+8-ea', 'linux', 'x64', '21.0.3+8'],
['17', 'linux-muse', 'aarch64']
])(
- 'should throw when required version of JDK can not be found in the JSON',
+ 'should throw when required version of JDK cannot be found in the JSON',
async (
version: string,
platform: string,
@@ -268,7 +405,7 @@ describe('getAvailableVersions', () => {
await expect(
distribution['findPackageForDownload'](normalizedVersion)
).rejects.toThrow(
- `Couldn't find any satisfied version for the specified java-version: "${normalizedVersion}" and architecture: "${arch}".`
+ `No matching version found for SemVer '${normalizedVersion}'`
);
}
);
diff --git a/__tests__/distributors/semeru-installer.test.ts b/__tests__/distributors/semeru-installer.test.ts
index 690478f79..7dde47d03 100644
--- a/__tests__/distributors/semeru-installer.test.ts
+++ b/__tests__/distributors/semeru-installer.test.ts
@@ -1,12 +1,53 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
import {HttpClient} from '@actions/http-client';
-import {JavaInstallerOptions} from '../../src/distributions/base-models';
-import {SemeruDistribution} from '../../src/distributions/semeru/installer';
+import manifestData from '../data/semeru.json' with {type: 'json'};
-import manifestData from '../data/semeru.json';
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {SemeruDistribution} =
+ await import('../../src/distributions/semeru/installer.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
+ let spyCoreWarning: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -15,6 +56,11 @@ describe('getAvailableVersions', () => {
headers: {},
result: []
});
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
+ spyCoreWarning = core.warning as jest.Mock;
+ spyCoreWarning.mockImplementation(() => {});
});
afterEach(() => {
@@ -77,22 +123,19 @@ describe('getAvailableVersions', () => {
);
it('load available versions', async () => {
+ const nextPageUrl =
+ 'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient
.mockReturnValueOnce({
statusCode: 200,
- headers: {},
+ headers: {link: `<${nextPageUrl}>; rel="next"`},
result: manifestData as any
})
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: manifestData as any
- })
- .mockReturnValueOnce({
- statusCode: 200,
- headers: {},
- result: []
});
const distribution = new SemeruDistribution({
@@ -104,6 +147,31 @@ describe('getAvailableVersions', () => {
const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull();
expect(availableVersions.length).toBe(manifestData.length * 2);
+ expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
+ });
+
+ it('stops pagination after 1000 pages as a safeguard', async () => {
+ const nextPageUrl =
+ 'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
+ spyHttpClient.mockReturnValue({
+ statusCode: 200,
+ headers: {link: `<${nextPageUrl}>; rel="next"`},
+ result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
+ });
+
+ const distribution = new SemeruDistribution({
+ version: '8',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenCalledTimes(1000);
+ expect(spyCoreWarning).toHaveBeenCalledWith(
+ expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
+ );
});
it.each([
@@ -140,6 +208,14 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData as any;
const resolvedVersion = await distribution['findPackageForDownload'](input);
expect(resolvedVersion.version).toBe(expected);
+ const vendorPackage = (manifestData as any[]).find(
+ item => item.version_data.semver === expected
+ ).binaries[0].package;
+ expect(resolvedVersion.checksum).toEqual({
+ algorithm: 'sha256',
+ value: vendorPackage.checksum,
+ source: vendorPackage.checksum_link
+ });
});
it('version is found but binaries list is empty', async () => {
@@ -152,7 +228,7 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(
distribution['findPackageForDownload']('9.0.8')
- ).rejects.toThrow(/Could not find satisfied version for SemVer */);
+ ).rejects.toThrow(/No matching version found for SemVer */);
});
it('version is not found', async () => {
@@ -164,7 +240,7 @@ describe('findPackageForDownload', () => {
});
distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
+ /No matching version found for SemVer */
);
});
@@ -177,7 +253,7 @@ describe('findPackageForDownload', () => {
});
distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
+ /No matching version found for SemVer */
);
});
diff --git a/__tests__/distributors/temurin-installer.test.ts b/__tests__/distributors/temurin-installer.test.ts
index f540901eb..830fdb943 100644
--- a/__tests__/distributors/temurin-installer.test.ts
+++ b/__tests__/distributors/temurin-installer.test.ts
@@ -1,15 +1,93 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
+import type {TemurinImplementation as TemurinImplementationType} from '../../src/distributions/temurin/installer.js';
import {HttpClient} from '@actions/http-client';
+import fs from 'fs';
import os from 'os';
-import {
- TemurinDistribution,
- TemurinImplementation
-} from '../../src/distributions/temurin/installer';
-import {JavaInstallerOptions} from '../../src/distributions/base-models';
+import path from 'path';
+
+import manifestData from '../data/temurin.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+jest.unstable_mockModule('@actions/tool-cache', () => ({
+ find: jest.fn(),
+ findAllVersions: jest.fn(),
+ downloadTool: jest.fn(),
+ extractZip: jest.fn(),
+ extractTar: jest.fn(),
+ extract7z: jest.fn(),
+ extractXar: jest.fn(),
+ cacheDir: jest.fn(),
+ cacheFile: jest.fn(),
+ getManifestFromRepo: jest.fn(),
+ findFromManifest: jest.fn(),
+ evaluateVersions: jest.fn()
+}));
-import manifestData from '../data/temurin.json';
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ extractJdkFile: jest.fn(),
+ getDownloadArchiveExtension: jest.fn(),
+ getToolcachePath: jest.fn(),
+ isJobStatusSuccess: jest.fn(),
+ renameWinArchive: jest.fn(),
+ isVersionSatisfies: real_util_module.isVersionSatisfies,
+ getTempDir: real_util_module.getTempDir
+}));
+
+jest.unstable_mockModule('../../src/gpg.js', () => ({
+ importKey: jest.fn(),
+ removeGpgHome: jest.fn(),
+ verifyPackageSignature: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const gpg = await import('../../src/gpg.js');
+const tc = await import('@actions/tool-cache');
+const {TemurinDistribution, TemurinImplementation, ADOPTIUM_PUBLIC_KEY} =
+ await import('../../src/distributions/temurin/installer.js');
+const util = await import('../../src/util.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
+ let spyCoreWarning: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +96,11 @@ describe('getAvailableVersions', () => {
headers: {},
result: []
});
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
+ spyCoreWarning = core.warning as jest.Mock;
+ spyCoreWarning.mockImplementation(() => {});
});
afterEach(() => {
@@ -37,6 +120,16 @@ describe('getAvailableVersions', () => {
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
+ [
+ {
+ version: '25',
+ architecture: 'x64',
+ packageType: 'jdk+jmods',
+ checkLatest: false
+ },
+ TemurinImplementation.Hotspot,
+ 'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
+ ],
[
{
version: '16',
@@ -71,7 +164,7 @@ describe('getAvailableVersions', () => {
'build correct url for %s',
async (
installerOptions: JavaInstallerOptions,
- impl: TemurinImplementation,
+ impl: TemurinImplementationType,
expectedParameters
) => {
const distribution = new TemurinDistribution(installerOptions, impl);
@@ -87,23 +180,41 @@ describe('getAvailableVersions', () => {
}
);
+ it('requests the JMOD image type', async () => {
+ const distribution = new TemurinDistribution(
+ {
+ version: '25',
+ architecture: 'x64',
+ packageType: 'jdk+jmods',
+ checkLatest: false
+ },
+ TemurinImplementation.Hotspot
+ );
+ distribution['getPlatformOption'] = () => 'linux';
+
+ await distribution['getAvailableVersions']('jmods');
+
+ expect(spyHttpClient).toHaveBeenCalledWith(
+ expect.stringContaining(
+ 'os=linux&architecture=x64&image_type=jmods&release_type=ga'
+ )
+ );
+ });
+
it('load available versions', async () => {
+ const nextPageUrl =
+ 'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient
.mockReturnValueOnce({
statusCode: 200,
- headers: {},
+ headers: {link: `<${nextPageUrl}>; rel="next"`},
result: manifestData as any
})
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: manifestData as any
- })
- .mockReturnValueOnce({
- statusCode: 200,
- headers: {},
- result: []
});
const distribution = new TemurinDistribution(
@@ -118,14 +229,51 @@ describe('getAvailableVersions', () => {
const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull();
expect(availableVersions.length).toBe(manifestData.length * 2);
+ expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
+ });
+
+ it('stops pagination after 1000 pages as a safeguard', async () => {
+ const nextPageUrl =
+ 'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
+ spyHttpClient.mockReturnValue({
+ statusCode: 200,
+ headers: {link: `<${nextPageUrl}>; rel="next"`},
+ result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
+ });
+
+ const distribution = new TemurinDistribution(
+ {
+ version: '8',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ },
+ TemurinImplementation.Hotspot
+ );
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient).toHaveBeenCalledTimes(1000);
+ expect(spyCoreWarning).toHaveBeenCalledWith(
+ expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
+ );
});
it.each([
[TemurinImplementation.Hotspot, 'jdk', 'Java_Temurin-Hotspot_jdk'],
- [TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre']
+ [TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre'],
+ [
+ TemurinImplementation.Hotspot,
+ 'jdk+jmods',
+ 'Java_Temurin-Hotspot_jdk+jmods'
+ ]
])(
'find right toolchain folder',
- (impl: TemurinImplementation, packageType: string, expected: string) => {
+ (
+ impl: TemurinImplementationType,
+ packageType: string,
+ expected: string
+ ) => {
const distribution = new TemurinDistribution(
{
version: '8',
@@ -143,6 +291,7 @@ describe('getAvailableVersions', () => {
it.each([
['amd64', 'x64'],
+ ['arm', 'arm'],
['arm64', 'aarch64']
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
@@ -198,6 +347,33 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData as any;
const resolvedVersion = await distribution['findPackageForDownload'](input);
expect(resolvedVersion.version).toBe(expected);
+ expect(resolvedVersion.signatureUrl).toBeDefined();
+ const vendorPackage = (manifestData as any[]).find(
+ item => item.version_data.semver === expected
+ ).binaries[0].package;
+ expect(resolvedVersion.checksum).toEqual({
+ algorithm: 'sha256',
+ value: vendorPackage.checksum,
+ source: vendorPackage.checksum_link
+ });
+ });
+
+ it('version "latest" is normalized to the newest available version', async () => {
+ const distribution = new TemurinDistribution(
+ {
+ version: 'latest',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ },
+ TemurinImplementation.Hotspot
+ );
+ distribution['getAvailableVersions'] = async () => manifestData as any;
+ // normalizeVersion turns `latest` into the wildcard carried on `this.version`
+ const resolvedVersion = await distribution['findPackageForDownload'](
+ distribution['version']
+ );
+ expect(resolvedVersion.version).toBe('16.0.2+7');
});
it('version is found but binaries list is empty', async () => {
@@ -213,7 +389,7 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(
distribution['findPackageForDownload']('9.0.8')
- ).rejects.toThrow(/Could not find satisfied version for SemVer */);
+ ).rejects.toThrow(/No matching version found for SemVer */);
});
it('version is not found', async () => {
@@ -228,7 +404,7 @@ describe('findPackageForDownload', () => {
);
distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
+ /No matching version found for SemVer */
);
});
@@ -244,7 +420,170 @@ describe('findPackageForDownload', () => {
);
distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
- /Could not find satisfied version for SemVer */
+ /No matching version found for SemVer */
+ );
+ });
+});
+
+describe('downloadTool', () => {
+ let spyDownloadTool: any;
+ let spyVerifySignature: any;
+ let spyExtractJdkFile: any;
+ let spyCacheDir: any;
+ let spyReadDirSync: any;
+ let spyRenameWinArchive: any;
+ let spyCopySync: any;
+
+ beforeEach(() => {
+ spyDownloadTool = tc.downloadTool as jest.Mock;
+ spyDownloadTool.mockResolvedValue('/tmp/jdk.tar.gz');
+ spyVerifySignature = gpg.verifyPackageSignature as jest.Mock;
+ spyVerifySignature.mockResolvedValue(undefined);
+ spyExtractJdkFile = util.extractJdkFile as jest.Mock;
+ spyExtractJdkFile.mockResolvedValue('/tmp/extracted');
+ spyCacheDir = tc.cacheDir as jest.Mock;
+ spyCacheDir.mockResolvedValue('/tmp/toolcache');
+ spyReadDirSync = jest.spyOn(fs, 'readdirSync');
+ spyReadDirSync.mockReturnValue(['jdk-17'] as any);
+ spyRenameWinArchive = util.renameWinArchive as jest.Mock;
+ spyRenameWinArchive.mockReturnValue('/tmp/jdk.tar.gz.zip');
+ spyCopySync = jest.spyOn(fs, 'cpSync');
+ spyCopySync.mockImplementation(() => undefined);
+ });
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ jest.clearAllMocks();
+ jest.restoreAllMocks();
+ });
+
+ it('verifies signature when enabled', async () => {
+ const distribution = new TemurinDistribution(
+ {
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true
+ },
+ TemurinImplementation.Hotspot
+ );
+
+ await distribution['downloadTool']({
+ version: '17.0.14+7',
+ url: 'https://example.com/jdk.tar.gz',
+ signatureUrl: 'https://example.com/jdk.tar.gz.sig'
+ });
+
+ expect(spyVerifySignature).toHaveBeenCalledWith(
+ '/tmp/jdk.tar.gz',
+ 'https://example.com/jdk.tar.gz.sig',
+ ADOPTIUM_PUBLIC_KEY
+ );
+ });
+
+ it('downloads and adds matching JMODs to the JDK', async () => {
+ spyDownloadTool
+ .mockResolvedValueOnce('/tmp/jdk.tar.gz')
+ .mockResolvedValueOnce('/tmp/jmods.tar.gz');
+ spyExtractJdkFile
+ .mockResolvedValueOnce('/tmp/extracted')
+ .mockResolvedValueOnce('/tmp/extracted-jmods');
+ spyReadDirSync
+ .mockReturnValueOnce(['jdk-25'] as any)
+ .mockReturnValueOnce(['jdk-25-jmods'] as any);
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+
+ const distribution = new TemurinDistribution(
+ {
+ version: '25',
+ architecture: 'x64',
+ packageType: 'jdk+jmods',
+ checkLatest: false
+ },
+ TemurinImplementation.Hotspot
+ );
+ distribution['resolvePackage'] = jest.fn().mockResolvedValue({
+ version: '25.0.3+9',
+ url: 'https://example.com/jmods.tar.gz'
+ });
+
+ await distribution['downloadTool']({
+ version: '25.0.3+9',
+ url: 'https://example.com/jdk.tar.gz'
+ });
+
+ expect(distribution['resolvePackage']).toHaveBeenCalledWith(
+ '25.0.3+9',
+ 'jmods'
+ );
+ expect(spyDownloadTool).toHaveBeenNthCalledWith(
+ 2,
+ 'https://example.com/jmods.tar.gz'
+ );
+ expect(spyCopySync).toHaveBeenCalledWith(
+ path.join('/tmp/extracted-jmods', 'jdk-25-jmods'),
+ process.platform === 'darwin'
+ ? path.join('/tmp/extracted', 'jdk-25', 'Contents', 'Home', 'jmods')
+ : path.join('/tmp/extracted', 'jdk-25', 'jmods'),
+ {recursive: true}
+ );
+ expect(spyCacheDir).toHaveBeenCalledWith(
+ path.join('/tmp/extracted', 'jdk-25'),
+ 'Java_Temurin-Hotspot_jdk+jmods',
+ '25.0.3-9',
+ 'x64'
+ );
+ });
+
+ it('fails when signature is missing and verification is enabled', async () => {
+ const distribution = new TemurinDistribution(
+ {
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true
+ },
+ TemurinImplementation.Hotspot
+ );
+
+ await expect(
+ distribution['downloadTool']({
+ version: '17.0.14+7',
+ url: 'https://example.com/jdk.tar.gz'
+ })
+ ).rejects.toThrow(
+ "Input 'verify-signature' is enabled, but no signature URL was found"
+ );
+ expect(spyVerifySignature).not.toHaveBeenCalled();
+ });
+
+ it('uses custom public key when verifySignaturePublicKey is provided', async () => {
+ const customKey =
+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\ncustom\n-----END PGP PUBLIC KEY BLOCK-----';
+ const distribution = new TemurinDistribution(
+ {
+ version: '17',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false,
+ verifySignature: true,
+ verifySignaturePublicKey: customKey
+ },
+ TemurinImplementation.Hotspot
+ );
+
+ await distribution['downloadTool']({
+ version: '17.0.14+7',
+ url: 'https://example.com/jdk.tar.gz',
+ signatureUrl: 'https://example.com/jdk.tar.gz.sig'
+ });
+
+ expect(spyVerifySignature).toHaveBeenCalledWith(
+ '/tmp/jdk.tar.gz',
+ 'https://example.com/jdk.tar.gz.sig',
+ customKey
);
});
});
diff --git a/__tests__/distributors/zulu-installer.test.ts b/__tests__/distributors/zulu-installer.test.ts
index 100429b30..20939cb9a 100644
--- a/__tests__/distributors/zulu-installer.test.ts
+++ b/__tests__/distributors/zulu-installer.test.ts
@@ -1,28 +1,77 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import fs from 'fs';
+import type {IZuluVersions} from '../../src/distributions/zulu/models.js';
import {HttpClient} from '@actions/http-client';
-import {ZuluDistribution} from '../../src/distributions/zulu/installer';
-import {IZuluVersions} from '../../src/distributions/zulu/models';
-import * as utils from '../../src/util';
import os from 'os';
-import manifestData from '../data/zulu-releases-default.json';
+import manifestData from '../data/zulu-releases-default.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ getDownloadArchiveExtension: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {ZuluDistribution} =
+ await import('../../src/distributions/zulu/installer.js');
+const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
- let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {},
- result: manifestData as IZuluVersions[]
+ result: [] as IZuluVersions[]
});
- spyUtilGetDownloadArchiveExtension = jest.spyOn(
- utils,
- 'getDownloadArchiveExtension'
+ (utils.getDownloadArchiveExtension as jest.Mock).mockReturnValue(
+ 'tar.gz'
);
- spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -39,7 +88,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ga'
+ '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -48,7 +97,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ea'
+ '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ea&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -57,7 +106,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=64&release_status=ga'
+ '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -66,7 +115,7 @@ describe('getAvailableVersions', () => {
packageType: 'jre',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jre&javafx=false&arch=x86&hw_bitness=64&release_status=ga'
+ '?os=macos&archive_type=tar.gz&java_package_type=jre&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -75,7 +124,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk+fx',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx'
+ '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -84,7 +133,16 @@ describe('getAvailableVersions', () => {
packageType: 'jre+fx',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jre&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx'
+ '?os=macos&archive_type=tar.gz&java_package_type=jre&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
+ ],
+ [
+ {
+ version: '8',
+ architecture: 'x64',
+ packageType: 'jdk+crac',
+ checkLatest: false
+ },
+ '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=true&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -93,7 +151,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=64&release_status=ga'
+ '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=aarch64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -102,12 +160,12 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=&release_status=ga'
+ '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=arm&release_status=ga&availability_types=ca&page=1&page_size=100'
]
])('build correct url for %s -> %s', async (input, parsedUrl) => {
const distribution = new ZuluDistribution(input);
distribution['getPlatformOption'] = () => 'macos';
- const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/${parsedUrl}`;
+ const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/${parsedUrl}`;
await distribution['getAvailableVersions']();
@@ -115,16 +173,12 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
});
- type DistroArch = {
- bitness: string;
- arch: string;
- };
it.each([
- ['amd64', {bitness: '64', arch: 'x86'}],
- ['arm64', {bitness: '64', arch: 'arm'}]
+ ['amd64', 'x64'],
+ ['arm64', 'aarch64']
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
- async (osArch: string, distroArch: DistroArch) => {
+ async (osArch: string, distroArch: string) => {
jest
.spyOn(os, 'arch')
.mockReturnValue(osArch as ReturnType);
@@ -136,7 +190,7 @@ describe('getAvailableVersions', () => {
checkLatest: false
});
distribution['getPlatformOption'] = () => 'macos';
- const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=${distroArch.arch}&hw_bitness=${distroArch.bitness}&release_status=ga`;
+ const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=${distroArch}&release_status=ga&availability_types=ca&page=1&page_size=100`;
await distribution['getAvailableVersions']();
@@ -146,6 +200,18 @@ describe('getAvailableVersions', () => {
);
it('load available versions', async () => {
+ spyHttpClient
+ .mockReturnValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: manifestData as IZuluVersions[]
+ })
+ .mockReturnValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: [] as IZuluVersions[]
+ });
+
const distribution = new ZuluDistribution({
version: '11',
architecture: 'x86',
@@ -159,10 +225,11 @@ describe('getAvailableVersions', () => {
describe('getArchitectureOptions', () => {
it.each([
- [{architecture: 'x64'}, {arch: 'x86', hw_bitness: '64', abi: ''}],
- [{architecture: 'x86'}, {arch: 'x86', hw_bitness: '32', abi: ''}],
- [{architecture: 'x32'}, {arch: 'x32', hw_bitness: '', abi: ''}],
- [{architecture: 'arm'}, {arch: 'arm', hw_bitness: '', abi: ''}]
+ [{architecture: 'x64'}, 'x64'],
+ [{architecture: 'x86'}, 'i686'],
+ [{architecture: 'aarch64'}, 'aarch64'],
+ [{architecture: 'arm64'}, 'aarch64'],
+ [{architecture: 'arm'}, 'arm']
])('%s -> %s', (input, expected) => {
const distribution = new ZuluDistribution({
version: '11',
@@ -170,11 +237,31 @@ describe('getArchitectureOptions', () => {
packageType: 'jdk',
checkLatest: false
});
- expect(distribution['getArchitectureOptions']()).toEqual(expected);
+ expect(distribution['getArchitectureOptions']()).toBe(expected);
});
});
describe('findPackageForDownload', () => {
+ let spyPackageDetails: any;
+
+ const ZULU_CHECKSUM = 'a'.repeat(64);
+
+ beforeEach(() => {
+ // The resolved winning package fetches sha256_hash from the Azul
+ // package-details endpoint; stub it so tests never reach the real
+ // network.
+ spyPackageDetails = jest.spyOn(HttpClient.prototype, 'getJson');
+ spyPackageDetails.mockResolvedValue({
+ statusCode: 200,
+ headers: {},
+ result: {sha256_hash: ZULU_CHECKSUM}
+ });
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
it.each([
['8', '8.0.282+8'],
['11.x', '11.0.10+9'],
@@ -213,6 +300,38 @@ describe('findPackageForDownload', () => {
expect(result.url).toBe(
'https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz'
);
+ expect(result.checksum).toEqual({
+ algorithm: 'sha256',
+ value: ZULU_CHECKSUM,
+ source: 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-10933'
+ });
+ // Only the winning package's UUID triggers a details request.
+ expect(spyPackageDetails).toHaveBeenCalledWith(
+ 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-10933'
+ );
+ expect(spyPackageDetails).toHaveBeenCalledTimes(1);
+ });
+
+ it('skips checksum verification when sha256_hash is missing or malformed', async () => {
+ spyPackageDetails.mockResolvedValue({
+ statusCode: 200,
+ headers: {},
+ result: {sha256_hash: 'not-a-valid-digest'}
+ });
+
+ const distribution = new ZuluDistribution({
+ version: '',
+ architecture: 'x86',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getAvailableVersions'] = async () => manifestData;
+ const result = await distribution['findPackageForDownload']('11.0.5');
+
+ expect(result.checksum).toBeUndefined();
+ expect(core.debug).toHaveBeenCalledWith(
+ expect.stringContaining('No authoritative sha256 checksum')
+ );
});
it('should throw an error', async () => {
@@ -225,6 +344,53 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData;
await expect(
distribution['findPackageForDownload'](distribution['version'])
- ).rejects.toThrow(/Could not find satisfied version for semver */);
+ ).rejects.toThrow(/No matching version found for SemVer/);
+ });
+});
+
+describe('Zulu getPlatformOption libc selection', () => {
+ const originalPlatform = Object.getOwnPropertyDescriptor(
+ process,
+ 'platform'
+ ) as PropertyDescriptor;
+
+ const setPlatform = (platform: NodeJS.Platform) =>
+ Object.defineProperty(process, 'platform', {
+ ...originalPlatform,
+ value: platform
+ });
+
+ const distribution = new ZuluDistribution({
+ version: '21',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ afterEach(() => {
+ Object.defineProperty(process, 'platform', originalPlatform);
+ jest.restoreAllMocks();
+ });
+
+ it('selects the musl artifacts on Alpine', () => {
+ setPlatform('linux');
+ jest.spyOn(fs, 'existsSync').mockReturnValue(true);
+
+ expect(distribution['getPlatformOption']()).toBe('linux_musl');
+ });
+
+ it('selects the glibc artifacts on other Linux runners', () => {
+ setPlatform('linux');
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+
+ expect(distribution['getPlatformOption']()).toBe('linux_glibc');
+ });
+
+ it('does not probe for Alpine off Linux', () => {
+ setPlatform('win32');
+ const existsSync = jest.spyOn(fs, 'existsSync');
+
+ expect(distribution['getPlatformOption']()).toBe('windows');
+ expect(existsSync).not.toHaveBeenCalled();
});
});
diff --git a/__tests__/distributors/zulu-linux-installer.test.ts b/__tests__/distributors/zulu-linux-installer.test.ts
index a25344cbd..2b818c7de 100644
--- a/__tests__/distributors/zulu-linux-installer.test.ts
+++ b/__tests__/distributors/zulu-linux-installer.test.ts
@@ -1,29 +1,78 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import type {IZuluVersions} from '../../src/distributions/zulu/models.js';
import {HttpClient} from '@actions/http-client';
import * as semver from 'semver';
-import {ZuluDistribution} from '../../src/distributions/zulu/installer';
-import {IZuluVersions} from '../../src/distributions/zulu/models';
-import * as utils from '../../src/util';
import os from 'os';
-import manifestData from '../data/zulu-linux.json';
+import manifestData from '../data/zulu-linux.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ getDownloadArchiveExtension: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {ZuluDistribution} =
+ await import('../../src/distributions/zulu/installer.js');
+const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
- let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyUtilGetDownloadArchiveExtension: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {},
- result: manifestData as IZuluVersions[]
+ result: [] as IZuluVersions[]
});
- spyUtilGetDownloadArchiveExtension = jest.spyOn(
- utils,
- 'getDownloadArchiveExtension'
- );
+ spyUtilGetDownloadArchiveExtension =
+ utils.getDownloadArchiveExtension as jest.Mock;
spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -40,7 +89,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ga'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -49,7 +98,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ea'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ea&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -58,7 +107,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=64&release_status=ga'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -67,7 +116,7 @@ describe('getAvailableVersions', () => {
packageType: 'jre',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jre&javafx=false&arch=x86&hw_bitness=64&release_status=ga'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jre&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -76,7 +125,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk+fx',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jdk&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -85,7 +134,16 @@ describe('getAvailableVersions', () => {
packageType: 'jre+fx',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jre&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jre&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
+ ],
+ [
+ {
+ version: '8',
+ architecture: 'x64',
+ packageType: 'jdk+crac',
+ checkLatest: false
+ },
+ '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=true&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -94,7 +152,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=64&release_status=ga'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=aarch64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -103,12 +161,12 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=&release_status=ga'
+ '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=arm&release_status=ga&availability_types=ca&page=1&page_size=100'
]
])('build correct url for %s -> %s', async (input, parsedUrl) => {
const distribution = new ZuluDistribution(input);
- distribution['getPlatformOption'] = () => 'linux';
- const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/${parsedUrl}`;
+ distribution['getPlatformOption'] = () => 'linux_glibc';
+ const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/${parsedUrl}`;
await distribution['getAvailableVersions']();
@@ -116,16 +174,12 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
});
- type DistroArch = {
- bitness: string;
- arch: string;
- };
it.each([
- ['amd64', {bitness: '64', arch: 'x86'}],
- ['arm64', {bitness: '64', arch: 'arm'}]
+ ['amd64', 'x64'],
+ ['arm64', 'aarch64']
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
- async (osArch: string, distroArch: DistroArch) => {
+ async (osArch: string, distroArch: string) => {
jest
.spyOn(os, 'arch')
.mockReturnValue(osArch as ReturnType);
@@ -136,10 +190,10 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
});
- distribution['getPlatformOption'] = () => 'linux';
+ distribution['getPlatformOption'] = () => 'linux_glibc';
// Override extension for linux default arch case to match util behavior
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
- const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?os=linux&ext=tar.gz&bundle_type=jdk&javafx=false&arch=${distroArch.arch}&hw_bitness=${distroArch.bitness}&release_status=ga`;
+ const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/?os=linux_glibc&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=${distroArch}&release_status=ga&availability_types=ca&page=1&page_size=100`;
await distribution['getAvailableVersions']();
@@ -149,6 +203,18 @@ describe('getAvailableVersions', () => {
);
it('load available versions', async () => {
+ spyHttpClient
+ .mockReturnValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: manifestData as IZuluVersions[]
+ })
+ .mockReturnValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: [] as IZuluVersions[]
+ });
+
const distribution = new ZuluDistribution({
version: '11',
architecture: 'x86',
@@ -162,10 +228,11 @@ describe('getAvailableVersions', () => {
describe('getArchitectureOptions', () => {
it.each([
- [{architecture: 'x64'}, {arch: 'x86', hw_bitness: '64', abi: ''}],
- [{architecture: 'x86'}, {arch: 'x86', hw_bitness: '32', abi: ''}],
- [{architecture: 'x32'}, {arch: 'x32', hw_bitness: '', abi: ''}],
- [{architecture: 'arm'}, {arch: 'arm', hw_bitness: '', abi: ''}]
+ [{architecture: 'x64'}, 'x64'],
+ [{architecture: 'x86'}, 'i686'],
+ [{architecture: 'aarch64'}, 'aarch64'],
+ [{architecture: 'arm64'}, 'aarch64'],
+ [{architecture: 'arm'}, 'arm']
])('%s -> %s', (input, expected) => {
const distribution = new ZuluDistribution({
version: '11',
@@ -173,11 +240,31 @@ describe('getArchitectureOptions', () => {
packageType: 'jdk',
checkLatest: false
});
- expect(distribution['getArchitectureOptions']()).toEqual(expected);
+ expect(distribution['getArchitectureOptions']()).toBe(expected);
});
});
describe('findPackageForDownload', () => {
+ let spyPackageDetails: any;
+
+ const ZULU_CHECKSUM = 'a'.repeat(64);
+
+ beforeEach(() => {
+ // The resolved winning package fetches sha256_hash from the Azul
+ // package-details endpoint; stub it so tests never reach the real
+ // network.
+ spyPackageDetails = jest.spyOn(HttpClient.prototype, 'getJson');
+ spyPackageDetails.mockResolvedValue({
+ statusCode: 200,
+ headers: {},
+ result: {sha256_hash: ZULU_CHECKSUM}
+ });
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
it.each([
['8', '8.0.282+8'],
['11.x', '11.0.10+9'],
@@ -216,6 +303,38 @@ describe('findPackageForDownload', () => {
expect(result.url).toBe(
'https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz'
);
+ expect(result.checksum).toEqual({
+ algorithm: 'sha256',
+ value: ZULU_CHECKSUM,
+ source: 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12447'
+ });
+ // Only the winning package's UUID triggers a details request.
+ expect(spyPackageDetails).toHaveBeenCalledWith(
+ 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12447'
+ );
+ expect(spyPackageDetails).toHaveBeenCalledTimes(1);
+ });
+
+ it('skips checksum verification when sha256_hash is missing or malformed', async () => {
+ spyPackageDetails.mockResolvedValue({
+ statusCode: 200,
+ headers: {},
+ result: {}
+ });
+
+ const distribution = new ZuluDistribution({
+ version: '',
+ architecture: 'arm64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getAvailableVersions'] = async () => manifestData;
+ const result = await distribution['findPackageForDownload']('21.0.2');
+
+ expect(result.checksum).toBeUndefined();
+ expect(core.debug).toHaveBeenCalledWith(
+ expect.stringContaining('No authoritative sha256 checksum')
+ );
});
it('should throw an error', async () => {
@@ -228,6 +347,6 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData;
await expect(
distribution['findPackageForDownload'](distribution['version'])
- ).rejects.toThrow(/Could not find satisfied version for semver */);
+ ).rejects.toThrow(/No matching version found for SemVer/);
});
});
diff --git a/__tests__/distributors/zulu-windows-installer.test.ts b/__tests__/distributors/zulu-windows-installer.test.ts
index a3511ac90..c90890d5a 100644
--- a/__tests__/distributors/zulu-windows-installer.test.ts
+++ b/__tests__/distributors/zulu-windows-installer.test.ts
@@ -1,29 +1,77 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import type {IZuluVersions} from '../../src/distributions/zulu/models.js';
import {HttpClient} from '@actions/http-client';
import * as semver from 'semver';
-import {ZuluDistribution} from '../../src/distributions/zulu/installer';
-import {IZuluVersions} from '../../src/distributions/zulu/models';
-import * as utils from '../../src/util';
import os from 'os';
-import manifestData from '../data/zulu-windows.json';
+import manifestData from '../data/zulu-windows.json' with {type: 'json'};
+
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const real_util_module = await import('../../src/util.js');
+jest.unstable_mockModule('../../src/util.js', () => ({
+ ...real_util_module,
+ getDownloadArchiveExtension: jest.fn()
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const {ZuluDistribution} =
+ await import('../../src/distributions/zulu/installer.js');
+const utils = await import('../../src/util.js');
describe('getAvailableVersions', () => {
- let spyHttpClient: jest.SpyInstance;
- let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
+ let spyHttpClient: any;
+ let spyCoreError: any;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {},
- result: manifestData as IZuluVersions[]
+ result: [] as IZuluVersions[]
});
- spyUtilGetDownloadArchiveExtension = jest.spyOn(
- utils,
- 'getDownloadArchiveExtension'
+ (utils.getDownloadArchiveExtension as jest.Mock).mockReturnValue(
+ 'zip'
);
- spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
+
+ // Mock core.error to suppress error logs
+ spyCoreError = core.error as jest.Mock;
+ spyCoreError.mockImplementation(() => {});
});
afterEach(() => {
@@ -40,7 +88,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ga'
+ '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -49,7 +97,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ea'
+ '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ea&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -58,7 +106,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=64&release_status=ga'
+ '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -67,7 +115,7 @@ describe('getAvailableVersions', () => {
packageType: 'jre',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jre&javafx=false&arch=x86&hw_bitness=64&release_status=ga'
+ '?os=windows&archive_type=zip&java_package_type=jre&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -76,7 +124,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk+fx',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jdk&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx'
+ '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -85,7 +133,16 @@ describe('getAvailableVersions', () => {
packageType: 'jre+fx',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jre&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx'
+ '?os=windows&archive_type=zip&java_package_type=jre&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
+ ],
+ [
+ {
+ version: '8',
+ architecture: 'x64',
+ packageType: 'jdk+crac',
+ checkLatest: false
+ },
+ '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=true&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -94,7 +151,7 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=64&release_status=ga'
+ '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=aarch64&release_status=ga&availability_types=ca&page=1&page_size=100'
],
[
{
@@ -103,12 +160,12 @@ describe('getAvailableVersions', () => {
packageType: 'jdk',
checkLatest: false
},
- '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=&release_status=ga'
+ '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=arm&release_status=ga&availability_types=ca&page=1&page_size=100'
]
])('build correct url for %s -> %s', async (input, parsedUrl) => {
const distribution = new ZuluDistribution(input);
distribution['getPlatformOption'] = () => 'windows';
- const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/${parsedUrl}`;
+ const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/${parsedUrl}`;
await distribution['getAvailableVersions']();
@@ -116,16 +173,12 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
});
- type DistroArch = {
- bitness: string;
- arch: string;
- };
it.each([
- ['amd64', {bitness: '64', arch: 'x86'}],
- ['arm64', {bitness: '64', arch: 'arm'}]
+ ['amd64', 'x64'],
+ ['arm64', 'aarch64']
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
- async (osArch: string, distroArch: DistroArch) => {
+ async (osArch: string, distroArch: string) => {
jest
.spyOn(os, 'arch')
.mockReturnValue(osArch as ReturnType);
@@ -137,7 +190,7 @@ describe('getAvailableVersions', () => {
checkLatest: false
});
distribution['getPlatformOption'] = () => 'windows';
- const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=${distroArch.arch}&hw_bitness=${distroArch.bitness}&release_status=ga`;
+ const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=${distroArch}&release_status=ga&availability_types=ca&page=1&page_size=100`;
await distribution['getAvailableVersions']();
@@ -147,6 +200,18 @@ describe('getAvailableVersions', () => {
);
it('load available versions', async () => {
+ spyHttpClient
+ .mockReturnValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: manifestData as IZuluVersions[]
+ })
+ .mockReturnValueOnce({
+ statusCode: 200,
+ headers: {},
+ result: [] as IZuluVersions[]
+ });
+
const distribution = new ZuluDistribution({
version: '11',
architecture: 'x86',
@@ -160,10 +225,11 @@ describe('getAvailableVersions', () => {
describe('getArchitectureOptions', () => {
it.each([
- [{architecture: 'x64'}, {arch: 'x86', hw_bitness: '64', abi: ''}],
- [{architecture: 'x86'}, {arch: 'x86', hw_bitness: '32', abi: ''}],
- [{architecture: 'x32'}, {arch: 'x32', hw_bitness: '', abi: ''}],
- [{architecture: 'arm'}, {arch: 'arm', hw_bitness: '', abi: ''}]
+ [{architecture: 'x64'}, 'x64'],
+ [{architecture: 'x86'}, 'i686'],
+ [{architecture: 'aarch64'}, 'aarch64'],
+ [{architecture: 'arm64'}, 'aarch64'],
+ [{architecture: 'arm'}, 'arm']
])('%s -> %s', (input, expected) => {
const distribution = new ZuluDistribution({
version: '11',
@@ -171,11 +237,31 @@ describe('getArchitectureOptions', () => {
packageType: 'jdk',
checkLatest: false
});
- expect(distribution['getArchitectureOptions']()).toEqual(expected);
+ expect(distribution['getArchitectureOptions']()).toBe(expected);
});
});
describe('findPackageForDownload', () => {
+ let spyPackageDetails: any;
+
+ const ZULU_CHECKSUM = 'a'.repeat(64);
+
+ beforeEach(() => {
+ // The resolved winning package fetches sha256_hash from the Azul
+ // package-details endpoint; stub it so tests never reach the real
+ // network.
+ spyPackageDetails = jest.spyOn(HttpClient.prototype, 'getJson');
+ spyPackageDetails.mockResolvedValue({
+ statusCode: 200,
+ headers: {},
+ result: {sha256_hash: ZULU_CHECKSUM}
+ });
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
it.each([
['8', '8.0.282+8'],
['11.x', '11.0.10+9'],
@@ -214,6 +300,38 @@ describe('findPackageForDownload', () => {
expect(result.url).toBe(
'https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip'
);
+ expect(result.checksum).toEqual({
+ algorithm: 'sha256',
+ value: ZULU_CHECKSUM,
+ source: 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12446'
+ });
+ // Only the winning package's UUID triggers a details request.
+ expect(spyPackageDetails).toHaveBeenCalledWith(
+ 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12446'
+ );
+ expect(spyPackageDetails).toHaveBeenCalledTimes(1);
+ });
+
+ it('skips checksum verification when sha256_hash is missing or malformed', async () => {
+ spyPackageDetails.mockResolvedValue({
+ statusCode: 200,
+ headers: {},
+ result: {sha256_hash: '123'}
+ });
+
+ const distribution = new ZuluDistribution({
+ version: '',
+ architecture: 'arm64',
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getAvailableVersions'] = async () => manifestData;
+ const result = await distribution['findPackageForDownload']('17.0.10');
+
+ expect(result.checksum).toBeUndefined();
+ expect(core.debug).toHaveBeenCalledWith(
+ expect.stringContaining('No authoritative sha256 checksum')
+ );
});
it('should throw an error', async () => {
@@ -226,6 +344,6 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData;
await expect(
distribution['findPackageForDownload'](distribution['version'])
- ).rejects.toThrow(/Could not find satisfied version for semver */);
+ ).rejects.toThrow(/No matching version found for SemVer/);
});
});
diff --git a/__tests__/gpg.test.ts b/__tests__/gpg.test.ts
index 1c981b3f5..db69e3de8 100644
--- a/__tests__/gpg.test.ts
+++ b/__tests__/gpg.test.ts
@@ -1,20 +1,40 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterAll,
+ afterEach
+} from '@jest/globals';
+import {fileURLToPath} from 'url';
+import * as fs from 'fs';
import * as path from 'path';
import * as io from '@actions/io';
-import * as exec from '@actions/exec';
-import * as gpg from '../src/gpg';
-jest.mock('@actions/exec', () => {
- return {
- exec: jest.fn()
- };
-});
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+
+jest.unstable_mockModule('@actions/exec', () => ({
+ exec: jest.fn()
+}));
+
+jest.unstable_mockModule('@actions/tool-cache', () => ({
+ downloadTool: jest.fn()
+}));
+
+const exec = await import('@actions/exec');
+const tc = await import('@actions/tool-cache');
+const gpg = await import('../src/gpg.js');
const tempDir = path.join(__dirname, 'runner', 'temp');
process.env['RUNNER_TEMP'] = tempDir;
describe('gpg tests', () => {
beforeEach(async () => {
+ await io.rmRF(tempDir);
await io.mkdirP(tempDir);
+ jest.clearAllMocks();
+ (exec.exec as jest.Mock).mockResolvedValue(0);
});
afterAll(async () => {
@@ -25,30 +45,222 @@ describe('gpg tests', () => {
}
});
+ describe('toGpgPath', () => {
+ const originalPlatform = process.platform;
+
+ afterEach(() => {
+ Object.defineProperty(process, 'platform', {value: originalPlatform});
+ });
+
+ it('returns path unchanged on non-Windows platforms', () => {
+ Object.defineProperty(process, 'platform', {value: 'linux'});
+ expect(gpg.toGpgPath('/tmp/some/path')).toBe('/tmp/some/path');
+ expect(gpg.toGpgPath('D:\\a\\_temp\\file')).toBe('D:\\a\\_temp\\file');
+ });
+
+ it('converts Windows backslashes and drive letter to POSIX path on Windows', () => {
+ Object.defineProperty(process, 'platform', {value: 'win32'});
+ expect(gpg.toGpgPath('D:\\a\\_temp\\gpg-home')).toBe(
+ '/d/a/_temp/gpg-home'
+ );
+ expect(
+ gpg.toGpgPath('C:\\Users\\runner\\AppData\\Local\\Temp\\key.asc')
+ ).toBe('/c/Users/runner/AppData/Local/Temp/key.asc');
+ });
+
+ it('handles uppercase and lowercase drive letters on Windows', () => {
+ Object.defineProperty(process, 'platform', {value: 'win32'});
+ expect(gpg.toGpgPath('d:\\a\\_temp\\file')).toBe('/d/a/_temp/file');
+ });
+ });
+
describe('importKey', () => {
- it('attempts to import private key and returns null key id on failure', async () => {
+ it('imports private keys into a unique isolated GPG home', async () => {
const privateKey = 'KEY CONTENTS';
- const keyId = await gpg.importKey(privateKey);
+ let privateKeyFile = '';
+ (exec.exec as jest.Mock).mockImplementation(
+ async (_command: string, _args: string[]) => {
+ const [createdGpgHome] = fs.readdirSync(tempDir);
+ privateKeyFile = path.join(
+ tempDir,
+ createdGpgHome,
+ fs
+ .readdirSync(path.join(tempDir, createdGpgHome))
+ .find(file => file.startsWith('private-key-')) ?? ''
+ );
+ expect(fs.readFileSync(privateKeyFile, 'utf8')).toBe(privateKey);
+ if (process.platform !== 'win32') {
+ expect(fs.statSync(privateKeyFile).mode & 0o777).toBe(0o600);
+ }
+ return 0;
+ }
+ );
- expect(keyId).toBeNull();
+ const gpgHome = await gpg.importKey(privateKey);
+ expect(path.dirname(gpgHome)).toBe(tempDir);
+ expect(path.basename(gpgHome).startsWith(gpg.GPG_HOME_PREFIX)).toBe(true);
+ expect(fs.existsSync(gpgHome)).toBe(true);
+ expect(fs.existsSync(privateKeyFile)).toBe(false);
+ if (process.platform !== 'win32') {
+ expect(fs.statSync(gpgHome).mode & 0o777).toBe(0o700);
+ }
expect(exec.exec).toHaveBeenCalledWith(
'gpg',
- expect.anything(),
- expect.anything()
+ [
+ '--homedir',
+ gpg.toGpgPath(gpgHome),
+ '--batch',
+ '--import',
+ gpg.toGpgPath(privateKeyFile)
+ ],
+ {silent: true}
);
});
+
+ it('removes the private-key file and isolated home when import fails', async () => {
+ let gpgHome = '';
+ let privateKeyFile = '';
+ (exec.exec as jest.Mock).mockImplementation(
+ async (_command: string, _args: string[]) => {
+ const [createdGpgHome] = fs.readdirSync(tempDir);
+ gpgHome = path.join(tempDir, createdGpgHome);
+ privateKeyFile = path.join(
+ gpgHome,
+ fs
+ .readdirSync(gpgHome)
+ .find(file => file.startsWith('private-key-')) ?? ''
+ );
+ expect(fs.existsSync(privateKeyFile)).toBe(true);
+ throw new Error('invalid key');
+ }
+ );
+
+ await expect(gpg.importKey('INVALID KEY')).rejects.toThrow('invalid key');
+
+ expect(fs.existsSync(privateKeyFile)).toBe(false);
+ expect(fs.existsSync(gpgHome)).toBe(false);
+ });
+
+ it('imports multi-key input without parsing or deleting fingerprints', async () => {
+ const privateKeys = 'KEY ONE\nKEY TWO';
+ (exec.exec as jest.Mock).mockImplementation(
+ async (_command: string, _args: string[]) => {
+ const [createdGpgHome] = fs.readdirSync(tempDir);
+ const keyFile = fs
+ .readdirSync(path.join(tempDir, createdGpgHome))
+ .find(file => file.startsWith('private-key-'));
+ expect(
+ fs.readFileSync(
+ path.join(tempDir, createdGpgHome, keyFile ?? ''),
+ 'utf8'
+ )
+ ).toBe(privateKeys);
+ return 0;
+ }
+ );
+
+ const gpgHome = await gpg.importKey(privateKeys);
+
+ expect(gpgHome).toContain(gpg.GPG_HOME_PREFIX);
+ expect(exec.exec).toHaveBeenCalledTimes(1);
+ expect((exec.exec as jest.Mock).mock.calls[0][1]).not.toContain(
+ '--delete-secret-and-public-key'
+ );
+ });
+
+ it('uses a separate GPG home for each invocation', async () => {
+ const firstGpgHome = await gpg.importKey('FIRST KEY');
+ const secondGpgHome = await gpg.importKey('SECOND KEY');
+
+ expect(firstGpgHome).not.toBe(secondGpgHome);
+ expect(fs.existsSync(firstGpgHome)).toBe(true);
+ expect(fs.existsSync(secondGpgHome)).toBe(true);
+ });
});
- describe('deleteKey', () => {
- it('deletes private key', async () => {
- const keyId = 'asdfhjkl';
- await gpg.deleteKey(keyId);
+ describe('removeGpgHome', () => {
+ it('removes only action-owned GPG homes and is idempotent', async () => {
+ const gpgHome = await gpg.importKey('KEY CONTENTS');
+ const unrelatedGpgHome = path.join(tempDir, 'user-gpg-home');
+ fs.mkdirSync(unrelatedGpgHome);
- expect(exec.exec).toHaveBeenCalledWith(
+ await gpg.removeGpgHome(gpgHome);
+ await gpg.removeGpgHome(gpgHome);
+
+ expect(exec.exec).toHaveBeenNthCalledWith(
+ 2,
+ 'gpgconf',
+ ['--homedir', gpg.toGpgPath(gpgHome), '--kill', 'gpg-agent'],
+ {silent: true, ignoreReturnCode: true}
+ );
+ expect(exec.exec).toHaveBeenCalledTimes(2);
+ expect(fs.existsSync(gpgHome)).toBe(false);
+ expect(fs.existsSync(unrelatedGpgHome)).toBe(true);
+ });
+
+ it('removes the GPG home when gpgconf is unavailable', async () => {
+ const gpgHome = await gpg.importKey('KEY CONTENTS');
+ (exec.exec as jest.Mock).mockRejectedValueOnce(
+ new Error('gpgconf not found')
+ );
+
+ await gpg.removeGpgHome(gpgHome);
+
+ expect(fs.existsSync(gpgHome)).toBe(false);
+ });
+
+ it('refuses to remove a GPG home it does not own', async () => {
+ const unrelatedGpgHome = path.join(tempDir, 'user-gpg-home');
+ fs.mkdirSync(unrelatedGpgHome, {recursive: true});
+
+ await expect(gpg.removeGpgHome(unrelatedGpgHome)).rejects.toThrow(
+ 'Refusing to remove unexpected GPG home'
+ );
+ expect(fs.existsSync(unrelatedGpgHome)).toBe(true);
+ });
+ });
+
+ describe('verifyPackageSignature', () => {
+ it('imports bundled key and verifies package', async () => {
+ const publicKeyContent =
+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest\n-----END PGP PUBLIC KEY BLOCK-----';
+ (tc.downloadTool as jest.Mock).mockResolvedValue(
+ '/tmp/jdk.tar.gz.sig'
+ );
+ await gpg.verifyPackageSignature(
+ '/tmp/jdk.tar.gz',
+ 'https://example.com/jdk.tar.gz.sig',
+ publicKeyContent
+ );
+
+ expect(tc.downloadTool).toHaveBeenCalledWith(
+ 'https://example.com/jdk.tar.gz.sig'
+ );
+ expect(exec.exec).toHaveBeenNthCalledWith(
+ 1,
+ 'gpg',
+ [
+ '--homedir',
+ expect.any(String),
+ '--batch',
+ '--import',
+ expect.stringContaining('public-key.asc')
+ ],
+ expect.objectContaining({silent: true})
+ );
+ expect(exec.exec).toHaveBeenNthCalledWith(
+ 2,
'gpg',
- expect.anything(),
- expect.anything()
+ [
+ '--homedir',
+ expect.any(String),
+ '--batch',
+ '--verify',
+ '/tmp/jdk.tar.gz.sig',
+ '/tmp/jdk.tar.gz'
+ ],
+ expect.objectContaining({silent: true})
);
});
});
diff --git a/__tests__/java-package-contract.test.ts b/__tests__/java-package-contract.test.ts
new file mode 100644
index 000000000..457b0a491
--- /dev/null
+++ b/__tests__/java-package-contract.test.ts
@@ -0,0 +1,82 @@
+import fs from 'fs';
+import path from 'path';
+import {
+ JAVA_PACKAGE_CAPABILITIES,
+ JavaDistribution
+} from '../src/distributions/package-types.js';
+
+const repositoryRoot = process.cwd();
+const readRepositoryFile = (filePath: string) =>
+ fs.readFileSync(path.join(repositoryRoot, filePath), 'utf8');
+const allPackageTypes = [
+ ...new Set(Object.values(JAVA_PACKAGE_CAPABILITIES).flat())
+];
+
+describe('java-package published contract', () => {
+ it.each(['action.yml', 'README.md'])(
+ 'documents every supported package type in %s',
+ filePath => {
+ const content = readRepositoryFile(filePath);
+ const contractLine =
+ filePath === 'action.yml'
+ ? content.match(/ {2}java-package:\n(?: {4}.+\n)+/)?.[0]
+ : content
+ .split('\n')
+ .find(line => line.includes('| `java-package` |'));
+
+ expect(contractLine).toBeDefined();
+ for (const packageType of allPackageTypes) {
+ expect(contractLine).toContain(`\`${packageType}\``);
+ }
+ }
+ );
+
+ it.each(Object.entries(JAVA_PACKAGE_CAPABILITIES))(
+ 'keeps the advanced compatibility table aligned for %s',
+ (distributionName, packageTypes) => {
+ const advancedUsage = readRepositoryFile('docs/advanced-usage.md');
+ const compatibilityTable = advancedUsage.slice(
+ advancedUsage.indexOf('### Package compatibility')
+ );
+ const compatibilityRow = compatibilityTable
+ .split('\n')
+ .find(
+ line =>
+ line.startsWith('|') && line.includes(`\`${distributionName}\``)
+ );
+
+ expect(compatibilityRow).toBeDefined();
+ for (const packageType of packageTypes) {
+ expect(compatibilityRow).toContain(`\`${packageType}\``);
+ }
+ }
+ );
+
+ it('only exercises supported distribution/package combinations in E2E', () => {
+ const workflow = readRepositoryFile('.github/workflows/e2e-versions.yml');
+ const defaultMatrix = workflow.match(
+ /distribution:\s*\n\s*\[([^\]]+)\]\s*\n\s*java-package:\s*\['([^']+)'\]/
+ );
+ expect(defaultMatrix).not.toBeNull();
+
+ const defaultDistributions = [
+ ...defaultMatrix![1].matchAll(/'([^']+)'/g)
+ ].map(match => match[1]);
+ const defaultPackage = defaultMatrix![2];
+ for (const distributionName of defaultDistributions) {
+ expect(supportedPackagesFor(distributionName)).toContain(defaultPackage);
+ }
+
+ const includedPackages = workflow.matchAll(
+ /- distribution: '([^']+)'\s*\n\s*java-package: ([^\s]+)/g
+ );
+ for (const match of includedPackages) {
+ const [, distributionName, packageType] = match;
+ expect(supportedPackagesFor(distributionName)).toContain(packageType);
+ }
+ });
+});
+
+function supportedPackagesFor(distributionName: string): readonly string[] {
+ return JAVA_PACKAGE_CAPABILITIES[distributionName as JavaDistribution] ?? [];
+}
diff --git a/__tests__/java-platform-contract.test.ts b/__tests__/java-platform-contract.test.ts
new file mode 100644
index 000000000..187a54a48
--- /dev/null
+++ b/__tests__/java-platform-contract.test.ts
@@ -0,0 +1,158 @@
+import fs from 'fs';
+import path from 'path';
+import {
+ getJavaPlatformIdentity,
+ isAlpineLinux,
+ JAVA_PLATFORM_CAPABILITIES,
+ normalizeArchitecture,
+ validateJavaPlatform
+} from '../src/distributions/platform-types.js';
+import {JavaDistribution} from '../src/distributions/package-types.js';
+
+describe('Java platform capabilities', () => {
+ it('declares a capability for every distribution', () => {
+ expect(Object.keys(JAVA_PLATFORM_CAPABILITIES).sort()).toEqual(
+ Object.values(JavaDistribution).sort()
+ );
+ });
+
+ it.each([
+ ['x64', 'x64'],
+ ['amd64', 'x64'],
+ ['x86', 'x86'],
+ ['ia32', 'x86'],
+ ['arm', 'armv7'],
+ ['aarch64', 'aarch64'],
+ ['arm64', 'aarch64'],
+ ['ppc64le', 'ppc64le'],
+ ['s390x', 's390x']
+ ])('normalizes architecture %s to %s', (input, expected) => {
+ expect(normalizeArchitecture(input)).toBe(expected);
+ });
+
+ it.each([
+ ['linux', false, 'linux-glibc'],
+ ['linux', true, 'linux-musl'],
+ ['darwin', false, 'macos'],
+ ['win32', false, 'windows'],
+ // Exercises the normalizePlatform alias path and the `?? platform`
+ // fallback for a platform that has no Java alias.
+ ['sunos', false, 'solaris'],
+ ['aix', false, 'aix']
+ ] as const)(
+ 'identifies %s with Alpine release %s as %s',
+ (platform, alpineReleaseExists, expected) => {
+ expect(getJavaPlatformIdentity(platform, alpineReleaseExists)).toBe(
+ expected
+ );
+ }
+ );
+
+ // The platform check has to short-circuit before the filesystem probe, so a
+ // stray /etc/alpine-release can never make a non-Linux runner look like musl.
+ it.each([
+ ['linux', true, true],
+ ['linux', false, false],
+ ['darwin', true, false],
+ ['win32', true, false]
+ ] as const)(
+ 'treats %s with Alpine release %s as Alpine: %s',
+ (platform, alpineReleaseExists, expected) => {
+ expect(isAlpineLinux(platform, alpineReleaseExists)).toBe(expected);
+ }
+ );
+
+ it('uses the normalized architecture for validation', () => {
+ expect(validateJavaPlatform('microsoft', 'linux', 'arm64', '25')).toBe(
+ 'aarch64'
+ );
+ });
+
+ it('rejects OS-specific restrictions with a consistent diagnostic', () => {
+ expect(() =>
+ validateJavaPlatform('oracle', 'win32', 'arm64', '21')
+ ).toThrow(
+ "Distribution 'oracle' does not support operating system 'windows' with architecture 'aarch64' for Java version '21'. Supported combinations: linux (x64, aarch64); macos (x64, aarch64); windows (x64)."
+ );
+ });
+
+ it('rejects version-dependent architecture restrictions', () => {
+ expect(() =>
+ validateJavaPlatform('corretto', 'linux', 'x86', '17')
+ ).toThrow(/x86 \(<12\)/);
+ expect(() =>
+ validateJavaPlatform('corretto', 'linux', 'x86', '17.0.2.8.1')
+ ).toThrow(/x86 \(<12\)/);
+ expect(validateJavaPlatform('corretto', 'linux', 'x86', '11')).toBe('x86');
+ });
+
+ it.each(['corretto', 'kona'])(
+ 'rejects Windows aarch64 for %s',
+ distributionName => {
+ expect(() =>
+ validateJavaPlatform(distributionName, 'win32', 'arm64', '21')
+ ).toThrow(/does not support operating system 'windows'/);
+ }
+ );
+
+ it('allows local archives on any platform and architecture', () => {
+ expect(validateJavaPlatform('jdkfile', 'aix', 'mips64', '21')).toBe(
+ 'mips64'
+ );
+ });
+
+ it('keeps the documented architecture contract aligned', () => {
+ const repositoryRoot = process.cwd();
+ const readRepositoryFile = (filePath: string) =>
+ fs.readFileSync(path.join(repositoryRoot, filePath), 'utf8');
+
+ for (const filePath of ['action.yml', 'README.md']) {
+ const content = readRepositoryFile(filePath);
+ for (const architecture of [
+ 'x86',
+ 'x64',
+ 'armv7',
+ 'aarch64',
+ 'ppc64le',
+ 'ppc64',
+ 's390x'
+ ]) {
+ expect(content).toContain(architecture);
+ }
+ }
+ });
+
+ it.each(Object.entries(JAVA_PLATFORM_CAPABILITIES))(
+ 'keeps the advanced compatibility table aligned for %s',
+ (distributionName, capability) => {
+ const advancedUsage = fs.readFileSync(
+ path.join(process.cwd(), 'docs/advanced-usage.md'),
+ 'utf8'
+ );
+ const compatibilityTable = advancedUsage.slice(
+ advancedUsage.indexOf('## Platform and architecture compatibility')
+ );
+ const compatibilityRow = compatibilityTable
+ .split('\n')
+ .find(
+ line =>
+ line.startsWith('|') && line.includes(`\`${distributionName}\``)
+ );
+
+ expect(compatibilityRow).toBeDefined();
+ if (!('platforms' in capability)) {
+ expect(compatibilityRow).toContain('Any');
+ return;
+ }
+
+ const architectures = new Set(
+ Object.values(capability.platforms)
+ .flat()
+ .map(item => (typeof item === 'string' ? item : item.architecture))
+ );
+ for (const architecture of architectures) {
+ expect(compatibilityRow).toContain(`\`${architecture}\``);
+ }
+ }
+ );
+});
diff --git a/__tests__/jdk-cache.test.ts b/__tests__/jdk-cache.test.ts
new file mode 100644
index 000000000..63788a78d
--- /dev/null
+++ b/__tests__/jdk-cache.test.ts
@@ -0,0 +1,325 @@
+import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
+import fs from 'fs';
+import os from 'os';
+import path from 'path';
+
+jest.unstable_mockModule('@actions/cache', () => ({
+ restoreCache: jest.fn(),
+ saveCache: jest.fn(),
+ ReserveCacheError: class ReserveCacheError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'ReserveCacheError';
+ }
+ }
+}));
+
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/cache-feature.js', () => ({
+ isCacheFeatureAvailable: jest.fn()
+}));
+
+const cache = await import('@actions/cache');
+const core = await import('@actions/core');
+const cacheFeature = await import('../src/cache-feature.js');
+const {
+ buildJdkCacheKey,
+ getJdkVerificationIdentity,
+ registerJdk,
+ restoreJdk,
+ saveJdkCaches
+} = await import('../src/jdk-cache.js');
+
+const jdk = {
+ distribution: 'temurin',
+ packageType: 'jdk',
+ architecture: 'x64',
+ version: '21.0.8+9',
+ source: 'sha256:abc123',
+ verification: 'unverified',
+ path: '/toolcache/Java_temurin_jdk/21.0.8-9'
+};
+
+describe('JDK cache', () => {
+ const tempRoots: string[] = [];
+
+ const createInstallation = (marker = 'a'): string => {
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-java-jdk-'));
+ tempRoots.push(root);
+ const jdkPath = path.join(root, 'Java_temurin_jdk', '21.0.8-9');
+ writeInstallation(jdkPath, marker);
+ return jdkPath;
+ };
+
+ const writeInstallation = (jdkPath: string, marker: string): void => {
+ const architecturePath = path.join(jdkPath, 'x64');
+ fs.rmSync(architecturePath, {recursive: true, force: true});
+ fs.rmSync(`${architecturePath}.complete`, {force: true});
+ fs.mkdirSync(path.join(architecturePath, 'bin'), {recursive: true});
+ fs.writeFileSync(path.join(architecturePath, 'bin', 'java'), marker);
+ fs.writeFileSync(`${architecturePath}.complete`, marker);
+ };
+
+ const lastState = (): string =>
+ ((core.saveState as jest.Mock).mock.calls.at(-1) as string[])[1];
+
+ beforeEach(() => {
+ jest.resetAllMocks();
+ (cacheFeature.isCacheFeatureAvailable as jest.Mock).mockReturnValue(true);
+ process.env['RUNNER_OS'] = 'Linux';
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ delete process.env['RUNNER_OS'];
+ while (tempRoots.length) {
+ fs.rmSync(tempRoots.pop()!, {recursive: true, force: true});
+ }
+ });
+
+ it('builds distinct keys for incompatible JDK identities', () => {
+ const key = buildJdkCacheKey(jdk);
+
+ expect(key).toMatch(/^setup-java-jdk-v1-Linux-x64-[a-f0-9]{64}$/);
+ expect(buildJdkCacheKey({...jdk, architecture: 'aarch64'})).not.toBe(key);
+ expect(buildJdkCacheKey({...jdk, distribution: 'zulu'})).not.toBe(key);
+ expect(buildJdkCacheKey({...jdk, packageType: 'jre'})).not.toBe(key);
+ expect(buildJdkCacheKey({...jdk, version: '21.0.7+6'})).not.toBe(key);
+ expect(buildJdkCacheKey({...jdk, source: 'sha256:def456'})).not.toBe(key);
+ });
+
+ it('preserves canonical runner OS values and separates operating systems', () => {
+ process.env['RUNNER_OS'] = 'Linux';
+ const linux = buildJdkCacheKey(jdk);
+ process.env['RUNNER_OS'] = 'Windows';
+ const windows = buildJdkCacheKey(jdk);
+ process.env['RUNNER_OS'] = 'macOS';
+ const macos = buildJdkCacheKey(jdk);
+
+ expect(new Set([linux, windows, macos])).toHaveProperty('size', 3);
+ expect(linux).toMatch(/^setup-java-jdk-v1-Linux-x64-/);
+ expect(windows).toMatch(/^setup-java-jdk-v1-Windows-x64-/);
+ expect(macos).toMatch(/^setup-java-jdk-v1-macOS-x64-/);
+ });
+
+ it('falls back to process.platform without RUNNER_OS', () => {
+ delete process.env['RUNNER_OS'];
+
+ expect(buildJdkCacheKey(jdk)).toMatch(
+ new RegExp(`^setup-java-jdk-v1-${process.platform}-x64-`)
+ );
+ });
+
+ it('separates unverified, bundled-key, and custom-key caches', () => {
+ const unverified = getJdkVerificationIdentity(false);
+ const bundled = getJdkVerificationIdentity(true);
+ const customA = getJdkVerificationIdentity(
+ true,
+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nkey-a\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n'
+ );
+ const customANormalized = getJdkVerificationIdentity(
+ true,
+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey-a\n-----END PGP PUBLIC KEY BLOCK-----'
+ );
+ const customB = getJdkVerificationIdentity(true, 'different-key');
+
+ expect(new Set([unverified, bundled, customA, customB])).toHaveProperty(
+ 'size',
+ 4
+ );
+ expect(customA).toBe(customANormalized);
+ expect(customA).not.toContain('key-a');
+ expect(
+ new Set(
+ [unverified, bundled, customA, customB].map(verification =>
+ buildJdkCacheKey({...jdk, verification})
+ )
+ )
+ ).toHaveProperty('size', 4);
+ });
+
+ it('restores and records an exact JDK cache hit', async () => {
+ (cache.restoreCache as jest.Mock).mockResolvedValue(buildJdkCacheKey(jdk));
+ jest.spyOn(fs, 'existsSync').mockReturnValue(true);
+
+ await expect(restoreJdk(jdk)).resolves.toBe(true);
+
+ expect(cache.restoreCache).toHaveBeenCalledWith(
+ [jdk.path],
+ buildJdkCacheKey(jdk)
+ );
+ const architecturePath = path.join(jdk.path, 'x64');
+ expect(fs.existsSync).toHaveBeenCalledWith(architecturePath);
+ expect(fs.existsSync).toHaveBeenCalledWith(`${architecturePath}.complete`);
+ expect(core.saveState).toHaveBeenCalledWith(
+ 'jdk-caches',
+ expect.stringContaining(buildJdkCacheKey(jdk))
+ );
+ });
+
+ it('falls back to download when restoration fails', async () => {
+ (cache.restoreCache as jest.Mock).mockRejectedValue(
+ new Error('cache unavailable')
+ );
+
+ await expect(restoreJdk(jdk)).resolves.toBe(false);
+ expect(core.warning).toHaveBeenCalledWith(
+ 'Failed to restore JDK cache: cache unavailable'
+ );
+ });
+
+ it('saves a downloaded JDK registered after installation', async () => {
+ const jdkPath = createInstallation();
+ const installed = {...jdk, path: jdkPath};
+ const key = buildJdkCacheKey(installed);
+ (cache.restoreCache as jest.Mock).mockResolvedValue(undefined);
+
+ await restoreJdk(installed);
+ registerJdk(installed);
+ (core.getState as jest.Mock).mockReturnValue(lastState());
+ (cache.saveCache as jest.Mock).mockResolvedValue(1);
+
+ await saveJdkCaches();
+
+ expect(cache.saveCache).toHaveBeenCalledWith([jdkPath], key);
+ });
+
+ it('does not save an installation that was replaced after registration', async () => {
+ const jdkPath = createInstallation();
+ const installed = {...jdk, path: jdkPath};
+ const key = buildJdkCacheKey(installed);
+
+ registerJdk(installed);
+ (core.getState as jest.Mock).mockReturnValue(lastState());
+ writeInstallation(jdkPath, 'replaced-by-a-later-step');
+
+ await saveJdkCaches();
+
+ expect(cache.saveCache).not.toHaveBeenCalledWith([jdkPath], key);
+ expect(core.warning).toHaveBeenCalledWith(
+ expect.stringContaining('was replaced after it was registered')
+ );
+ });
+
+ it('saves only the key matching the installation that occupies the path', async () => {
+ const jdkPath = createInstallation();
+ const verified = {...jdk, path: jdkPath, verification: 'verified:bundled'};
+ const unverified = {...jdk, path: jdkPath};
+
+ registerJdk(verified);
+ writeInstallation(jdkPath, 'force-downloaded-without-verification');
+ registerJdk(unverified);
+ (core.getState as jest.Mock).mockReturnValue(lastState());
+ (cache.saveCache as jest.Mock).mockResolvedValue(1);
+
+ await saveJdkCaches();
+
+ expect(cache.saveCache).not.toHaveBeenCalledWith(
+ [jdkPath],
+ buildJdkCacheKey(verified)
+ );
+ expect(cache.saveCache).toHaveBeenCalledWith(
+ [jdkPath],
+ buildJdkCacheKey(unverified)
+ );
+ });
+
+ it('does not save a path that was never registered as installed', async () => {
+ const jdkPath = createInstallation();
+ const installed = {...jdk, path: jdkPath};
+ (cache.restoreCache as jest.Mock).mockResolvedValue(undefined);
+
+ await restoreJdk(installed);
+ (core.getState as jest.Mock).mockReturnValue(lastState());
+
+ await saveJdkCaches();
+
+ expect(cache.saveCache).not.toHaveBeenCalledWith(
+ [jdkPath],
+ buildJdkCacheKey(installed)
+ );
+ });
+
+ it('keeps saving the remaining JDK caches when one save fails', async () => {
+ const failingPath = createInstallation();
+ const succeedingPath = createInstallation();
+ const failing = {...jdk, path: failingPath};
+ const succeeding = {...jdk, path: succeedingPath, version: '17.0.19+9'};
+
+ registerJdk(failing);
+ registerJdk(succeeding);
+ (core.getState as jest.Mock).mockReturnValue(lastState());
+ (cache.saveCache as jest.Mock).mockImplementation(
+ async (paths: unknown) => {
+ if ((paths as string[])[0] === failingPath) {
+ throw new Error('cache service unavailable');
+ }
+ return 1;
+ }
+ );
+
+ await expect(saveJdkCaches()).resolves.toBeUndefined();
+
+ expect(cache.saveCache).toHaveBeenCalledWith(
+ [succeedingPath],
+ buildJdkCacheKey(succeeding)
+ );
+ expect(core.warning).toHaveBeenCalledWith(
+ expect.stringContaining('cache service unavailable')
+ );
+ expect(core.info).toHaveBeenCalledWith(
+ `JDK cache saved with the key: ${buildJdkCacheKey(succeeding)}`
+ );
+ });
+
+ it('reports a reserved cache key without failing the remaining saves', async () => {
+ const reservedPath = createInstallation();
+ const reserved = {...jdk, path: reservedPath};
+
+ registerJdk(reserved);
+ (core.getState as jest.Mock).mockReturnValue(lastState());
+ (cache.saveCache as jest.Mock).mockRejectedValue(
+ new cache.ReserveCacheError('Unable to reserve cache')
+ );
+
+ await expect(saveJdkCaches()).resolves.toBeUndefined();
+
+ expect(core.info).toHaveBeenCalledWith('Unable to reserve cache');
+ });
+
+ it('registers a force-downloaded JDK without restoring it', () => {
+ const jdkPath = createInstallation();
+ registerJdk({...jdk, path: jdkPath});
+
+ expect(cache.restoreCache).not.toHaveBeenCalled();
+ expect(core.saveState).toHaveBeenCalledWith(
+ 'jdk-caches',
+ expect.stringContaining(buildJdkCacheKey({...jdk, path: jdkPath}))
+ );
+ });
+
+ it('does not save an exact JDK cache hit again', async () => {
+ const key = buildJdkCacheKey(jdk);
+ (core.getState as jest.Mock).mockReturnValue(
+ JSON.stringify([
+ {
+ key,
+ path: jdk.path,
+ architecture: jdk.architecture,
+ matchedKey: key
+ }
+ ])
+ );
+
+ await saveJdkCaches();
+
+ expect(cache.saveCache).not.toHaveBeenCalled();
+ });
+});
diff --git a/__tests__/jdk-resolution-cache.test.ts b/__tests__/jdk-resolution-cache.test.ts
new file mode 100644
index 000000000..9c6703fc6
--- /dev/null
+++ b/__tests__/jdk-resolution-cache.test.ts
@@ -0,0 +1,416 @@
+import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
+import fs from 'fs';
+import os from 'os';
+import path from 'path';
+
+jest.unstable_mockModule('@actions/cache', () => ({
+ isFeatureAvailable: jest.fn(),
+ restoreCache: jest.fn(),
+ saveCache: jest.fn()
+}));
+
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn()
+}));
+
+const cache = await import('@actions/cache');
+const core = await import('@actions/core');
+const {restoreJdkResolution, registerJdkResolution, saveJdkResolutionCaches} =
+ await import('../src/jdk-resolution-cache.js');
+
+const request = {
+ distribution: 'Temurin-Hotspot',
+ packageType: 'jdk',
+ platform: 'linux-glibc',
+ architecture: 'x64',
+ versionSpec: '21',
+ stable: true
+};
+
+const release = {
+ version: '21.0.8+9',
+ url: 'https://example.com/jdk-21.0.8.tar.gz',
+ checksum: {algorithm: 'sha256' as const, value: 'abc123'}
+};
+
+const WEEK = 7 * 24 * 60 * 60 * 1000;
+const bucket = () =>
+ new Date(Math.floor(Date.now() / WEEK) * WEEK).toISOString().slice(0, 10);
+
+describe('JDK resolution cache', () => {
+ const tempRoots: string[] = [];
+ let originalTemp: string | undefined;
+ let originalOs: string | undefined;
+
+ const createRunnerTemp = (): string => {
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-java-res-'));
+ tempRoots.push(root);
+ process.env['RUNNER_TEMP'] = root;
+ return root;
+ };
+
+ /** Emulates the cache service materializing the entry at the requested path. */
+ const restoreWith = (contents: string, matchedKey: string) => {
+ jest
+ .mocked(cache.restoreCache)
+ .mockImplementation(async (paths: string[]) => {
+ fs.mkdirSync(paths[0], {recursive: true});
+ fs.writeFileSync(path.join(paths[0], 'release.json'), contents);
+ return matchedKey;
+ });
+ };
+
+ beforeEach(() => {
+ originalTemp = process.env['RUNNER_TEMP'];
+ originalOs = process.env['RUNNER_OS'];
+ process.env['RUNNER_OS'] = 'Linux';
+ jest.mocked(cache.isFeatureAvailable).mockReturnValue(true);
+ jest.mocked(cache.restoreCache).mockResolvedValue(undefined);
+ jest.mocked(cache.saveCache).mockResolvedValue(1);
+ jest.mocked(core.getState).mockReturnValue('');
+ });
+
+ afterEach(() => {
+ process.env['RUNNER_TEMP'] = originalTemp;
+ process.env['RUNNER_OS'] = originalOs;
+ if (originalTemp === undefined) {
+ delete process.env['RUNNER_TEMP'];
+ }
+ if (originalOs === undefined) {
+ delete process.env['RUNNER_OS'];
+ }
+ while (tempRoots.length > 0) {
+ fs.rmSync(tempRoots.pop()!, {recursive: true, force: true});
+ }
+ jest.resetAllMocks();
+ });
+
+ describe('restoreJdkResolution', () => {
+ it('looks the entry up with a bucket-independent path', async () => {
+ const runnerTemp = createRunnerTemp();
+ await restoreJdkResolution(request);
+
+ const [paths, primaryKey, restoreKeys] = jest.mocked(cache.restoreCache)
+ .mock.calls[0] as [string[], string, string[]];
+ expect(paths).toHaveLength(1);
+ expect(
+ paths[0].startsWith(path.join(runnerTemp, 'setup-java-jdk-resolution'))
+ ).toBe(true);
+ expect(paths[0]).not.toContain(bucket());
+ expect(primaryKey).toBe(`${restoreKeys[0]}${bucket()}`);
+ expect(restoreKeys[0]).toMatch(
+ /^setup-java-jdkres-v2-Linux-x64-[0-9a-f]{64}-$/
+ );
+ });
+
+ it('separates glibc and musl Linux resolutions', async () => {
+ createRunnerTemp();
+ await restoreJdkResolution(request);
+ const [glibcPaths, glibcKey] = jest.mocked(cache.restoreCache).mock
+ .calls[0] as [string[], string];
+
+ await restoreJdkResolution({...request, platform: 'linux-musl'});
+ const [muslPaths, muslKey] = jest.mocked(cache.restoreCache).mock
+ .calls[1] as [string[], string];
+
+ expect(muslKey).not.toBe(glibcKey);
+ expect(muslPaths).not.toEqual(glibcPaths);
+ });
+
+ it('holds the key steady for a week and then rolls it', async () => {
+ createRunnerTemp();
+ const nowSpy = jest.spyOn(Date, 'now');
+ const keyAt = async (ms: number) => {
+ nowSpy.mockReturnValue(ms);
+ await restoreJdkResolution(request);
+ return jest.mocked(cache.restoreCache).mock.calls.at(-1)![1] as string;
+ };
+
+ // A window boundary, so the offsets below are unambiguous.
+ const windowStart = 2900 * WEEK;
+
+ const start = await keyAt(windowStart);
+ const sameWindow = await keyAt(windowStart + 6 * 24 * 60 * 60 * 1000);
+ const nextWindow = await keyAt(windowStart + WEEK);
+
+ expect(sameWindow).toBe(start);
+ expect(nextWindow).not.toBe(start);
+ nowSpy.mockRestore();
+ });
+
+ it('reports a hit on the current bucket as fresh', async () => {
+ createRunnerTemp();
+ const key = `setup-java-jdkres-v2-Linux-x64-${'0'.repeat(64)}-${bucket()}`;
+ restoreWith(JSON.stringify(release), key);
+
+ // The key the module computes is the one it passes to restoreCache, so
+ // echo it back to emulate an exact hit.
+ jest
+ .mocked(cache.restoreCache)
+ .mockImplementation(async (paths: string[], primaryKey: string) => {
+ fs.mkdirSync(paths[0], {recursive: true});
+ fs.writeFileSync(
+ path.join(paths[0], 'release.json'),
+ JSON.stringify(release)
+ );
+ return primaryKey;
+ });
+
+ const restored = await restoreJdkResolution(request);
+ expect(restored?.fresh).toBe(true);
+ expect(restored?.release).toEqual(release);
+ });
+
+ it('reports a hit on an older bucket as stale', async () => {
+ createRunnerTemp();
+ restoreWith(JSON.stringify(release), 'setup-java-jdkres-v2-old');
+
+ const restored = await restoreJdkResolution(request);
+ expect(restored?.fresh).toBe(false);
+ expect(restored?.release).toEqual(release);
+ });
+
+ it('returns nothing when the entry is missing', async () => {
+ createRunnerTemp();
+ await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
+ });
+
+ it('returns nothing when the cache service is unavailable', async () => {
+ createRunnerTemp();
+ jest.mocked(cache.isFeatureAvailable).mockReturnValue(false);
+
+ await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
+ expect(cache.restoreCache).not.toHaveBeenCalled();
+ });
+
+ it('returns nothing when RUNNER_TEMP is not set', async () => {
+ delete process.env['RUNNER_TEMP'];
+
+ await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
+ expect(cache.restoreCache).not.toHaveBeenCalled();
+ });
+
+ it('does not fail the job when the restore throws', async () => {
+ createRunnerTemp();
+ jest
+ .mocked(cache.restoreCache)
+ .mockRejectedValue(new Error('service unavailable'));
+
+ await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
+ });
+
+ it.each([
+ ['malformed JSON', 'not json'],
+ ['a non-object payload', '"nope"'],
+ [
+ 'a missing version',
+ JSON.stringify({url: 'https://example.com/a.tar.gz'})
+ ],
+ ['a missing url', JSON.stringify({version: '21.0.8+9'})],
+ [
+ 'a non-HTTPS url',
+ JSON.stringify({
+ version: '21.0.8+9',
+ url: 'http://example.com/a.tar.gz'
+ })
+ ],
+ [
+ 'a malformed url',
+ JSON.stringify({version: '21.0.8+9', url: 'not-a-url'})
+ ],
+ [
+ 'a non-HTTPS signature url',
+ JSON.stringify({
+ version: '21.0.8+9',
+ url: 'https://example.com/a.tar.gz',
+ signatureUrl: 'http://example.com/a.sig'
+ })
+ ],
+ [
+ 'an unsupported checksum algorithm',
+ JSON.stringify({
+ version: '21.0.8+9',
+ url: 'https://example.com/a.tar.gz',
+ checksum: {algorithm: 'md5', value: 'abc'}
+ })
+ ],
+ [
+ 'a checksum without a value',
+ JSON.stringify({
+ version: '21.0.8+9',
+ url: 'https://example.com/a.tar.gz',
+ checksum: {algorithm: 'sha256'}
+ })
+ ]
+ ])('rejects an entry with %s', async (_name, contents) => {
+ createRunnerTemp();
+ restoreWith(contents, 'setup-java-jdkres-v2-old');
+
+ await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
+ });
+
+ it('keeps the optional fields of a valid entry', async () => {
+ createRunnerTemp();
+ const full = {
+ version: '21.0.8+9',
+ url: 'https://example.com/a.tar.gz',
+ signatureUrl: 'https://example.com/a.sig',
+ checksum: {
+ algorithm: 'sha512',
+ value: 'def456',
+ source: 'https://example.com/a.sha512'
+ },
+ floating: true
+ };
+ restoreWith(JSON.stringify(full), 'setup-java-jdkres-v2-old');
+
+ const restored = await restoreJdkResolution(request);
+ expect(restored?.release).toEqual(full);
+ });
+
+ it('ignores unknown fields rather than passing them through', async () => {
+ createRunnerTemp();
+ restoreWith(
+ JSON.stringify({...release, evil: 'payload'}),
+ 'setup-java-jdkres-v2-old'
+ );
+
+ const restored = await restoreJdkResolution(request);
+ expect(restored?.release).toEqual(release);
+ });
+ });
+
+ describe('registerJdkResolution', () => {
+ it('writes the release and records it under the current bucket', () => {
+ createRunnerTemp();
+ registerJdkResolution(request, release);
+
+ const state = JSON.parse(
+ jest.mocked(core.saveState).mock.calls.at(-1)![1] as string
+ );
+ const entry = state.at(-1);
+ expect(entry.key.endsWith(bucket())).toBe(true);
+ expect(
+ JSON.parse(
+ fs.readFileSync(path.join(entry.path, 'release.json'), 'utf8')
+ )
+ ).toEqual(release);
+ });
+
+ it('does nothing when the cache service is unavailable', () => {
+ createRunnerTemp();
+ jest.mocked(cache.isFeatureAvailable).mockReturnValue(false);
+
+ registerJdkResolution(request, release);
+ expect(core.saveState).not.toHaveBeenCalled();
+ });
+
+ it('does nothing when RUNNER_TEMP is not set', () => {
+ delete process.env['RUNNER_TEMP'];
+
+ registerJdkResolution(request, release);
+ expect(core.saveState).not.toHaveBeenCalled();
+ });
+
+ it('uses different keys for different requests', () => {
+ createRunnerTemp();
+ registerJdkResolution(request, release);
+ registerJdkResolution({...request, distribution: 'zulu'}, release);
+
+ const state = JSON.parse(
+ jest.mocked(core.saveState).mock.calls.at(-1)![1] as string
+ );
+ expect(new Set(state.map((item: {key: string}) => item.key)).size).toBe(
+ state.length
+ );
+ });
+
+ it('uses different keys for different floating artifact identities', () => {
+ createRunnerTemp();
+ registerJdkResolution({...request, source: 'sha256:first'}, release);
+ registerJdkResolution({...request, source: 'sha256:second'}, release);
+
+ const state = JSON.parse(
+ jest.mocked(core.saveState).mock.calls.at(-1)![1] as string
+ );
+ expect(new Set(state.map((item: {key: string}) => item.key)).size).toBe(
+ state.length
+ );
+ });
+ });
+
+ describe('saveJdkResolutionCaches', () => {
+ const stateFor = (cachePath: string) =>
+ JSON.stringify([
+ {
+ key: 'setup-java-jdkres-v2-key',
+ path: cachePath,
+ release: JSON.stringify(release)
+ }
+ ]);
+
+ it('does nothing without state', async () => {
+ await saveJdkResolutionCaches();
+ expect(cache.saveCache).not.toHaveBeenCalled();
+ });
+
+ it('saves a recorded entry', async () => {
+ const root = createRunnerTemp();
+ jest.mocked(core.getState).mockReturnValue(stateFor(root));
+
+ await saveJdkResolutionCaches();
+ expect(cache.saveCache).toHaveBeenCalledWith(
+ [root],
+ 'setup-java-jdkres-v2-key'
+ );
+ });
+
+ it('saves the payload the key was computed for, not the file on disk', async () => {
+ const root = createRunnerTemp();
+ jest.mocked(core.getState).mockReturnValue(stateFor(root));
+ // A restore performed by a later step replaces the file behind the key.
+ fs.writeFileSync(
+ path.join(root, 'release.json'),
+ JSON.stringify({version: '8.0.1+1', url: 'https://example.com/stale'})
+ );
+
+ await saveJdkResolutionCaches();
+
+ expect(
+ JSON.parse(fs.readFileSync(path.join(root, 'release.json'), 'utf8'))
+ ).toEqual(release);
+ expect(cache.saveCache).toHaveBeenCalled();
+ });
+
+ it('does not fail the job when the payload cannot be written', async () => {
+ const root = createRunnerTemp();
+ const blocked = path.join(root, 'blocked');
+ fs.writeFileSync(blocked, 'not a directory');
+ jest.mocked(core.getState).mockReturnValue(stateFor(blocked));
+
+ await expect(saveJdkResolutionCaches()).resolves.toBeUndefined();
+ expect(cache.saveCache).not.toHaveBeenCalled();
+ });
+
+ it('does not fail the job when the save throws', async () => {
+ const root = createRunnerTemp();
+ jest.mocked(core.getState).mockReturnValue(stateFor(root));
+ jest
+ .mocked(cache.saveCache)
+ .mockRejectedValue(new Error('already reserved'));
+
+ await expect(saveJdkResolutionCaches()).resolves.toBeUndefined();
+ });
+
+ it('does not fail the job on invalid state', async () => {
+ jest.mocked(core.getState).mockReturnValue('{}');
+
+ await expect(saveJdkResolutionCaches()).resolves.toBeUndefined();
+ expect(cache.saveCache).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/__tests__/maven-args.test.ts b/__tests__/maven-args.test.ts
new file mode 100644
index 000000000..4ad6acd6c
--- /dev/null
+++ b/__tests__/maven-args.test.ts
@@ -0,0 +1,130 @@
+import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
+
+const mockGetInput = jest.fn<(...args: any[]) => any>();
+const mockExportVariable = jest.fn<(...args: any[]) => any>();
+const mockInfo = jest.fn<(...args: any[]) => any>();
+const mockDebug = jest.fn<(...args: any[]) => any>();
+const mockWarning = jest.fn<(...args: any[]) => any>();
+
+jest.unstable_mockModule('@actions/core', () => ({
+ getInput: mockGetInput,
+ exportVariable: mockExportVariable,
+ info: mockInfo,
+ debug: mockDebug,
+ warning: mockWarning,
+ setSecret: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ addPath: jest.fn(),
+ getMultilineInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getState: jest.fn(),
+ saveState: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn(),
+ isDebug: jest.fn(),
+ setCommandEcho: jest.fn(),
+ getIDToken: jest.fn(),
+ ExitCode: {Success: 0, Failure: 1},
+ summary: {},
+ markdownSummary: {},
+ platform: {},
+ toPosixPath: jest.fn(),
+ toWin32Path: jest.fn(),
+ toPlatformPath: jest.fn()
+}));
+
+const {configureMavenArgs} = await import('../src/maven-args.js');
+const {
+ INPUT_SHOW_DOWNLOAD_PROGRESS,
+ MAVEN_ARGS_ENV,
+ MAVEN_NO_TRANSFER_PROGRESS_FLAG
+} = await import('../src/constants.js');
+
+describe('configureMavenArgs', () => {
+ let inputs: Record;
+ const originalMavenArgs = process.env[MAVEN_ARGS_ENV];
+
+ beforeEach(() => {
+ inputs = {};
+
+ mockGetInput.mockImplementation((name: string) => inputs[name] ?? '');
+ mockExportVariable.mockImplementation((name: string, value: string) => {
+ process.env[name] = value;
+ });
+ mockInfo.mockImplementation(() => undefined);
+ mockDebug.mockImplementation(() => undefined);
+
+ delete process.env[MAVEN_ARGS_ENV];
+ });
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ if (originalMavenArgs === undefined) {
+ delete process.env[MAVEN_ARGS_ENV];
+ } else {
+ process.env[MAVEN_ARGS_ENV] = originalMavenArgs;
+ }
+ });
+
+ it('sets MAVEN_ARGS with -ntp by default', () => {
+ configureMavenArgs();
+
+ expect(mockExportVariable).toHaveBeenCalledWith(
+ MAVEN_ARGS_ENV,
+ MAVEN_NO_TRANSFER_PROGRESS_FLAG
+ );
+ expect(process.env[MAVEN_ARGS_ENV]).toBe(MAVEN_NO_TRANSFER_PROGRESS_FLAG);
+ });
+
+ it('does not modify MAVEN_ARGS when show-download-progress is true', () => {
+ inputs[INPUT_SHOW_DOWNLOAD_PROGRESS] = 'true';
+
+ configureMavenArgs();
+
+ expect(mockExportVariable).not.toHaveBeenCalled();
+ expect(process.env[MAVEN_ARGS_ENV]).toBeUndefined();
+ });
+
+ it('preserves an existing MAVEN_ARGS value and appends -ntp', () => {
+ process.env[MAVEN_ARGS_ENV] = '-B -Dstyle.color=always';
+
+ configureMavenArgs();
+
+ expect(mockExportVariable).toHaveBeenCalledWith(
+ MAVEN_ARGS_ENV,
+ `-B -Dstyle.color=always ${MAVEN_NO_TRANSFER_PROGRESS_FLAG}`
+ );
+ });
+
+ it('does not duplicate the flag when -ntp is already present', () => {
+ process.env[MAVEN_ARGS_ENV] = '-B -ntp';
+
+ configureMavenArgs();
+
+ expect(mockExportVariable).not.toHaveBeenCalled();
+ expect(process.env[MAVEN_ARGS_ENV]).toBe('-B -ntp');
+ });
+
+ it('does not duplicate the flag when --no-transfer-progress is already present', () => {
+ process.env[MAVEN_ARGS_ENV] = '--no-transfer-progress -B';
+
+ configureMavenArgs();
+
+ expect(mockExportVariable).not.toHaveBeenCalled();
+ expect(process.env[MAVEN_ARGS_ENV]).toBe('--no-transfer-progress -B');
+ });
+
+ it('keeps the existing MAVEN_ARGS when show-download-progress is true', () => {
+ inputs[INPUT_SHOW_DOWNLOAD_PROGRESS] = 'true';
+ process.env[MAVEN_ARGS_ENV] = '-B';
+
+ configureMavenArgs();
+
+ expect(mockExportVariable).not.toHaveBeenCalled();
+ expect(process.env[MAVEN_ARGS_ENV]).toBe('-B');
+ });
+});
diff --git a/__tests__/maven-xml-loading.test.ts b/__tests__/maven-xml-loading.test.ts
new file mode 100644
index 000000000..8f42e5461
--- /dev/null
+++ b/__tests__/maven-xml-loading.test.ts
@@ -0,0 +1,56 @@
+import {describe, expect, it, jest} from '@jest/globals';
+
+const mockXmlBuilderFactory = jest.fn();
+const mockParse = jest.fn(() => ({
+ toolchains: {
+ toolchain: [
+ {
+ type: 'foo',
+ provides: {id: 'custom'},
+ configuration: {fooHome: '/opt/foo'}
+ }
+ ]
+ }
+}));
+
+jest.unstable_mockModule('fast-xml-parser', () => {
+ mockXmlBuilderFactory();
+ return {
+ XMLParser: jest.fn().mockImplementation(() => ({
+ parse: mockParse
+ }))
+ };
+});
+
+const toolchains = await import('../src/toolchains.js');
+
+describe('Maven XML loading', () => {
+ it('does not load fast-xml-parser for new toolchains.xml generation', async () => {
+ const xml = await toolchains.generateToolchainDefinition(
+ '',
+ '21',
+ 'temurin',
+ 'temurin_21',
+ '/opt/java/21'
+ );
+
+ expect(xml).toContain('temurin_21');
+ expect(mockXmlBuilderFactory).not.toHaveBeenCalled();
+ expect(mockParse).not.toHaveBeenCalled();
+ });
+
+ it('loads fast-xml-parser for existing toolchains.xml merge generation', async () => {
+ await expect(
+ toolchains.generateToolchainDefinition(
+ 'foo',
+ '21',
+ 'temurin',
+ 'temurin_21',
+ '/opt/java/21'
+ )
+ ).resolves.toContain('temurin_21');
+
+ expect(mockXmlBuilderFactory).toHaveBeenCalledTimes(1);
+ expect(mockParse).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/__tests__/problem-matcher.test.ts b/__tests__/problem-matcher.test.ts
new file mode 100644
index 000000000..6a6a7b63c
--- /dev/null
+++ b/__tests__/problem-matcher.test.ts
@@ -0,0 +1,44 @@
+import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
+
+const mockGetInput = jest.fn<(...args: any[]) => any>();
+const mockInfo = jest.fn<(...args: any[]) => any>();
+const mockDebug = jest.fn<(...args: any[]) => any>();
+
+jest.unstable_mockModule('@actions/core', () => ({
+ getInput: mockGetInput,
+ info: mockInfo,
+ debug: mockDebug,
+ warning: jest.fn(),
+ setSecret: jest.fn()
+}));
+
+const {configureProblemMatcher} = await import('../src/problem-matcher.js');
+const {INPUT_PROBLEM_MATCHER} = await import('../src/constants.js');
+
+describe('configureProblemMatcher', () => {
+ let inputs: Record;
+
+ beforeEach(() => {
+ inputs = {};
+ mockGetInput.mockImplementation((name: string) => inputs[name] ?? '');
+ });
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ });
+
+ it('registers the Java problem matcher by default', () => {
+ configureProblemMatcher('/matchers/java.json');
+
+ expect(mockInfo).toHaveBeenCalledWith('##[add-matcher]/matchers/java.json');
+ });
+
+ it('does not register the Java problem matcher when disabled', () => {
+ inputs[INPUT_PROBLEM_MATCHER] = 'false';
+
+ configureProblemMatcher('/matchers/java.json');
+
+ expect(mockInfo).not.toHaveBeenCalled();
+ expect(mockDebug).toHaveBeenCalledWith('Java problem matcher is disabled');
+ });
+});
diff --git a/__tests__/retrying-http-client.test.ts b/__tests__/retrying-http-client.test.ts
new file mode 100644
index 000000000..b9fb63db1
--- /dev/null
+++ b/__tests__/retrying-http-client.test.ts
@@ -0,0 +1,251 @@
+import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
+import type {IncomingMessage} from 'http';
+
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn()
+}));
+
+const core = await import('@actions/core');
+const httpm = await import('@actions/http-client');
+const {RetryingHttpClient, isRetryableNetworkError, parseRetryAfter} =
+ await import('../src/retrying-http-client.js');
+
+function response(
+ statusCode: number,
+ retryAfter?: string
+): httpm.HttpClientResponse {
+ return {
+ message: {
+ statusCode,
+ headers: retryAfter ? {'retry-after': retryAfter} : {}
+ } as IncomingMessage,
+ readBody: jest.fn(async () => '')
+ } as unknown as httpm.HttpClientResponse;
+}
+
+describe('RetryingHttpClient', () => {
+ let request: ReturnType;
+ let sleep: jest.Mock<(delayMs: number) => Promise>;
+
+ beforeEach(() => {
+ request = jest.spyOn(httpm.HttpClient.prototype, 'request');
+ sleep = jest.fn(async () => undefined);
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ jest.clearAllMocks();
+ });
+
+ it('uses exponential backoff with jitter for retryable responses', async () => {
+ request
+ .mockResolvedValueOnce(response(503))
+ .mockResolvedValueOnce(response(502))
+ .mockResolvedValueOnce(response(200));
+ const client = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0,
+ baseDelayMs: 1000,
+ maxDelayMs: 10000
+ });
+
+ await expect(client.get('https://example.com')).resolves.toBeDefined();
+
+ expect(request).toHaveBeenCalledTimes(3);
+ expect(sleep).toHaveBeenNthCalledWith(1, 500);
+ expect(sleep).toHaveBeenNthCalledWith(2, 1000);
+ expect(core.info).toHaveBeenNthCalledWith(
+ 1,
+ 'Request attempt 1 of 4 failed (HTTP 503); retrying in 500 ms'
+ );
+ expect(core.info).toHaveBeenNthCalledWith(
+ 2,
+ 'Request attempt 2 of 4 failed (HTTP 502); retrying in 1000 ms'
+ );
+ });
+
+ it('honors Retry-After delta-seconds over the client delay', async () => {
+ request
+ .mockResolvedValueOnce(response(429, '3'))
+ .mockResolvedValueOnce(response(200));
+ const client = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0
+ });
+
+ await client.get('https://example.com');
+
+ expect(sleep).toHaveBeenCalledWith(3000);
+ });
+
+ it('honors Retry-After HTTP dates over the client delay', async () => {
+ const now = Date.parse('2026-07-29T00:00:00Z');
+ request
+ .mockResolvedValueOnce(response(503, new Date(now + 5000).toUTCString()))
+ .mockResolvedValueOnce(response(200));
+ const client = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0,
+ now: () => now
+ });
+
+ await client.get('https://example.com');
+
+ expect(sleep).toHaveBeenCalledWith(5000);
+ });
+
+ it('caps Retry-After at the configured maximum delay', async () => {
+ request
+ .mockResolvedValueOnce(response(429, '60'))
+ .mockResolvedValueOnce(response(200));
+ const client = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0,
+ maxDelayMs: 10000
+ });
+
+ await client.get('https://example.com');
+
+ expect(sleep).toHaveBeenCalledWith(10000);
+ });
+
+ it.each([429, 502, 503, 504, 522])(
+ 'retries HTTP %s responses',
+ async statusCode => {
+ request
+ .mockResolvedValueOnce(response(statusCode))
+ .mockResolvedValueOnce(response(200));
+ const client = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0
+ });
+
+ await client.get('https://example.com');
+
+ expect(request).toHaveBeenCalledTimes(2);
+ }
+ );
+
+ it.each(['ETIMEDOUT', 'ECONNRESET', 'ENOTFOUND', 'ECONNREFUSED'])(
+ 'retries network errors with code %s',
+ async code => {
+ request
+ .mockRejectedValueOnce(Object.assign(new Error(code), {code}))
+ .mockResolvedValueOnce(response(200));
+ const client = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0
+ });
+
+ await client.get('https://example.com');
+
+ expect(request).toHaveBeenCalledTimes(2);
+ }
+ );
+
+ it('retries retryable aggregate network errors', async () => {
+ const aggregateError = Object.assign(new Error('connection failed'), {
+ errors: [Object.assign(new Error('timed out'), {code: 'ETIMEDOUT'})]
+ });
+ request
+ .mockRejectedValueOnce(aggregateError)
+ .mockResolvedValueOnce(response(200));
+ const client = new RetryingHttpClient('test', {
+ sleep,
+ random: () => 0
+ });
+
+ await client.get('https://example.com');
+
+ expect(request).toHaveBeenCalledTimes(2);
+ expect(sleep).toHaveBeenCalledWith(500);
+ });
+
+ it('does not retry non-retryable responses or network errors', async () => {
+ request.mockResolvedValueOnce(response(500));
+ const client = new RetryingHttpClient('test', {sleep});
+
+ await expect(client.get('https://example.com')).resolves.toBeDefined();
+ expect(request).toHaveBeenCalledTimes(1);
+ expect(sleep).not.toHaveBeenCalled();
+
+ request.mockRejectedValueOnce(
+ Object.assign(new Error('certificate failed'), {code: 'CERT_HAS_EXPIRED'})
+ );
+ await expect(client.get('https://example.com')).rejects.toThrow(
+ 'certificate failed'
+ );
+ expect(request).toHaveBeenCalledTimes(2);
+ expect(sleep).not.toHaveBeenCalled();
+ });
+
+ it('stops after the configured total attempt count', async () => {
+ request
+ .mockResolvedValueOnce(response(503))
+ .mockResolvedValueOnce(response(503));
+ const client = new RetryingHttpClient('test', {
+ maxAttempts: 2,
+ sleep,
+ random: () => 0
+ });
+
+ const finalResponse = await client.get('https://example.com');
+
+ expect(finalResponse.message.statusCode).toBe(503);
+ expect(request).toHaveBeenCalledTimes(2);
+ expect(sleep).toHaveBeenCalledTimes(1);
+ });
+
+ it('propagates the final network error after exhausting attempts', async () => {
+ const finalError = Object.assign(new Error('still unavailable'), {
+ code: 'ECONNREFUSED'
+ });
+ request
+ .mockRejectedValueOnce(
+ Object.assign(new Error('unavailable'), {code: 'ECONNREFUSED'})
+ )
+ .mockRejectedValueOnce(finalError);
+ const client = new RetryingHttpClient('test', {
+ maxAttempts: 2,
+ sleep,
+ random: () => 0
+ });
+
+ await expect(client.get('https://example.com')).rejects.toBe(finalError);
+
+ expect(request).toHaveBeenCalledTimes(2);
+ expect(sleep).toHaveBeenCalledTimes(1);
+ });
+
+ it('does not retry write requests', async () => {
+ request.mockResolvedValueOnce(response(503));
+ const client = new RetryingHttpClient('test', {sleep});
+
+ await client.post('https://example.com', '{}');
+
+ expect(request).toHaveBeenCalledTimes(1);
+ expect(sleep).not.toHaveBeenCalled();
+ });
+});
+
+describe('retry classification', () => {
+ it('parses valid Retry-After values and ignores invalid or past values', () => {
+ const now = Date.parse('2026-07-29T00:00:00Z');
+
+ expect(parseRetryAfter('7', now)).toBe(7000);
+ expect(parseRetryAfter(new Date(now + 3000).toUTCString(), now)).toBe(3000);
+ expect(parseRetryAfter(new Date(now - 3000).toUTCString(), now)).toBe(
+ undefined
+ );
+ expect(parseRetryAfter('not-a-date', now)).toBe(undefined);
+ });
+
+ it('recognizes direct and nested retryable network error codes', () => {
+ expect(isRetryableNetworkError({code: 'ECONNRESET'})).toBe(true);
+ expect(
+ isRetryableNetworkError({errors: [{code: 'ENOTFOUND'}, {code: 'OTHER'}]})
+ ).toBe(true);
+ expect(isRetryableNetworkError({code: 'CERT_HAS_EXPIRED'})).toBe(false);
+ expect(isRetryableNetworkError(new Error('unknown'))).toBe(false);
+ });
+});
diff --git a/__tests__/setup-java.module-loading.test.ts b/__tests__/setup-java.module-loading.test.ts
new file mode 100644
index 000000000..7705abfc4
--- /dev/null
+++ b/__tests__/setup-java.module-loading.test.ts
@@ -0,0 +1,120 @@
+import {jest, describe, it, expect, beforeEach} from '@jest/globals';
+
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((value: string) => value),
+ toWin32Path: jest.fn((value: string) => value),
+ toPosixPath: jest.fn((value: string) => value)
+}));
+
+jest.unstable_mockModule('fs', () => ({
+ default: {
+ readFileSync: jest.fn()
+ }
+}));
+
+jest.unstable_mockModule('../src/util.js', () => ({
+ getBooleanInput: jest.fn(),
+ getVersionFromFileContent: jest.fn(),
+ isJdkCacheEnabled: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/toolchains.js', () => ({
+ validateToolchainIds: jest.fn(),
+ configureToolchains: jest.fn()
+}));
+
+jest.unstable_mockModule(
+ '../src/distributions/distribution-factory.js',
+ () => ({
+ getJavaDistribution: jest.fn()
+ })
+);
+
+jest.unstable_mockModule('../src/auth.js', () => ({
+ configureAuthentication: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/maven-args.js', () => ({
+ configureMavenArgs: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/problem-matcher.js', () => ({
+ configureProblemMatcher: jest.fn()
+}));
+
+// These modules should never be imported when `cache` input is empty.
+jest.unstable_mockModule('../src/cache-feature.js', () => {
+ throw new Error('cache-feature module should not be loaded');
+});
+jest.unstable_mockModule('../src/cache.js', () => {
+ throw new Error('cache module should not be loaded');
+});
+
+const core = await import('@actions/core');
+const util = await import('../src/util.js');
+const toolchains = await import('../src/toolchains.js');
+const factory = await import('../src/distributions/distribution-factory.js');
+const {run} = await import('../src/setup-java.js');
+
+describe('setup-java conditional module loading', () => {
+ const inputs = new Map();
+ const multilineInputs = new Map();
+ const booleanInputs = new Map();
+
+ beforeEach(() => {
+ jest.resetAllMocks();
+ inputs.clear();
+ multilineInputs.clear();
+ booleanInputs.clear();
+
+ (core.getInput as jest.Mock).mockImplementation((name: unknown) => {
+ return inputs.get(name as string) ?? '';
+ });
+ (core.getMultilineInput as jest.Mock).mockImplementation(
+ (name: unknown) => {
+ return multilineInputs.get(name as string) ?? [];
+ }
+ );
+ (util.getBooleanInput as jest.Mock).mockImplementation(
+ (name: unknown, defaultValue: unknown) => {
+ return booleanInputs.get(name as string) ?? defaultValue;
+ }
+ );
+ (util.isJdkCacheEnabled as jest.Mock).mockReturnValue(false);
+ (toolchains.configureToolchains as jest.Mock).mockResolvedValue(undefined);
+ });
+
+ it('does not import cache modules when cache input is not provided', async () => {
+ inputs.set('distribution', 'temurin');
+ multilineInputs.set('java-version', ['21']);
+ (factory.getJavaDistribution as jest.Mock).mockResolvedValue({
+ setupJava: jest.fn(async () => ({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ }))
+ });
+
+ await run();
+
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+});
diff --git a/__tests__/setup-java.test.ts b/__tests__/setup-java.test.ts
new file mode 100644
index 000000000..6453c6c1e
--- /dev/null
+++ b/__tests__/setup-java.test.ts
@@ -0,0 +1,689 @@
+import {jest, describe, it, expect, beforeEach} from '@jest/globals';
+
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((value: string) => value),
+ toWin32Path: jest.fn((value: string) => value),
+ toPosixPath: jest.fn((value: string) => value)
+}));
+
+jest.unstable_mockModule('fs', () => ({
+ default: {
+ readFileSync: jest.fn()
+ }
+}));
+
+jest.unstable_mockModule('../src/util.js', () => ({
+ getBooleanInput: jest.fn(),
+ getVersionFromFileContent: jest.fn(),
+ isJdkCacheEnabled: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/toolchains.js', () => ({
+ validateToolchainIds: jest.fn(),
+ configureToolchains: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/toolchain-ids.js', () => ({
+ validateToolchainIds: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/cache.js', () => ({
+ restore: jest.fn(),
+ validatePackageManager: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/cache-feature.js', () => ({
+ isCacheFeatureAvailable: jest.fn()
+}));
+
+jest.unstable_mockModule(
+ '../src/distributions/distribution-factory.js',
+ () => ({
+ getJavaDistribution: jest.fn()
+ })
+);
+
+jest.unstable_mockModule('../src/auth.js', () => ({
+ configureAuthentication: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/maven-args.js', () => ({
+ configureMavenArgs: jest.fn()
+}));
+
+jest.unstable_mockModule('../src/problem-matcher.js', () => ({
+ configureProblemMatcher: jest.fn()
+}));
+
+const core = await import('@actions/core');
+const fs = (await import('fs')).default;
+const util = await import('../src/util.js');
+const toolchains = await import('../src/toolchains.js');
+const toolchainIds = await import('../src/toolchain-ids.js');
+const cache = await import('../src/cache.js');
+const cacheFeature = await import('../src/cache-feature.js');
+const factory = await import('../src/distributions/distribution-factory.js');
+const auth = await import('../src/auth.js');
+const mavenArgs = await import('../src/maven-args.js');
+const problemMatcher = await import('../src/problem-matcher.js');
+const {run} = await import('../src/setup-java.js');
+
+const inputCallsOnImport = (core.getInput as jest.Mock).mock.calls.length;
+const multilineInputCallsOnImport = (core.getMultilineInput as jest.Mock).mock
+ .calls.length;
+
+describe('setup action orchestration', () => {
+ const inputs = new Map();
+ const multilineInputs = new Map();
+ const booleanInputs = new Map();
+
+ beforeEach(() => {
+ jest.resetAllMocks();
+ inputs.clear();
+ multilineInputs.clear();
+ booleanInputs.clear();
+
+ (core.getInput as jest.Mock).mockImplementation((name: unknown) => {
+ return inputs.get(name as string) ?? '';
+ });
+ (core.getMultilineInput as jest.Mock).mockImplementation(
+ (name: unknown) => {
+ return multilineInputs.get(name as string) ?? [];
+ }
+ );
+ (util.getBooleanInput as jest.Mock).mockImplementation(
+ (name: unknown, defaultValue: unknown) => {
+ return booleanInputs.get(name as string) ?? defaultValue;
+ }
+ );
+ (util.isJdkCacheEnabled as jest.Mock).mockImplementation(
+ (cache: string) => {
+ const explicit = inputs.get('cache-jdk');
+ return explicit
+ ? (booleanInputs.get('cache-jdk') ?? explicit === 'true')
+ : Boolean(cache);
+ }
+ );
+ (cacheFeature.isCacheFeatureAvailable as jest.Mock).mockReturnValue(true);
+ (toolchainIds.validateToolchainIds as jest.Mock).mockImplementation(
+ () => undefined
+ );
+ (toolchains.configureToolchains as jest.Mock).mockResolvedValue(undefined);
+ (auth.configureAuthentication as jest.Mock).mockResolvedValue(undefined);
+ (cache.restore as jest.Mock).mockResolvedValue(undefined);
+ (cache.validatePackageManager as jest.Mock).mockImplementation(
+ () => undefined
+ );
+ });
+
+ it('does not execute the action when imported', () => {
+ expect(inputCallsOnImport).toBe(0);
+ expect(multilineInputCallsOnImport).toBe(0);
+ });
+
+ it('requires java-version or java-version-file', async () => {
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith(
+ 'java-version or java-version-file input expected'
+ );
+ expect(factory.getJavaDistribution).not.toHaveBeenCalled();
+ expect(problemMatcher.configureProblemMatcher).not.toHaveBeenCalled();
+ });
+
+ it('requires distribution when java-version is provided', async () => {
+ multilineInputs.set('java-version', ['21']);
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith(
+ 'distribution input is required'
+ );
+ expect(factory.getJavaDistribution).not.toHaveBeenCalled();
+ });
+
+ it('requires distribution when it cannot be inferred from the version file', async () => {
+ inputs.set('java-version-file', '.java-version');
+ (fs.readFileSync as jest.Mock).mockReturnValue(Buffer.from('21'));
+ (util.getVersionFromFileContent as jest.Mock).mockReturnValue({
+ version: '21'
+ });
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith(
+ 'distribution input is required when not specified in the version file'
+ );
+ expect(factory.getJavaDistribution).not.toHaveBeenCalled();
+ });
+
+ it('fails when the version file has no supported version', async () => {
+ inputs.set('java-version-file', '.java-version');
+ inputs.set('distribution', 'temurin');
+ (fs.readFileSync as jest.Mock).mockReturnValue(Buffer.from('invalid'));
+ (util.getVersionFromFileContent as jest.Mock).mockReturnValue(undefined);
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith(
+ 'No supported version was found in file .java-version'
+ );
+ expect(factory.getJavaDistribution).not.toHaveBeenCalled();
+ });
+
+ it('uses the distribution inferred from a version file', async () => {
+ inputs.set('java-version-file', '.sdkmanrc');
+ inputs.set('architecture', 'x64');
+ inputs.set('java-package', 'jdk');
+ inputs.set('distribution', 'zulu');
+ inputs.set('jdk-file', '/tmp/java.tar.gz');
+ multilineInputs.set('mvn-toolchain-id', ['file-jdk']);
+ booleanInputs.set('check-latest', true);
+ booleanInputs.set('force-download', true);
+ booleanInputs.set('set-default', false);
+ booleanInputs.set('verify-signature', true);
+ inputs.set('verify-signature-public-key', 'public-key');
+ (fs.readFileSync as jest.Mock).mockReturnValue(
+ Buffer.from('java=21.0.5-tem')
+ );
+ (util.getVersionFromFileContent as jest.Mock).mockReturnValue({
+ version: '21.0.5',
+ distribution: 'temurin'
+ });
+ const setupJava = jest.fn(async () => ({
+ version: '21.0.5+11',
+ path: '/opt/java/21'
+ }));
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
+
+ await run();
+
+ expect(util.getVersionFromFileContent).toHaveBeenCalledWith(
+ 'java=21.0.5-tem',
+ 'zulu',
+ '.sdkmanrc'
+ );
+ expect(factory.getJavaDistribution).toHaveBeenCalledWith(
+ 'temurin',
+ {
+ version: '21.0.5',
+ architecture: 'x64',
+ packageType: 'jdk',
+ checkLatest: true,
+ forceDownload: true,
+ cacheJdk: false,
+ setDefault: false,
+ verifySignature: true,
+ verifySignaturePublicKey: 'public-key'
+ },
+ '/tmp/java.tar.gz'
+ );
+ expect(toolchainIds.validateToolchainIds).toHaveBeenCalledWith(
+ [],
+ '.sdkmanrc',
+ ['file-jdk']
+ );
+ expect(toolchains.configureToolchains).toHaveBeenCalledWith(
+ '21.0.5',
+ 'temurin',
+ '/opt/java/21',
+ 'file-jdk'
+ );
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('installs multiple JDKs in order with matching toolchain IDs', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('architecture', 'x64');
+ inputs.set('java-package', 'jdk');
+ multilineInputs.set('java-version', ['17', '21']);
+ multilineInputs.set('mvn-toolchain-id', ['java-17', 'java-21']);
+
+ const setupJava17 = jest.fn(async () => ({
+ version: '17.0.12+7',
+ path: '/opt/java/17'
+ }));
+ const setupJava21 = jest.fn(async () => ({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ }));
+ (factory.getJavaDistribution as jest.Mock)
+ .mockReturnValueOnce({setupJava: setupJava17})
+ .mockReturnValueOnce({setupJava: setupJava21});
+
+ await run();
+
+ expect(factory.getJavaDistribution).toHaveBeenNthCalledWith(
+ 1,
+ 'temurin',
+ expect.objectContaining({version: '17'}),
+ ''
+ );
+ expect(factory.getJavaDistribution).toHaveBeenNthCalledWith(
+ 2,
+ 'temurin',
+ expect.objectContaining({version: '21'}),
+ ''
+ );
+ expect(toolchains.configureToolchains).toHaveBeenNthCalledWith(
+ 1,
+ '17',
+ 'temurin',
+ '/opt/java/17',
+ 'java-17'
+ );
+ expect(toolchains.configureToolchains).toHaveBeenNthCalledWith(
+ 2,
+ '21',
+ 'temurin',
+ '/opt/java/21',
+ 'java-21'
+ );
+ expect(setupJava17.mock.invocationCallOrder[0]).toBeLessThan(
+ setupJava21.mock.invocationCallOrder[0]
+ );
+ });
+
+ it('uses the resolved version for the latest Maven toolchain', async () => {
+ inputs.set('distribution', 'temurin');
+ multilineInputs.set('java-version', ['latest']);
+ const setupJava = jest.fn(async () => ({
+ version: '24.0.2+12',
+ path: '/opt/java/24'
+ }));
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
+
+ await run();
+
+ expect(toolchains.configureToolchains).toHaveBeenCalledWith(
+ '24.0.2+12',
+ 'temurin',
+ '/opt/java/24',
+ undefined
+ );
+ });
+
+ it('starts cache restoration before post-install steps and awaits it before finishing', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', 'maven');
+ inputs.set('cache-dependency-path', '**/pom.xml');
+ multilineInputs.set('java-version', ['21']);
+ multilineInputs.set('cache-path', [
+ '/custom/maven/repository',
+ '!/custom/maven/repository/excluded'
+ ]);
+ const cacheRestore = deferred();
+ let resolveSetupJava: (() => void) | undefined;
+ const setupJava = jest.fn(
+ () =>
+ new Promise<{version: string; path: string}>(resolve => {
+ resolveSetupJava = () =>
+ resolve({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ });
+ })
+ );
+ (cache.restore as jest.Mock).mockReturnValue(cacheRestore.promise);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
+
+ const runPromise = run();
+ try {
+ await tick();
+
+ expect(cacheFeature.isCacheFeatureAvailable).toHaveBeenCalled();
+ expect(cache.restore).toHaveBeenCalledWith('maven', '**/pom.xml', [
+ '/custom/maven/repository',
+ '!/custom/maven/repository/excluded'
+ ]);
+ expect(toolchains.configureToolchains).not.toHaveBeenCalled();
+
+ resolveSetupJava?.();
+ await tick();
+ expect(problemMatcher.configureProblemMatcher).toHaveBeenCalledWith(
+ expect.stringMatching(/\.github[/\\]java\.json$/)
+ );
+
+ expect(
+ (problemMatcher.configureProblemMatcher as jest.Mock).mock
+ .invocationCallOrder[0]
+ ).toBeLessThan(
+ (auth.configureAuthentication as jest.Mock).mock.invocationCallOrder[0]
+ );
+ expect(
+ (problemMatcher.configureProblemMatcher as jest.Mock).mock
+ .invocationCallOrder[0]
+ ).toBeLessThan(
+ (toolchains.configureToolchains as jest.Mock).mock
+ .invocationCallOrder[0]
+ );
+ expect(
+ (auth.configureAuthentication as jest.Mock).mock.invocationCallOrder[0]
+ ).toBeLessThan(
+ (mavenArgs.configureMavenArgs as jest.Mock).mock.invocationCallOrder[0]
+ );
+ expect(
+ (toolchains.configureToolchains as jest.Mock).mock
+ .invocationCallOrder[0]
+ ).toBeLessThan(
+ (mavenArgs.configureMavenArgs as jest.Mock).mock.invocationCallOrder[0]
+ );
+
+ let completed = false;
+ runPromise.then(() => {
+ completed = true;
+ });
+ await tick();
+ expect(completed).toBe(false);
+ } finally {
+ resolveSetupJava?.();
+ cacheRestore.resolve();
+ await runPromise;
+ }
+
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('overlaps independent Maven settings and toolchains configuration', async () => {
+ inputs.set('distribution', 'temurin');
+ multilineInputs.set('java-version', ['21']);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({
+ setupJava: jest.fn(async () => ({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ }))
+ });
+ const authentication = deferred();
+ const toolchainConfiguration = deferred();
+ (auth.configureAuthentication as jest.Mock).mockReturnValue(
+ authentication.promise
+ );
+ (toolchains.configureToolchains as jest.Mock).mockReturnValue(
+ toolchainConfiguration.promise
+ );
+
+ const runPromise = run();
+ try {
+ await tick();
+ await tick();
+
+ expect(auth.configureAuthentication).toHaveBeenCalled();
+ expect(toolchains.configureToolchains).toHaveBeenCalledWith(
+ '21',
+ 'temurin',
+ '/opt/java/21',
+ undefined
+ );
+ expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
+
+ authentication.resolve();
+ await tick();
+ expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
+
+ toolchainConfiguration.resolve();
+ await runPromise;
+ } finally {
+ authentication.resolve();
+ toolchainConfiguration.resolve();
+ await runPromise;
+ }
+
+ expect(mavenArgs.configureMavenArgs).toHaveBeenCalled();
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('skips cache restoration when the cache feature is unavailable', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', 'maven');
+ multilineInputs.set('java-version', ['21']);
+ (cacheFeature.isCacheFeatureAvailable as jest.Mock).mockReturnValue(false);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({
+ setupJava: jest.fn(async () => ({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ }))
+ });
+
+ await run();
+
+ expect(cache.restore).not.toHaveBeenCalled();
+ });
+
+ it('does not initialize cache modules when cache input is absent', async () => {
+ inputs.set('distribution', 'temurin');
+ multilineInputs.set('java-version', ['21']);
+ booleanInputs.set('cache-jdk', false);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({
+ setupJava: jest.fn(async () => ({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ }))
+ });
+
+ await run();
+
+ expect(cacheFeature.isCacheFeatureAvailable).not.toHaveBeenCalled();
+ expect(cache.restore).not.toHaveBeenCalled();
+ expect(factory.getJavaDistribution).toHaveBeenCalledWith(
+ 'temurin',
+ expect.objectContaining({cacheJdk: false}),
+ ''
+ );
+ });
+
+ it('fails invalid cache input before resolving a Java distribution', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', 'ant');
+ multilineInputs.set('java-version', ['21']);
+ const setupJava = jest.fn();
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
+ (cache.validatePackageManager as jest.Mock).mockImplementation(() => {
+ throw new Error('unknown package manager specified: ant');
+ });
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith(
+ 'unknown package manager specified: ant'
+ );
+ expect(factory.getJavaDistribution).not.toHaveBeenCalled();
+ expect(setupJava).not.toHaveBeenCalled();
+ expect(cache.restore).not.toHaveBeenCalled();
+ });
+
+ it('reports missing java-version before validating the cache input', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', 'ant');
+ (cache.validatePackageManager as jest.Mock).mockImplementation(() => {
+ throw new Error('unknown package manager specified: ant');
+ });
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith(
+ 'java-version or java-version-file input expected'
+ );
+ expect(cache.validatePackageManager).not.toHaveBeenCalled();
+ });
+
+ it.each([
+ ['', '', false],
+ ['', 'true', true],
+ ['', 'false', false],
+ ['maven', '', true],
+ ['maven', 'true', true],
+ ['maven', 'false', false]
+ ])(
+ 'passes effective JDK caching for cache=%j and cache-jdk=%j',
+ async (cacheInput, cacheJdkInput, expected) => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', cacheInput);
+ inputs.set('cache-jdk', cacheJdkInput);
+ multilineInputs.set('java-version', ['21']);
+ if (cacheJdkInput) {
+ booleanInputs.set('cache-jdk', cacheJdkInput === 'true');
+ }
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({
+ setupJava: jest.fn(async () => ({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ }))
+ });
+
+ await run();
+
+ expect(factory.getJavaDistribution).toHaveBeenCalledWith(
+ 'temurin',
+ expect.objectContaining({cacheJdk: expected}),
+ ''
+ );
+ }
+ );
+
+ it('reports unsupported distributions through core.setFailed', async () => {
+ inputs.set('distribution', 'unsupported');
+ multilineInputs.set('java-version', ['21']);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue(null);
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith(
+ 'No supported distribution was found for input unsupported'
+ );
+ expect(toolchains.configureToolchains).not.toHaveBeenCalled();
+ expect(problemMatcher.configureProblemMatcher).not.toHaveBeenCalled();
+ });
+
+ it('reports collaborator failures and stops post-install configuration', async () => {
+ inputs.set('distribution', 'temurin');
+ multilineInputs.set('java-version', ['21']);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({
+ setupJava: jest.fn(async () => {
+ throw new Error('download failed');
+ })
+ });
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith('download failed');
+ expect(toolchains.configureToolchains).not.toHaveBeenCalled();
+ expect(problemMatcher.configureProblemMatcher).not.toHaveBeenCalled();
+ expect(auth.configureAuthentication).not.toHaveBeenCalled();
+ expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
+ expect(cache.restore).not.toHaveBeenCalled();
+ });
+
+ it('reports post-install failures and skips later collaborators', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', 'maven');
+ multilineInputs.set('java-version', ['21']);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({
+ setupJava: jest.fn(async () => ({
+ version: '21.0.4+7',
+ path: '/opt/java/21'
+ }))
+ });
+ (auth.configureAuthentication as jest.Mock).mockRejectedValue(
+ new Error('authentication failed')
+ );
+
+ await run();
+
+ expect(problemMatcher.configureProblemMatcher).toHaveBeenCalled();
+ expect(core.setFailed).toHaveBeenCalledWith('authentication failed');
+ expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
+ expect(cache.restore).toHaveBeenCalled();
+ });
+
+ it('keeps Java setup errors deterministic when cache restore also fails', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', 'maven');
+ multilineInputs.set('java-version', ['21']);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({
+ setupJava: jest.fn(async () => {
+ throw new Error('download failed');
+ })
+ });
+ (cache.restore as jest.Mock).mockRejectedValue(
+ new Error('cache restore failed')
+ );
+
+ await run();
+
+ expect(core.setFailed).toHaveBeenCalledWith('download failed');
+ });
+
+ it('observes cache failures while Java setup is still pending', async () => {
+ inputs.set('distribution', 'temurin');
+ inputs.set('cache', 'maven');
+ multilineInputs.set('java-version', ['21']);
+ const javaSetup = deferred<{version: string; path: string}>();
+ const setupJava = jest.fn(() => javaSetup.promise);
+ (factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
+ const cacheRestore = deferred();
+ const cacheRestoreCalled = deferred();
+ (cache.restore as jest.Mock).mockImplementation(() => {
+ cacheRestoreCalled.resolve();
+ return cacheRestore.promise;
+ });
+ const unhandledRejections: unknown[] = [];
+ const onUnhandledRejection = (reason: unknown) => {
+ unhandledRejections.push(reason);
+ };
+ process.on('unhandledRejection', onUnhandledRejection);
+
+ const runPromise = run();
+ try {
+ // Only reject once the restore has actually started and while the Java
+ // installation is still pending, so the unfixed code would leave the
+ // rejection unhandled.
+ await cacheRestoreCalled.promise;
+ cacheRestore.reject(new Error('cache restore failed'));
+ await tick();
+
+ expect(setupJava).toHaveBeenCalled();
+ expect(unhandledRejections).toEqual([]);
+ expect(core.setFailed).not.toHaveBeenCalled();
+ } finally {
+ javaSetup.resolve({version: '21.0.4+7', path: '/opt/java/21'});
+ await runPromise;
+ process.off('unhandledRejection', onUnhandledRejection);
+ }
+
+ expect(unhandledRejections).toEqual([]);
+ expect(core.setFailed).toHaveBeenCalledWith('cache restore failed');
+ });
+});
+
+function deferred() {
+ let resolve!: (value: T | PromiseLike) => void;
+ let reject!: (reason?: unknown) => void;
+ const promise = new Promise((res, rej) => {
+ resolve = res;
+ reject = rej;
+ });
+ return {promise, resolve, reject};
+}
+
+async function tick() {
+ await new Promise(resolve => setTimeout(resolve, 0));
+}
diff --git a/__tests__/toolchains.test.ts b/__tests__/toolchains.test.ts
index 483077dc1..ea5248629 100644
--- a/__tests__/toolchains.test.ts
+++ b/__tests__/toolchains.test.ts
@@ -1,23 +1,64 @@
+import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterEach,
+ beforeAll,
+ afterAll
+} from '@jest/globals';
+import {fileURLToPath} from 'url';
import * as fs from 'fs';
import os from 'os';
import * as path from 'path';
-import * as core from '@actions/core';
import * as io from '@actions/io';
-import * as toolchains from '../src/toolchains';
-import {M2_DIR, MVN_TOOLCHAINS_FILE} from '../src/constants';
+import {XMLParser} from 'fast-xml-parser';
+// Mock @actions/core before importing source modules that depend on it
+jest.unstable_mockModule('@actions/core', () => ({
+ info: jest.fn(),
+ warning: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn(),
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+// Dynamic imports after mocking
+const core = await import('@actions/core');
+const toolchains = await import('../src/toolchains.js');
+const {M2_DIR, MVN_TOOLCHAINS_FILE} = await import('../src/constants.js');
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
const m2Dir = path.join(__dirname, M2_DIR);
const toolchainsFile = path.join(m2Dir, MVN_TOOLCHAINS_FILE);
describe('toolchains tests', () => {
- let spyOSHomedir: jest.SpyInstance;
- let spyInfo: jest.SpyInstance;
+ let spyOSHomedir: any;
+ let spyInfo: any;
beforeEach(async () => {
await io.rmRF(m2Dir);
spyOSHomedir = jest.spyOn(os, 'homedir');
spyOSHomedir.mockReturnValue(__dirname);
- spyInfo = jest.spyOn(core, 'info');
+ spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null);
}, 300000);
@@ -46,8 +87,7 @@ describe('toolchains tests', () => {
await toolchains.createToolchainsSettings({
jdkInfo,
- settingsDirectory: altHome,
- overwriteSettings: true
+ settingsDirectory: altHome
});
expect(fs.existsSync(m2Dir)).toBe(false);
@@ -56,7 +96,7 @@ describe('toolchains tests', () => {
expect(fs.existsSync(altHome)).toBe(true);
expect(fs.existsSync(altToolchainsFile)).toBe(true);
expect(fs.readFileSync(altToolchainsFile, 'utf-8')).toEqual(
- toolchains.generateToolchainDefinition(
+ await toolchains.generateToolchainDefinition(
'',
jdkInfo.version,
jdkInfo.vendor,
@@ -95,14 +135,13 @@ describe('toolchains tests', () => {
await toolchains.createToolchainsSettings({
jdkInfo,
- settingsDirectory: m2Dir,
- overwriteSettings: true
+ settingsDirectory: m2Dir
});
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(toolchainsFile)).toBe(true);
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
- toolchains.generateToolchainDefinition(
+ await toolchains.generateToolchainDefinition(
'',
jdkInfo.version,
jdkInfo.vendor,
@@ -111,7 +150,7 @@ describe('toolchains tests', () => {
)
);
expect(
- toolchains.generateToolchainDefinition(
+ await toolchains.generateToolchainDefinition(
'',
jdkInfo.version,
jdkInfo.vendor,
@@ -143,7 +182,20 @@ describe('toolchains tests', () => {
`;
const result = `
-
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
jdk
@@ -155,6 +207,67 @@ describe('toolchains tests', () => {
/opt/jdk/sun/1.6
+`;
+
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
+ }, 100000);
+
+ it('does not discard custom elements in existing toolchain definitions', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = `
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+ foo
+
+
+ /opt/jdk/sun/1.6
+ /usr/local/bin/bash
+
+
+ `;
+ const result = `
+
jdk
@@ -166,6 +279,19 @@ describe('toolchains tests', () => {
/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+ foo
+
+
+ /opt/jdk/sun/1.6
+ /usr/local/bin/bash
+
+
`;
fs.mkdirSync(m2Dir, {recursive: true});
@@ -175,14 +301,13 @@ describe('toolchains tests', () => {
await toolchains.createToolchainsSettings({
jdkInfo,
- settingsDirectory: m2Dir,
- overwriteSettings: true
+ settingsDirectory: m2Dir
});
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(toolchainsFile)).toBe(true);
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
- toolchains.generateToolchainDefinition(
+ await toolchains.generateToolchainDefinition(
originalFile,
jdkInfo.version,
jdkInfo.vendor,
@@ -191,7 +316,7 @@ describe('toolchains tests', () => {
)
);
expect(
- toolchains.generateToolchainDefinition(
+ await toolchains.generateToolchainDefinition(
originalFile,
jdkInfo.version,
jdkInfo.vendor,
@@ -201,7 +326,7 @@ describe('toolchains tests', () => {
).toEqual(result);
}, 100000);
- it('does not overwrite existing toolchains.xml files', async () => {
+ it('does not discard existing, custom toolchain definitions', async () => {
const jdkInfo = {
version: '17',
vendor: 'Eclipse Temurin',
@@ -211,17 +336,40 @@ describe('toolchains tests', () => {
const originalFile = `
- jdk
-
- 1.6
- Sun
- sun_1.6
-
-
- /opt/jdk/sun/1.6
-
+ foo
+
+ baz
+
+
+ /usr/local/bin/foo
+
`;
+ const result = `
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+
+ foo
+
+ baz
+
+
+ /usr/local/bin/foo
+
+
+`;
fs.mkdirSync(m2Dir, {recursive: true});
fs.writeFileSync(toolchainsFile, originalFile);
@@ -230,75 +378,809 @@ describe('toolchains tests', () => {
await toolchains.createToolchainsSettings({
jdkInfo,
- settingsDirectory: m2Dir,
- overwriteSettings: false
+ settingsDirectory: m2Dir
});
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(toolchainsFile)).toBe(true);
- expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(originalFile);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
}, 100000);
- it('generates valid toolchains.xml with minimal configuration', () => {
+ it('does not duplicate existing toolchain definitions', async () => {
const jdkInfo = {
- version: 'JAVA_VERSION',
- vendor: 'JAVA_VENDOR',
- id: 'VENDOR_VERSION',
- jdkHome: 'JAVA_HOME'
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
};
- const expectedToolchains = `
+ const originalFile = `
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+ `;
+ const result = `
jdk
- ${jdkInfo.version}
- ${jdkInfo.vendor}
- ${jdkInfo.id}
+ 17
+ Eclipse Temurin
+ temurin_17
- ${jdkInfo.jdkHome}
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
`;
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
expect(
- toolchains.generateToolchainDefinition(
- '',
+ await toolchains.generateToolchainDefinition(
+ originalFile,
jdkInfo.version,
jdkInfo.vendor,
jdkInfo.id,
jdkInfo.jdkHome
)
- ).toEqual(expectedToolchains);
+ ).toEqual(result);
}, 100000);
- it('creates toolchains.xml with correct id when none is supplied', async () => {
- const version = '17';
- const distributionName = 'temurin';
- const id = 'temurin_17';
- const jdkHome =
- '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64';
+ it('does not duplicate existing toolchain definitions if multiple exist', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
- await toolchains.configureToolchains(
- version,
- distributionName,
- jdkHome,
- undefined
- );
+ const originalFile = `
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+ `;
+ const result = `
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+`;
+
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(toolchainsFile)).toBe(true);
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
- toolchains.generateToolchainDefinition(
- '',
- version,
- distributionName,
- id,
- jdkHome
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
)
);
+ expect(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
}, 100000);
-});
+
+ it('handles an empty list of existing toolchains correctly', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = `
+ `;
+ const result = `
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+`;
+
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
+ }, 100000);
+
+ it('handles an empty existing toolchains.xml correctly', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = ``;
+ const result = `
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+`;
+
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
+ }, 100000);
+
+ it('preserves custom root attributes on existing toolchains.xml', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = `
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+ `;
+ const result = `
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+`;
+
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
+ }, 100000);
+
+ it('keeps partially-formed jdk toolchains without an id instead of crashing', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = `
+
+ jdk
+
+ 1.6
+ Sun
+
+
+ /opt/jdk/sun/1.6
+
+
+ `;
+ const result = `
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+
+ jdk
+
+ 1.6
+ Sun
+
+
+ /opt/jdk/sun/1.6
+
+
+`;
+
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ await toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
+ }, 100000);
+
+ it('extends existing toolchains.xml files instead of overwriting them', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = `
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+ `;
+
+ fs.mkdirSync(m2Dir, {recursive: true});
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ const updated = fs.readFileSync(toolchainsFile, 'utf-8');
+ // The pre-existing (Sun 1.6) toolchain must be preserved ...
+ expect(updated).toContain('sun_1.6');
+ expect(updated).toContain('/opt/jdk/sun/1.6');
+ // ... and the newly installed JDK must be appended.
+ expect(updated).toContain('temurin_17');
+ expect(updated).toContain('Eclipse Temurin');
+ expect(updated).toContain(`${jdkInfo.jdkHome}`);
+ }, 100000);
+
+ it('generates valid toolchains.xml with minimal configuration', async () => {
+ const jdkInfo = {
+ version: 'JAVA_VERSION',
+ vendor: 'JAVA_VENDOR',
+ id: 'VENDOR_VERSION',
+ jdkHome: 'JAVA_HOME'
+ };
+
+ const expectedToolchains = `
+
+
+ jdk
+
+ ${jdkInfo.version}
+ ${jdkInfo.vendor}
+ ${jdkInfo.id}
+
+
+ ${jdkInfo.jdkHome}
+
+
+`;
+
+ expect(
+ await toolchains.generateToolchainDefinition(
+ '',
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(expectedToolchains);
+ }, 100000);
+
+ it('escapes new toolchains.xml values while preserving parsed semantics', () => {
+ const jdkInfo = {
+ version: `21&<>"'é`,
+ vendor: `Temurin&<>"'é`,
+ id: `temurin&<>"'é`,
+ jdkHome: `/opt/java&<>"'é`
+ };
+
+ const xml = toolchains.generateNewToolchainDefinition(
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ );
+ const parsed = parseXmlObject(xml) as any;
+
+ expect(parsed.toolchains.toolchain[0].type).toBe('jdk');
+ expect(xmlElementText(xml, 'version')).toBe(jdkInfo.version);
+ expect(xmlElementText(xml, 'vendor')).toBe(jdkInfo.vendor);
+ expect(xmlElementText(xml, 'id')).toBe(jdkInfo.id);
+ expect(xmlElementText(xml, 'jdkHome')).toBe(jdkInfo.jdkHome);
+ });
+
+ it('creates toolchains.xml with correct id when none is supplied', async () => {
+ const version = '17';
+ const distributionName = 'temurin';
+ const id = 'temurin_17';
+ const jdkHome =
+ '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64';
+
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
+ if (name === 'settings-path') return m2Dir;
+ return '';
+ });
+
+ await toolchains.configureToolchains(
+ version,
+ distributionName,
+ jdkHome,
+ undefined
+ );
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ await toolchains.generateToolchainDefinition(
+ '',
+ version,
+ distributionName,
+ id,
+ jdkHome
+ )
+ );
+ }, 100000);
+
+ it('merges a second JDK into a toolchains.xml produced by the new-file fast path', async () => {
+ const firstJdk = {
+ version: '17',
+ vendor: 'temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/java/17'
+ };
+ const secondJdk = {
+ version: '21',
+ vendor: 'temurin',
+ id: 'temurin_21',
+ jdkHome: '/opt/java/21'
+ };
+
+ const firstToolchains = await toolchains.generateToolchainDefinition(
+ '',
+ firstJdk.version,
+ firstJdk.vendor,
+ firstJdk.id,
+ firstJdk.jdkHome
+ );
+ const mergedToolchains = await toolchains.generateToolchainDefinition(
+ firstToolchains,
+ secondJdk.version,
+ secondJdk.vendor,
+ secondJdk.id,
+ secondJdk.jdkHome
+ );
+
+ for (const jdk of [firstJdk, secondJdk]) {
+ expect(mergedToolchains).toContain(`${jdk.id}`);
+ expect(mergedToolchains).toContain(`${jdk.jdkHome}`);
+ }
+ expect((mergedToolchains.match(//g) || []).length).toBe(2);
+ });
+
+ it('preserves custom attributes and elements when merging existing toolchains.xml', async () => {
+ const originalFile = `
+
+ foo
+
+ baz & qux
+
+
+ /usr/local/bin/foo
+
+
+ `;
+
+ const mergedToolchains = await toolchains.generateToolchainDefinition(
+ originalFile,
+ '21&<>"\'',
+ 'Temurin&<>"\'',
+ 'temurin_21&<>"\'',
+ '/opt/java/21&<>"\''
+ );
+ const parsed = parseXmlObject(mergedToolchains) as any;
+ const merged = parsed.toolchains.toolchain;
+
+ expect(parsed.toolchains['@customRoot']).toBe('A & B');
+ expect(merged).toHaveLength(2);
+ expect(merged[0].provides.id).toBe('temurin_21&<>"\'');
+ expect(merged[0].configuration.jdkHome).toBe('/opt/java/21&<>"\'');
+ expect(merged[1]['@customAttr']).toBe('custom & value');
+ expect(merged[1].provides['@customProvides']).toBe('yes');
+ expect(merged[1].provides.custom['#text']).toBe('baz & qux');
+ expect(merged[1].provides.custom['@attr']).toBe('custom " attr');
+ });
+
+ it('preserves toolchains from previous executions across multiple setup-java runs', async () => {
+ // Regression test for https://github.com/actions/setup-java/issues/1099
+ // Running setup-java several times in the same job (e.g. multiple steps / multiple
+ // java-version entries) must accumulate every JDK in toolchains.xml rather
+ // than replacing previously registered entries.
+ (core.getInput as jest.Mock).mockImplementation((name: string) => {
+ if (name === 'settings-path') return m2Dir;
+ return '';
+ });
+
+ const runs = [
+ {
+ version: '8',
+ distributionName: 'temurin',
+ id: 'temurin_8',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/8.0.1-12/x64'
+ },
+ {
+ version: '11',
+ distributionName: 'temurin',
+ id: 'temurin_11',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.1-12/x64'
+ },
+ {
+ version: '17',
+ distributionName: 'temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ }
+ ];
+
+ for (const run of runs) {
+ await toolchains.configureToolchains(
+ run.version,
+ run.distributionName,
+ run.jdkHome,
+ undefined
+ );
+ }
+
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ const contents = fs.readFileSync(toolchainsFile, 'utf-8');
+
+ for (const run of runs) {
+ expect(contents).toContain(`${run.id}`);
+ expect(contents).toContain(`${run.jdkHome}`);
+ }
+ // Exactly one entry per run – no duplicates, none dropped.
+ expect((contents.match(//g) || []).length).toBe(runs.length);
+ }, 100000);
+});
+
+describe('validateToolchainIds', () => {
+ it.each([
+ {
+ name: 'uses generated IDs when no custom IDs are supplied',
+ versions: ['17', '21'],
+ versionFile: '',
+ toolchainIds: []
+ },
+ {
+ name: 'accepts one custom ID for a single Java version',
+ versions: ['21'],
+ versionFile: '',
+ toolchainIds: ['custom-21']
+ },
+ {
+ name: 'accepts one custom ID per Java version',
+ versions: ['17', '21'],
+ versionFile: '',
+ toolchainIds: ['custom-17', 'custom-21']
+ },
+ {
+ name: 'accepts one custom ID with java-version-file',
+ versions: [],
+ versionFile: '.java-version',
+ toolchainIds: ['custom-file-version']
+ }
+ ])('$name', ({versions, versionFile, toolchainIds}) => {
+ expect(() =>
+ toolchains.validateToolchainIds(versions, versionFile, toolchainIds)
+ ).not.toThrow();
+ });
+
+ it.each([
+ {
+ name: 'rejects fewer IDs than Java versions',
+ versions: ['17', '21'],
+ versionFile: '',
+ toolchainIds: ['custom-17'],
+ expectedMessage:
+ 'The number of Maven toolchain IDs (1) must match the number of Java versions (2)'
+ },
+ {
+ name: 'rejects extra IDs for a single Java version',
+ versions: ['21'],
+ versionFile: '',
+ toolchainIds: ['custom-21', 'custom-extra'],
+ expectedMessage:
+ 'The number of Maven toolchain IDs (2) must match the number of Java versions (1)'
+ },
+ {
+ name: 'rejects extra IDs with java-version-file',
+ versions: [],
+ versionFile: '.java-version',
+ toolchainIds: ['custom-file-version', 'custom-extra'],
+ expectedMessage:
+ 'The number of Maven toolchain IDs (2) must match the number of Java versions (1)'
+ }
+ ])('$name', ({versions, versionFile, toolchainIds, expectedMessage}) => {
+ expect(() =>
+ toolchains.validateToolchainIds(versions, versionFile, toolchainIds)
+ ).toThrow(expectedMessage);
+ });
+});
+
+function xmlElementText(xml: string, tagName: string): string {
+ const match = new RegExp(`<${tagName}>([\\s\\S]*?)${tagName}>`).exec(xml);
+ expect(match).not.toBeNull();
+ return (parseXmlObject(`${match?.[1]}`) as {value: string})
+ .value;
+}
+
+function parseXmlObject(xml: string): unknown {
+ const parser = new XMLParser({
+ ignoreAttributes: false,
+ attributeNamePrefix: '@',
+ textNodeName: '#text',
+ parseAttributeValue: false,
+ parseTagValue: false,
+ trimValues: true,
+ isArray: tagName => tagName === 'toolchain'
+ });
+ return parser.parse(xml);
+}
diff --git a/__tests__/util-install.test.ts b/__tests__/util-install.test.ts
new file mode 100644
index 000000000..b56529cd6
--- /dev/null
+++ b/__tests__/util-install.test.ts
@@ -0,0 +1,508 @@
+import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
+import * as fs from 'fs';
+import * as os from 'os';
+import * as path from 'path';
+
+jest.unstable_mockModule('@actions/core', () => ({
+ debug: jest.fn(),
+ info: jest.fn(),
+ warning: jest.fn(),
+ error: jest.fn(),
+ getInput: jest.fn(() => ''),
+ isDebug: jest.fn(() => false),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ setOutput: jest.fn()
+}));
+
+jest.unstable_mockModule('@actions/tool-cache', () => ({
+ cacheDir: jest.fn(),
+ extractTar: jest.fn(),
+ extractZip: jest.fn(),
+ extract7z: jest.fn()
+}));
+
+jest.unstable_mockModule('@actions/exec', () => ({
+ exec: jest.fn()
+}));
+
+jest.unstable_mockModule('@actions/io', () => ({
+ which: jest.fn(),
+ rmRF: jest.fn(async (target: string) =>
+ fs.rmSync(target, {recursive: true, force: true})
+ ),
+ mkdirP: jest.fn(async (target: string) =>
+ fs.mkdirSync(target, {recursive: true})
+ )
+}));
+
+jest.unstable_mockModule('@actions/http-client', () => ({
+ HttpClient: jest.fn(),
+ HttpClientError: class HttpClientError extends Error {}
+}));
+
+const tc = await import('@actions/tool-cache');
+const exec = await import('@actions/exec');
+const io = await import('@actions/io');
+const {
+ cacheJdkDir,
+ extractJdkFile,
+ getArtifactFingerprint,
+ getJavaVersionFromReleaseFile
+} = await import('../src/util.js');
+
+const originalToolCache = process.env['RUNNER_TOOL_CACHE'];
+const originalTemp = process.env['RUNNER_TEMP'];
+const originalPlatform = process.platform;
+
+let workDir: string;
+
+function setPlatform(platform: NodeJS.Platform) {
+ Object.defineProperty(process, 'platform', {
+ value: platform,
+ configurable: true
+ });
+}
+
+beforeEach(() => {
+ workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-java-util-'));
+ process.env['RUNNER_TOOL_CACHE'] = path.join(workDir, 'toolcache');
+ process.env['RUNNER_TEMP'] = path.join(workDir, 'temp');
+ fs.mkdirSync(process.env['RUNNER_TEMP'], {recursive: true});
+});
+
+afterEach(() => {
+ jest.clearAllMocks();
+ setPlatform(originalPlatform);
+ while (lockedDirs.length) {
+ fs.chmodSync(lockedDirs.pop()!, 0o755);
+ }
+ fs.rmSync(workDir, {recursive: true, force: true});
+ if (originalToolCache === undefined) {
+ delete process.env['RUNNER_TOOL_CACHE'];
+ } else {
+ process.env['RUNNER_TOOL_CACHE'] = originalToolCache;
+ }
+ if (originalTemp === undefined) {
+ delete process.env['RUNNER_TEMP'];
+ } else {
+ process.env['RUNNER_TEMP'] = originalTemp;
+ }
+});
+
+function createJdkDir(name = 'jdk-source'): string {
+ const sourceDir = path.join(workDir, name);
+ fs.mkdirSync(path.join(sourceDir, 'bin'), {recursive: true});
+ fs.writeFileSync(path.join(sourceDir, 'bin', 'java'), 'binary');
+ fs.writeFileSync(path.join(sourceDir, 'release'), 'JAVA_VERSION="17"');
+
+ return sourceDir;
+}
+
+// A rename needs write permission on the source's parent directory, so making
+// that parent read-only is a portable way to force the same failure a
+// cross-device tool-cache (EXDEV) or a Windows anti-virus handle (EPERM) would.
+// Root ignores the permission bits, so those tests are skipped there.
+const canForceRenameFailure =
+ process.platform !== 'win32' &&
+ typeof process.getuid === 'function' &&
+ process.getuid() !== 0;
+const itUnlessRoot = canForceRenameFailure ? it : it.skip;
+const lockedDirs: string[] = [];
+
+function createUnrenameableJdkDir(): string {
+ const parent = path.join(workDir, 'locked');
+ fs.mkdirSync(parent, {recursive: true});
+ const sourceDir = path.join(parent, 'jdk-source');
+ fs.mkdirSync(path.join(sourceDir, 'bin'), {recursive: true});
+ fs.writeFileSync(path.join(sourceDir, 'bin', 'java'), 'binary');
+ fs.chmodSync(parent, 0o555);
+ lockedDirs.push(parent);
+
+ return sourceDir;
+}
+
+describe('cacheJdkDir', () => {
+ it('moves the JDK into the tool-cache instead of copying it', async () => {
+ const sourceDir = createJdkDir();
+
+ const javaPath = await cacheJdkDir(
+ sourceDir,
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+
+ expect(javaPath).toBe(
+ path.join(
+ process.env['RUNNER_TOOL_CACHE']!,
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ )
+ );
+ expect(fs.existsSync(path.join(javaPath, 'bin', 'java'))).toBe(true);
+ expect(fs.existsSync(path.join(javaPath, 'release'))).toBe(true);
+ // the source is moved, not copied, so it no longer exists
+ expect(fs.existsSync(sourceDir)).toBe(false);
+ expect(tc.cacheDir).not.toHaveBeenCalled();
+ });
+
+ it('writes the .complete marker expected by the tool-cache', async () => {
+ const javaPath = await cacheJdkDir(
+ createJdkDir(),
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+
+ expect(fs.existsSync(`${javaPath}.complete`)).toBe(true);
+ });
+
+ it('replaces an existing tool-cache entry', async () => {
+ const destPath = path.join(
+ process.env['RUNNER_TOOL_CACHE']!,
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+ fs.mkdirSync(destPath, {recursive: true});
+ fs.writeFileSync(path.join(destPath, 'stale'), 'stale');
+
+ const javaPath = await cacheJdkDir(
+ createJdkDir(),
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+
+ expect(fs.existsSync(path.join(javaPath, 'stale'))).toBe(false);
+ expect(fs.existsSync(path.join(javaPath, 'bin', 'java'))).toBe(true);
+ });
+
+ it('normalizes the version the same way as tc.cacheDir', async () => {
+ const javaPath = await cacheJdkDir(
+ createJdkDir(),
+ 'Java_temurin_jdk',
+ 'v17.0.1',
+ 'x64'
+ );
+
+ expect(path.basename(path.dirname(javaPath))).toBe('17.0.1');
+ });
+
+ it('keeps unparseable versions as-is', async () => {
+ const javaPath = await cacheJdkDir(
+ createJdkDir(),
+ 'Java_temurin_jdk',
+ '17.0.1-ea.3',
+ 'x64'
+ );
+
+ expect(path.basename(path.dirname(javaPath))).toBe('17.0.1-ea.3');
+ });
+
+ it('falls back to tc.cacheDir when the move fails', async () => {
+ (tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
+ const missingDir = path.join(workDir, 'does-not-exist');
+
+ const javaPath = await cacheJdkDir(
+ missingDir,
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+
+ expect(javaPath).toBe('/fallback/path');
+ expect(tc.cacheDir).toHaveBeenCalledWith(
+ missingDir,
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+ });
+
+ itUnlessRoot(
+ 'falls back to tc.cacheDir when the rename itself fails',
+ async () => {
+ const sourceDir = createUnrenameableJdkDir();
+ (tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
+
+ await expect(
+ cacheJdkDir(sourceDir, 'Java_temurin_jdk', '17.0.1', 'x64')
+ ).resolves.toBe('/fallback/path');
+ // the source must survive so the copy-based fallback can still read it
+ expect(fs.existsSync(path.join(sourceDir, 'bin', 'java'))).toBe(true);
+ }
+ );
+
+ itUnlessRoot(
+ 'does not leave a .complete marker behind when the rename fails',
+ async () => {
+ const destPath = path.join(
+ process.env['RUNNER_TOOL_CACHE']!,
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+ fs.mkdirSync(destPath, {recursive: true});
+ fs.writeFileSync(`${destPath}.complete`, '');
+ (tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
+
+ await cacheJdkDir(
+ createUnrenameableJdkDir(),
+ 'Java_temurin_jdk',
+ '17.0.1',
+ 'x64'
+ );
+
+ // a stale marker without a matching installation would make the
+ // tool-cache resolve a directory that is no longer there
+ expect(fs.existsSync(`${destPath}.complete`)).toBe(false);
+ }
+ );
+
+ it('falls back to tc.cacheDir for symlinked sources', async () => {
+ const realDir = createJdkDir('real-jdk');
+ const linkDir = path.join(workDir, 'linked-jdk');
+ fs.symlinkSync(realDir, linkDir, 'dir');
+ (tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
+
+ await expect(
+ cacheJdkDir(linkDir, 'Java_temurin_jdk', '17.0.1', 'x64')
+ ).resolves.toBe('/fallback/path');
+ // moving the symlink itself would leave a dangling tool-cache entry
+ expect(fs.lstatSync(linkDir).isSymbolicLink()).toBe(true);
+ });
+
+ it('defaults the architecture the same way as tc.cacheDir', async () => {
+ const javaPath = await cacheJdkDir(
+ createJdkDir(),
+ 'Java_temurin_jdk',
+ '17.0.1',
+ ''
+ );
+
+ expect(javaPath).toBe(
+ path.join(
+ process.env['RUNNER_TOOL_CACHE']!,
+ 'Java_temurin_jdk',
+ '17.0.1',
+ os.arch()
+ )
+ );
+ });
+
+ it('falls back to tc.cacheDir when the tool-cache location is unknown', async () => {
+ delete process.env['RUNNER_TOOL_CACHE'];
+ (tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
+
+ await expect(
+ cacheJdkDir(createJdkDir(), 'Java_temurin_jdk', '17.0.1', 'x64')
+ ).resolves.toBe('/fallback/path');
+ });
+});
+
+describe('getJavaVersionFromReleaseFile', () => {
+ it.each([
+ ['JAVA_RUNTIME_VERSION="21.0.9+7-LTS-123"', '21.0.9+7'],
+ ['JAVA_RUNTIME_VERSION="17.0.12+8-jvmci-23.1-b52"', '17.0.12+8'],
+ ['JAVA_RUNTIME_VERSION="25+36-LTS"', '25.0.0+36'],
+ ['JAVA_VERSION="25.0.1"', '25.0.1'],
+ ['JAVA_VERSION="25"', '25.0.0']
+ ])('reads a concrete version from %s', (contents, expected) => {
+ const javaHome = createJdkDir();
+ fs.writeFileSync(path.join(javaHome, 'release'), contents);
+
+ expect(getJavaVersionFromReleaseFile(javaHome)).toBe(expected);
+ });
+
+ it('reads the macOS Contents/Home release file', () => {
+ const javaHome = path.join(workDir, 'macos-jdk');
+ fs.mkdirSync(path.join(javaHome, 'Contents', 'Home'), {recursive: true});
+ fs.writeFileSync(
+ path.join(javaHome, 'Contents', 'Home', 'release'),
+ 'JAVA_RUNTIME_VERSION="21.0.9+7-LTS"'
+ );
+
+ expect(getJavaVersionFromReleaseFile(javaHome)).toBe('21.0.9+7');
+ });
+
+ it('fails when the JDK release metadata has no usable version', () => {
+ const javaHome = createJdkDir();
+ fs.writeFileSync(path.join(javaHome, 'release'), 'IMPLEMENTOR="Oracle"');
+
+ expect(() => getJavaVersionFromReleaseFile(javaHome)).toThrow(
+ /Unable to determine the installed Java version/
+ );
+ });
+});
+
+describe('extractJdkFile', () => {
+ it('uses pigz for tarballs when it is available', async () => {
+ (io.which as jest.Mock).mockResolvedValue('/usr/bin/pigz' as never);
+ (tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
+
+ await expect(extractJdkFile('/tmp/jdk.tar.gz')).resolves.toBe('/extracted');
+ expect(tc.extractTar).toHaveBeenCalledWith(
+ '/tmp/jdk.tar.gz',
+ expect.stringContaining(process.env['RUNNER_TEMP']!),
+ ['--use-compress-program', '/usr/bin/pigz -d', '-x']
+ );
+ });
+
+ it('falls back to gzip when pigz is not installed', async () => {
+ (io.which as jest.Mock).mockResolvedValue('' as never);
+ (tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
+
+ await expect(extractJdkFile('/tmp/jdk.tar.gz')).resolves.toBe('/extracted');
+ expect(tc.extractTar).toHaveBeenCalledWith('/tmp/jdk.tar.gz');
+ });
+
+ it('falls back to gzip when pigz extraction fails', async () => {
+ (io.which as jest.Mock).mockResolvedValue('/usr/bin/pigz' as never);
+ (tc.extractTar as jest.Mock)
+ .mockRejectedValueOnce(new Error('pigz exploded') as never)
+ .mockResolvedValue('/extracted' as never);
+
+ await expect(extractJdkFile('/tmp/jdk.tar.gz')).resolves.toBe('/extracted');
+ expect(tc.extractTar).toHaveBeenNthCalledWith(2, '/tmp/jdk.tar.gz');
+ });
+
+ it('cleans up the abandoned folder when pigz extraction fails', async () => {
+ (io.which as jest.Mock).mockResolvedValue('/usr/bin/pigz' as never);
+ let pigzDest: string | undefined;
+ (tc.extractTar as jest.Mock)
+ .mockImplementationOnce((...args: unknown[]) => {
+ pigzDest = args[1] as string;
+ throw new Error('pigz exploded');
+ })
+ .mockResolvedValue('/extracted' as never);
+
+ await extractJdkFile('/tmp/jdk.tar.gz');
+
+ expect(pigzDest).toBeDefined();
+ expect(fs.existsSync(pigzDest!)).toBe(false);
+ });
+
+ it('ignores pigz when its path contains whitespace', async () => {
+ (io.which as jest.Mock).mockResolvedValue(
+ 'C:\\Program Files\\pigz.exe' as never
+ );
+ (tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
+
+ await extractJdkFile('/tmp/jdk.tar.gz');
+
+ // tar word-splits --use-compress-program, so a spaced path is unusable
+ expect(tc.extractTar).toHaveBeenCalledWith('/tmp/jdk.tar.gz');
+ });
+
+ it('leaves uncompressed tarballs on the default extraction path', async () => {
+ (tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
+
+ await expect(extractJdkFile('/tmp/jdk.tar')).resolves.toBe('/extracted');
+ expect(tc.extractTar).toHaveBeenCalledWith('/tmp/jdk.tar');
+ expect(io.which).not.toHaveBeenCalled();
+ });
+
+ it('uses the bundled tar.exe for zip archives on Windows', async () => {
+ setPlatform('win32');
+ const systemRoot = path.join(workDir, 'Windows');
+ fs.mkdirSync(path.join(systemRoot, 'System32'), {recursive: true});
+ const systemTar = path.join(systemRoot, 'System32', 'tar.exe');
+ fs.writeFileSync(systemTar, '');
+ process.env['SystemRoot'] = systemRoot;
+
+ const javaPath = await extractJdkFile('/tmp/jdk.zip');
+
+ expect(tc.extractZip).not.toHaveBeenCalled();
+ expect(exec.exec).toHaveBeenCalledWith(
+ `"${systemTar}"`,
+ ['-xf', '/tmp/jdk.zip', '-C', javaPath],
+ {silent: true}
+ );
+ expect(fs.existsSync(javaPath)).toBe(true);
+ });
+
+ it('falls back to tc.extractZip when tar.exe fails', async () => {
+ setPlatform('win32');
+ const systemRoot = path.join(workDir, 'Windows');
+ fs.mkdirSync(path.join(systemRoot, 'System32'), {recursive: true});
+ fs.writeFileSync(path.join(systemRoot, 'System32', 'tar.exe'), '');
+ process.env['SystemRoot'] = systemRoot;
+ let tarDest: string | undefined;
+ (exec.exec as jest.Mock).mockImplementation((...args: unknown[]) => {
+ tarDest = (args[1] as string[])[3];
+ throw new Error('boom');
+ });
+ (tc.extractZip as jest.Mock).mockResolvedValue('/extracted' as never);
+
+ await expect(extractJdkFile('/tmp/jdk.zip')).resolves.toBe('/extracted');
+ expect(tarDest).toBeDefined();
+ expect(fs.existsSync(tarDest!)).toBe(false);
+ });
+
+ it('uses tc.extractZip on non-Windows platforms', async () => {
+ setPlatform('linux');
+ (tc.extractZip as jest.Mock).mockResolvedValue('/extracted' as never);
+
+ await expect(extractJdkFile('/tmp/jdk.zip')).resolves.toBe('/extracted');
+ expect(exec.exec).not.toHaveBeenCalled();
+ });
+});
+
+describe('getArtifactFingerprint', () => {
+ it('prefers the ETag over the other validators', () => {
+ expect(
+ getArtifactFingerprint({
+ etag: '"abc123"',
+ 'last-modified': 'Wed, 21 Oct 2026 07:28:00 GMT',
+ 'content-length': '195000000'
+ })
+ ).toBe('etag:"abc123"');
+ });
+
+ it('combines the last-modified date and the content length without an ETag', () => {
+ expect(
+ getArtifactFingerprint({
+ 'last-modified': 'Wed, 21 Oct 2026 07:28:00 GMT',
+ 'content-length': '195000000'
+ })
+ ).toBe('mtime:Wed, 21 Oct 2026 07:28:00 GMT;length:195000000');
+ });
+
+ it.each([
+ ['no validators', {}],
+ [
+ 'only a last-modified date',
+ {'last-modified': 'Wed, 21 Oct 2026 07:28:00 GMT'}
+ ],
+ ['only a content length', {'content-length': '195000000'}],
+ [
+ 'blank validators',
+ {etag: ' ', 'last-modified': '', 'content-length': ''}
+ ],
+ ['missing headers', undefined]
+ ])('returns undefined for %s', (_label, headers) => {
+ expect(getArtifactFingerprint(headers)).toBeUndefined();
+ });
+
+ it('uses the first value of a repeated header', () => {
+ expect(getArtifactFingerprint({etag: ['"first"', '"second"'] as any})).toBe(
+ 'etag:"first"'
+ );
+ });
+
+ it('distinguishes a republished artifact from the previous one', () => {
+ const before = getArtifactFingerprint({
+ 'last-modified': 'Wed, 21 Oct 2026 07:28:00 GMT',
+ 'content-length': '195000000'
+ });
+ const after = getArtifactFingerprint({
+ 'last-modified': 'Thu, 22 Oct 2026 09:03:00 GMT',
+ 'content-length': '195400000'
+ });
+
+ expect(before).not.toBe(after);
+ });
+});
diff --git a/__tests__/util.test.ts b/__tests__/util.test.ts
index 9c943c2fa..05bf6deb1 100644
--- a/__tests__/util.test.ts
+++ b/__tests__/util.test.ts
@@ -1,14 +1,151 @@
-import * as cache from '@actions/cache';
-import * as core from '@actions/core';
import {
+ jest,
+ describe,
+ it,
+ expect,
+ beforeEach,
+ afterAll,
+ afterEach
+} from '@jest/globals';
+import {fileURLToPath} from 'url';
+import * as fs from 'fs';
+import * as path from 'path';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+
+// Mock @actions/core
+jest.unstable_mockModule('@actions/core', () => ({
+ getInput: jest.fn(),
+ getBooleanInput: jest.fn(),
+ getMultilineInput: jest.fn(),
+ setOutput: jest.fn(),
+ setFailed: jest.fn(),
+ warning: jest.fn(),
+ info: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ notice: jest.fn(),
+ startGroup: jest.fn(),
+ endGroup: jest.fn(),
+ addPath: jest.fn(),
+ exportVariable: jest.fn(),
+ saveState: jest.fn(),
+ getState: jest.fn(),
+ setSecret: jest.fn(),
+ isDebug: jest.fn(() => false),
+ group: jest.fn((_name: string, fn: () => Promise) => fn()),
+ toPlatformPath: jest.fn((p: string) => p),
+ toWin32Path: jest.fn((p: string) => p),
+ toPosixPath: jest.fn((p: string) => p)
+}));
+
+const core = await import('@actions/core');
+
+const {
convertVersionToSemver,
+ getNextPageUrlFromLinkHeader,
+ getVersionFromFileContent,
isVersionSatisfies,
- isCacheFeatureAvailable,
- isGhes
-} from '../src/util';
+ isGhes,
+ validatePaginationUrl,
+ getLatestMajorVersion,
+ getBooleanInput,
+ isJdkCacheEnabled
+} = await import('../src/util.js');
+
+describe('getBooleanInput', () => {
+ let inputs: Record;
-jest.mock('@actions/cache');
-jest.mock('@actions/core');
+ beforeEach(() => {
+ inputs = {};
+ (core.getInput as jest.Mock).mockImplementation(
+ (name: string) => inputs[name] ?? ''
+ );
+ });
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ });
+
+ it.each([
+ ['true', true],
+ ['TRUE', true],
+ ['TrUe', true],
+ [' true ', true],
+ ['false', false],
+ ['FALSE', false],
+ ['FaLsE', false],
+ [' false ', false]
+ ])('parses %j as %s', (value: string, expected: boolean) => {
+ inputs['boolean-input'] = value;
+
+ expect(getBooleanInput('boolean-input')).toBe(expected);
+ });
+
+ it.each([
+ [undefined, false],
+ [false, false],
+ [true, true]
+ ])(
+ 'uses the configured default %s when the input is omitted',
+ (defaultValue: boolean | undefined, expected: boolean) => {
+ expect(getBooleanInput('boolean-input', defaultValue)).toBe(expected);
+ }
+ );
+
+ it('uses the configured default for a whitespace-only input', () => {
+ inputs['boolean-input'] = ' ';
+
+ expect(getBooleanInput('boolean-input', true)).toBe(true);
+ });
+
+ it.each([
+ 'check-latest',
+ 'force-download',
+ 'set-default',
+ 'verify-signature',
+ 'overwrite-settings',
+ 'show-download-progress',
+ 'problem-matcher'
+ ])('rejects an invalid value for %s', inputName => {
+ inputs[inputName] = 'ture';
+
+ expect(() => getBooleanInput(inputName)).toThrow(
+ `Invalid value 'ture' for boolean input '${inputName}'. Expected 'true' or 'false'.`
+ );
+ });
+});
+
+describe('isJdkCacheEnabled', () => {
+ let inputs: Record;
+
+ beforeEach(() => {
+ inputs = {};
+ (core.getInput as jest.Mock).mockImplementation(
+ (name: string) => inputs[name] ?? ''
+ );
+ });
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ });
+
+ it.each([
+ ['', '', false],
+ ['', 'true', true],
+ ['', 'false', false],
+ ['maven', '', true],
+ ['maven', 'true', true],
+ ['maven', 'false', false]
+ ])(
+ 'resolves cache=%j and cache-jdk=%j to %s',
+ (cache, cacheJdk, expected) => {
+ inputs['cache-jdk'] = cacheJdk;
+
+ expect(isJdkCacheEnabled(cache)).toBe(expected);
+ }
+ );
+});
describe('isVersionSatisfies', () => {
it.each([
@@ -24,7 +161,11 @@ describe('isVersionSatisfies', () => {
['2.5.1+3', '2.5.1+3', true],
['2.5.1+3', '2.5.1+2', false],
['15.0.0+14', '15.0.0+14.1.202003190635', false],
- ['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true]
+ ['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true],
+ // 4-segment versions (e.g. JetBrains Runtime '17.0.8.1+1080.1') are not
+ // valid semver — they should be rejected, not throw.
+ ['25.0.3+480.61', '17.0.8.1+1080.1', false],
+ ['17', '17.0.8.1+1080.1', false]
])(
'%s, %s -> %s',
(inputRange: string, inputVersion: string, expected: boolean) => {
@@ -34,41 +175,6 @@ describe('isVersionSatisfies', () => {
);
});
-describe('isCacheFeatureAvailable', () => {
- it('isCacheFeatureAvailable disabled on GHES', () => {
- jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false);
- const infoMock = jest.spyOn(core, 'warning');
- const message =
- 'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.';
- try {
- process.env['GITHUB_SERVER_URL'] = 'http://example.com';
- expect(isCacheFeatureAvailable()).toBeFalsy();
- expect(infoMock).toHaveBeenCalledWith(message);
- } finally {
- delete process.env['GITHUB_SERVER_URL'];
- }
- });
-
- it('isCacheFeatureAvailable disabled on dotcom', () => {
- jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false);
- const infoMock = jest.spyOn(core, 'warning');
- const message =
- 'The runner was not able to contact the cache service. Caching will be skipped';
- try {
- process.env['GITHUB_SERVER_URL'] = 'http://github.com';
- expect(isCacheFeatureAvailable()).toBe(false);
- expect(infoMock).toHaveBeenCalledWith(message);
- } finally {
- delete process.env['GITHUB_SERVER_URL'];
- }
- });
-
- it('isCacheFeatureAvailable is enabled', () => {
- jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => true);
- expect(isCacheFeatureAvailable()).toBe(true);
- });
-});
-
describe('convertVersionToSemver', () => {
it.each([
['12', '12'],
@@ -82,11 +188,230 @@ describe('convertVersionToSemver', () => {
});
});
+describe('getNextPageUrlFromLinkHeader', () => {
+ it.each([
+ [
+ {
+ link: '; rel="next"'
+ },
+ 'https://api.adoptium.net/v3/info/release_versions?page=1&page_size=10'
+ ],
+ [
+ {
+ Link: '; rel="last", ; rel="next"'
+ },
+ 'https://example.com/next?page=2'
+ ],
+ [
+ {
+ link: '; type="application/json"; rel="next"'
+ },
+ 'https://api.adoptium.net/v3/versions?page=3'
+ ],
+ [{link: '; rel="last"'}, null],
+ [{link: '; rel="nextsomething"'}, null],
+ [undefined, null]
+ ])('returns %s -> %s', (headers, expected) => {
+ expect(getNextPageUrlFromLinkHeader(headers)).toBe(expected);
+ });
+});
+
+describe('validatePaginationUrl', () => {
+ it('accepts URL with matching origin', () => {
+ expect(
+ validatePaginationUrl(
+ 'https://api.adoptium.net/v3/assets?page=2',
+ 'https://api.adoptium.net'
+ )
+ ).toBe(true);
+ });
+
+ it('rejects URL with different host', () => {
+ expect(
+ validatePaginationUrl(
+ 'https://evil.example.com/steal?data=1',
+ 'https://api.adoptium.net'
+ )
+ ).toBe(false);
+ });
+
+ it('rejects URL with different protocol', () => {
+ expect(
+ validatePaginationUrl(
+ 'http://api.adoptium.net/v3/assets?page=2',
+ 'https://api.adoptium.net'
+ )
+ ).toBe(false);
+ });
+
+ it('returns false for invalid URL', () => {
+ expect(validatePaginationUrl('not-a-url', 'https://api.adoptium.net')).toBe(
+ false
+ );
+ });
+
+ it('accepts URL with explicit default port', () => {
+ expect(
+ validatePaginationUrl(
+ 'https://api.adoptium.net:443/v3/assets?page=2',
+ 'https://api.adoptium.net'
+ )
+ ).toBe(true);
+ });
+});
+
+describe('getVersionFromFileContent', () => {
+ describe('.sdkmanrc', () => {
+ it.each([
+ ['java=11.0.20.1-tem', '11.0.20', 'temurin'],
+ ['java = 11.0.20.1-tem', '11.0.20', 'temurin'],
+ ['java=11.0.20.1-tem # a comment in sdkmanrc', '11.0.20', 'temurin'],
+ ['java=11.0.20.1-tem\n#java=21.0.20.1-tem\n', '11.0.20', 'temurin'], // choose first match
+ ['java=11.0.20.1-tem\njava=21.0.20.1-tem\n', '11.0.20', 'temurin'], // choose first match
+ ['#java=11.0.20.1-tem\njava=21.0.20.1-tem\n', '21.0.20', 'temurin'], // first one is 'commented' in .sdkmanrc
+ ['java=21.0.5-zulu', '21.0.5', 'zulu'],
+ ['java=17.0.13-albba', '17.0.13', 'dragonwell'],
+ ['java=17.0.13-amzn', '17', 'corretto'],
+ ['java=21.0.5-graal', '21.0.5', 'graalvm'],
+ ['java=17.0.9-graalce', '17.0.9', 'graalvm'],
+ ['java=11.0.25-librca', '11.0.25', 'liberica'],
+ ['java=11.0.25-ms', '11.0.25', 'microsoft'],
+ ['java=21.0.5-oracle', '21.0.5', 'oracle'],
+ ['java=11.0.25-sapmchn', '11.0.25', 'sapmachine'],
+ ['java=21.0.5-jbr', '21.0.5', 'jetbrains'],
+ ['java=11.0.25-sem', '11.0.25', 'semeru'],
+ ['java=17.0.13-dragonwell', '17.0.13', 'dragonwell'],
+ ['java=21.0.5-kona', '21.0.5', 'kona']
+ ])(
+ 'parsing %s should return version %s and distribution %s',
+ (content: string, expectedVersion: string, expectedDist: string) => {
+ const actual = getVersionFromFileContent(
+ content,
+ 'openjdk',
+ '.sdkmanrc'
+ );
+ expect(actual?.version).toBe(expectedVersion);
+ expect(actual?.distribution).toBe(expectedDist);
+ }
+ );
+
+ it('should warn and return undefined distribution for unknown identifier', () => {
+ const warnSpy = jest.spyOn(core, 'warning');
+ const actual = getVersionFromFileContent(
+ 'java=21.0.5-unknown',
+ 'temurin',
+ '.sdkmanrc'
+ );
+ expect(actual?.version).toBe('21.0.5');
+ expect(actual?.distribution).toBeUndefined();
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Unknown SDKMAN distribution identifier')
+ );
+ });
+
+ it('should return version without distribution when no suffix provided', () => {
+ const actual = getVersionFromFileContent(
+ 'java=11.0.20',
+ 'temurin',
+ '.sdkmanrc'
+ );
+ expect(actual?.version).toBe('11.0.20');
+ expect(actual?.distribution).toBeUndefined();
+ });
+
+ describe('known versions', () => {
+ const csv = fs.readFileSync(
+ path.join(__dirname, 'data/sdkman-java-versions.csv'),
+ 'utf8'
+ );
+ const versions = csv.split('\n').map(r => r.split(', '));
+
+ it.each(versions)(
+ 'parsing %s should return %s',
+ (sdkmanJavaVersion: string, expected: string) => {
+ const asContent = `java=${sdkmanJavaVersion}`;
+ const actual = getVersionFromFileContent(
+ asContent,
+ 'openjdk',
+ '.sdkmanrc'
+ );
+ expect(actual?.version).toBe(expected);
+ }
+ );
+ });
+ });
+
+ describe('.tool-versions', () => {
+ it.each([
+ ['java temurin-17.0.3+7', '17.0.3+7', 'temurin'],
+ ['java temurin-jre-17.0.3+7', '17.0.3+7', 'temurin'],
+ ['java adoptopenjdk-11.0.16+8', '11.0.16+8', 'temurin'],
+ ['java adoptopenjdk-openj9-11.0.16+8', '11.0.16+8', 'temurin'],
+ ['java zulu-11.56.19', '11.56.19', 'zulu'],
+ ['java corretto-17.0.13.11.1', '17', 'corretto'], // corretto -> major only
+ ['java liberica-11.0.15+10', '11.0.15+10', 'liberica'],
+ ['java microsoft-11.0.13.8.1', '11.0.13', 'microsoft'],
+ ['java semeru-openj9-11.0.25+9', '11.0.25+9', 'semeru'],
+ ['java ibm-openj9-11.0.25+9', '11.0.25+9', 'semeru'],
+ ['java dragonwell-17.0.13.0.13+11', '17.0.13', 'dragonwell'],
+ ['java graalvm-22.3.0+java17', '22.3.0+java17', 'graalvm'],
+ ['java graalvm-community-22.3.0', '22.3.0', 'graalvm-community'],
+ ['java oracle-graalvm-21.0.5', '21.0.5', 'graalvm'],
+ ['java oracle-21.0.5', '21.0.5', 'oracle'],
+ ['java sapmachine-21.0.5', '21.0.5', 'sapmachine'],
+ ['java kona-17.0.13', '17.0.13', 'kona'],
+ ['java jetbrains-21.0.5', '21.0.5', 'jetbrains']
+ ])(
+ 'parsing %s should return version %s and distribution %s',
+ (content: string, expectedVersion: string, expectedDist: string) => {
+ const actual = getVersionFromFileContent(
+ content,
+ 'openjdk',
+ '.tool-versions'
+ );
+ expect(actual?.version).toBe(expectedVersion);
+ expect(actual?.distribution).toBe(expectedDist);
+ }
+ );
+
+ it.each([
+ ['java 17.0.7', '17.0.7'],
+ ['java 17', '17'],
+ ['java 1.8', '8'],
+ ['java 21-ea', '21-ea']
+ ])(
+ 'parsing prefix-less %s should return version %s and no distribution',
+ (content: string, expectedVersion: string) => {
+ const actual = getVersionFromFileContent(
+ content,
+ 'temurin',
+ '.tool-versions'
+ );
+ expect(actual?.version).toBe(expectedVersion);
+ expect(actual?.distribution).toBeUndefined();
+ }
+ );
+
+ it('should warn and return undefined distribution for unsupported vendor', () => {
+ const warnSpy = jest.spyOn(core, 'warning');
+ const actual = getVersionFromFileContent(
+ 'java openjdk-17.0.7',
+ 'temurin',
+ '.tool-versions'
+ );
+ expect(actual?.version).toBe('17.0.7');
+ expect(actual?.distribution).toBeUndefined();
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Unknown asdf distribution identifier')
+ );
+ });
+ });
+});
+
describe('isGhes', () => {
const pristineEnv = process.env;
beforeEach(() => {
- jest.resetModules();
process.env = {...pristineEnv};
});
@@ -119,3 +444,33 @@ describe('isGhes', () => {
expect(isGhes()).toBeTruthy();
});
});
+
+describe('getLatestMajorVersion', () => {
+ const makeHttp = (getJson: jest.Mock) =>
+ ({getJson}) as unknown as import('@actions/http-client').HttpClient;
+
+ it('returns most_recent_feature_release from the Adoptium API', async () => {
+ const getJson = jest.fn(async () => ({
+ statusCode: 200,
+ result: {most_recent_feature_release: 25},
+ headers: {}
+ }));
+
+ await expect(getLatestMajorVersion(makeHttp(getJson))).resolves.toBe(25);
+ expect(getJson).toHaveBeenCalledWith(
+ 'https://api.adoptium.net/v3/info/available_releases'
+ );
+ });
+
+ it('throws when the response does not contain a usable value', async () => {
+ const getJson = jest.fn(async () => ({
+ statusCode: 200,
+ result: {},
+ headers: {}
+ }));
+
+ await expect(getLatestMajorVersion(makeHttp(getJson))).rejects.toThrow(
+ 'Could not determine the latest available Java major version'
+ );
+ });
+});
diff --git a/__tests__/verify-java.sh b/__tests__/verify-java.sh
index 069d9008a..b7904f248 100755
--- a/__tests__/verify-java.sh
+++ b/__tests__/verify-java.sh
@@ -12,6 +12,8 @@ fi
EXPECTED_JAVA_VERSION=$1
EXPECTED_PATH=$2
+SETUP_JAVA_VERSION=$3
+REQUIRE_CONCRETE_VERSION=$4
EXPECTED_JAVA_VERSION=$(echo $EXPECTED_JAVA_VERSION | cut -d'+' -f1)
if [[ $EXPECTED_JAVA_VERSION == 8 ]] || [[ $EXPECTED_JAVA_VERSION == 8.* ]]; then
@@ -31,6 +33,24 @@ if [ -z "$GREP_RESULT" ]; then
exit 1
fi
+if [ -n "$SETUP_JAVA_VERSION" ]; then
+ OUTPUT_JAVA_VERSION=$(echo "$SETUP_JAVA_VERSION" | cut -d'+' -f1)
+ if [[ $OUTPUT_JAVA_VERSION == *-ea* ]]; then
+ OUTPUT_JAVA_VERSION=$(echo "$OUTPUT_JAVA_VERSION" | cut -d'-' -f1 | cut -d'.' -f1)
+ fi
+ OUTPUT_GREP_RESULT=$(echo "$ACTUAL_JAVA_VERSION" | grep -E "^(openjdk|java) version \"$OUTPUT_JAVA_VERSION")
+ if [ -z "$OUTPUT_GREP_RESULT" ]; then
+ echo "::error::The version output does not match the installed Java version"
+ echo "Version output: $SETUP_JAVA_VERSION"
+ exit 1
+ fi
+ if [ "$REQUIRE_CONCRETE_VERSION" = "true" ] && [ "$OUTPUT_JAVA_VERSION" = "$EXPECTED_JAVA_VERSION" ]; then
+ echo "::error::Expected a concrete version output for a floating JDK"
+ echo "Version output: $SETUP_JAVA_VERSION"
+ exit 1
+ fi
+fi
+
if [ "$EXPECTED_PATH" != "$JAVA_HOME" ]; then
echo "::error::Unexpected path"
echo "Actual path: $JAVA_HOME"
diff --git a/action.yml b/action.yml
index 21a4269d7..60c1a00e9 100644
--- a/action.yml
+++ b/action.yml
@@ -4,41 +4,66 @@ description: 'Set up a specific version of the Java JDK and add the
author: 'GitHub'
inputs:
java-version:
- description: 'The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file'
+ description: 'The Java version to set up. Takes a whole or semver Java version, or the "latest" alias to use the newest available stable release. See examples of supported syntax in README file'
+ required: false
java-version-file:
- description: 'The path to the `.java-version` file. See examples of supported syntax in README file'
+ description: 'The path to a file containing the Java version to set up (.java-version, .tool-versions, .sdkmanrc). Used when java-version is not set. See examples of supported syntax in README file'
+ required: false
distribution:
- description: 'Java distribution. See the list of supported distributions in README file'
- required: true
+ description: 'Java distribution. See the list of supported distributions in README file. This input is required except when java-version-file points to .sdkmanrc with a recognized distribution suffix (e.g., java=21.0.5-tem).'
+ required: false
java-package:
- description: 'The package type (jdk, jre, jdk+fx, jre+fx)'
+ description: 'The package type (`jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, or `jre+ft`). Supported values vary by distribution.'
required: false
default: 'jdk'
architecture:
- description: "The architecture of the package (defaults to the action runner's architecture)"
+ description: "The architecture of the package (`x86`, `x64`, `armv7`, `aarch64`, `ppc64le`, `ppc64`, or `s390x`). Aliases `ia32`, `amd64`, `arm`, and `arm64` are normalized to `x86`, `x64`, `armv7`, and `aarch64`. Supported values vary by distribution and operating system. Defaults to the action runner's architecture."
required: false
- jdkFile:
+ jdk-file:
description: 'Path to where the compressed JDK is located'
required: false
+ jdkFile:
+ description: 'Deprecated alias for `jdk-file`. Path to where the compressed JDK is located. Use `jdk-file` instead; this alias may be removed in a future release.'
+ required: false
+ deprecationMessage: 'The `jdkFile` input is deprecated. Use `jdk-file` instead.'
check-latest:
description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec'
required: false
default: false
+ force-download:
+ description: 'Set this option to always download Java and replace any matching version in the tool cache'
+ required: false
+ default: false
+ set-default:
+ description: 'Set this option to false if you want to install a JDK but not make it the default. When false, JAVA_HOME and PATH are not updated, but JAVA_HOME__ is still set.'
+ required: false
+ default: true
+ verify-signature:
+ description: 'Verify downloaded Java package signatures when supported by the selected distribution'
+ required: false
+ default: false
+ verify-signature-public-key:
+ description: 'ASCII-armored GPG public key used to verify the downloaded package signature. Overrides the default bundled key for the selected distribution.'
+ required: false
server-id:
description: 'ID of the distributionManagement repository in the pom.xml
file. Default is `github`'
required: false
default: 'github'
- server-username:
+ server-username-env-var:
description: 'Environment variable name for the username for authentication
to the Apache Maven repository. Default is $GITHUB_ACTOR'
required: false
- default: 'GITHUB_ACTOR'
- server-password:
+ server-username:
+ description: 'Deprecated alias for server-username-env-var'
+ required: false
+ server-password-env-var:
description: 'Environment variable name for password or token for
authentication to the Apache Maven repository. Default is $GITHUB_TOKEN'
required: false
- default: 'GITHUB_TOKEN'
+ server-password:
+ description: 'Deprecated alias for server-password-env-var'
+ required: false
settings-path:
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
required: false
@@ -47,30 +72,53 @@ inputs:
required: false
default: true
gpg-private-key:
- description: 'GPG private key to import. Default is empty string.'
+ description: 'GPG private key to import into an isolated temporary keyring. Default is empty string.'
+ required: false
+ default: ''
+ gpg-passphrase-env-var:
+ description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set.'
required: false
gpg-passphrase:
- description: 'Environment variable name for the GPG private key passphrase. Default is
- $GPG_PASSPHRASE.'
+ description: 'Deprecated alias for gpg-passphrase-env-var'
required: false
cache:
description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".'
required: false
+ cache-jdk:
+ description: 'Cache downloaded JDK installations between jobs. Defaults to enabled when dependency caching is configured with `cache`; set explicitly to "true" or "false" to override.'
+ required: false
cache-dependency-path:
description: 'The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.'
required: false
+ cache-path:
+ description: 'The path to cache instead of the default dependency cache path for the selected package manager. This option can be used with the `cache` option and supports a list of paths and exclusion patterns.'
+ required: false
+ cache-read-only:
+ description: 'Restore caches without saving cache changes in the post action.'
+ required: false
+ default: false
job-status:
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
+ required: false
default: ${{ job.status }}
token:
description: The token used to authenticate when fetching version manifests hosted on github.com, such as for the Microsoft Build of OpenJDK. When running this action on github.com, the default value is sufficient. When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting.
+ required: false
default: ${{ github.server_url == 'https://github.com' && github.token || '' }}
mvn-toolchain-id:
- description: 'Name of Maven Toolchain ID if the default name of "${distribution}_${java-version}" is not wanted. See examples of supported syntax in Advanced Usage file'
+ description: 'Name of Maven Toolchain ID if the default name of "${mvn-toolchain-vendor}_${java-version}" is not wanted. The toolchain vendor defaults to the "distribution" input. When supplied, the number of IDs must match the number of Java versions. See examples of supported syntax in Advanced Usage file'
required: false
mvn-toolchain-vendor:
description: 'Name of Maven Toolchain Vendor if the default name of "${distribution}" is not wanted. See examples of supported syntax in Advanced Usage file'
required: false
+ show-download-progress:
+ description: 'Whether Maven should print artifact download/transfer progress to the build log. When "false" (default) the action sets "-ntp" (--no-transfer-progress) in MAVEN_ARGS to produce cleaner logs. Set to "true" to keep the progress output. Has no effect on non-Maven builds.'
+ required: false
+ default: false
+ problem-matcher:
+ description: 'Whether to register the Java problem matcher (compiler errors/warnings and uncaught exceptions). Set to "false" to disable annotations.'
+ required: false
+ default: true
outputs:
distribution:
description: 'Distribution of Java that has been installed'
@@ -80,6 +128,8 @@ outputs:
description: 'Path to where the java environment has been installed (same as $JAVA_HOME)'
cache-hit:
description: 'A boolean value to indicate an exact match was found for the primary key'
+ cache-primary-key:
+ description: 'The primary cache key computed by the action for the configured build tool. Empty when caching is not enabled or when caching is skipped (e.g. cache service unavailable). Useful for composing with actions/cache or actions/cache/restore across jobs.'
runs:
using: 'node24'
main: 'dist/setup/index.js'
diff --git a/dist/cleanup/314.index.js b/dist/cleanup/314.index.js
new file mode 100644
index 000000000..1d80a1366
--- /dev/null
+++ b/dist/cleanup/314.index.js
@@ -0,0 +1,224 @@
+export const id = 314;
+export const ids = [314];
+export const modules = {
+
+/***/ 2314:
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+
+// EXPORTS
+__webpack_require__.d(__webpack_exports__, {
+ saveJdkCaches: () => (/* binding */ saveJdkCaches)
+});
+
+// UNUSED EXPORTS: buildJdkCacheKey, getJdkVerificationIdentity, registerJdk, restoreJdk
+
+// EXTERNAL MODULE: external "crypto"
+var external_crypto_ = __webpack_require__(6982);
+// EXTERNAL MODULE: external "fs"
+var external_fs_ = __webpack_require__(9896);
+var external_fs_default = /*#__PURE__*/__webpack_require__.n(external_fs_);
+// EXTERNAL MODULE: external "path"
+var external_path_ = __webpack_require__(6928);
+var external_path_default = /*#__PURE__*/__webpack_require__.n(external_path_);
+// EXTERNAL MODULE: ./node_modules/@actions/cache/lib/cache.js + 291 modules
+var lib_cache = __webpack_require__(5767);
+// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js + 7 modules
+var lib_core = __webpack_require__(3838);
+// EXTERNAL MODULE: ./src/util.ts
+var util = __webpack_require__(4527);
+;// CONCATENATED MODULE: ./src/cache-feature.ts
+
+
+
+function cache_feature_isCacheFeatureAvailable() {
+ if (cache.isFeatureAvailable()) {
+ return true;
+ }
+ if (isGhes()) {
+ core.warning('Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.');
+ return false;
+ }
+ core.warning('The runner was not able to contact the cache service. Caching will be skipped');
+ return false;
+}
+
+;// CONCATENATED MODULE: ./src/jdk-cache.ts
+
+
+
+
+
+
+const STATE_JDK_CACHES = 'jdk-caches';
+const JDK_CACHE_KEY_VERSION = 1;
+const restoredCaches = (/* unused pure expression or super */ null && ([]));
+async function restoreJdk(jdk) {
+ if (!jdk.path || !isCacheFeatureAvailable()) {
+ return false;
+ }
+ const key = buildJdkCacheKey(jdk);
+ let matchedKey;
+ try {
+ matchedKey = await cache.restoreCache([jdk.path], key);
+ }
+ catch (error) {
+ core.warning(`Failed to restore JDK cache: ${error.message}`);
+ }
+ const architecturePath = path.join(jdk.path, jdk.architecture);
+ if (matchedKey &&
+ (!fs.existsSync(architecturePath) ||
+ !fs.existsSync(`${architecturePath}.complete`))) {
+ core.warning(`JDK cache key ${matchedKey} was restored without the expected tool-cache path; downloading the JDK instead.`);
+ matchedKey = undefined;
+ }
+ recordJdkCache({
+ key,
+ path: jdk.path,
+ architecture: jdk.architecture,
+ matchedKey
+ });
+ if (matchedKey) {
+ core.info(`JDK cache restored from key: ${matchedKey}`);
+ return true;
+ }
+ core.info(`JDK cache is not found for ${jdk.distribution} ${jdk.version}`);
+ return false;
+}
+function registerJdk(jdk) {
+ if (!jdk.path) {
+ return;
+ }
+ recordJdkCache({
+ key: buildJdkCacheKey(jdk),
+ path: jdk.path,
+ architecture: jdk.architecture,
+ installation: getInstallationIdentity(jdk.path, jdk.architecture)
+ });
+}
+/**
+ * Cheap fingerprint of the installation stored at a tool-cache path. The
+ * `.complete` marker is (re)created by `tc.cacheDir` every time an
+ * installation is written, so its inode and timestamps change whenever the
+ * installation is replaced. This avoids rehashing a multi-hundred-megabyte JDK
+ * directory while still detecting that the bytes behind a key were swapped.
+ */
+function getInstallationIdentity(jdkPath, architecture) {
+ const architecturePath = external_path_default().join(jdkPath, architecture);
+ try {
+ const marker = external_fs_default().statSync(`${architecturePath}.complete`);
+ const installation = external_fs_default().statSync(architecturePath);
+ return [
+ marker.ino,
+ marker.mtimeMs,
+ marker.ctimeMs,
+ marker.size,
+ installation.ino,
+ installation.mtimeMs,
+ installation.ctimeMs
+ ].join(':');
+ }
+ catch {
+ return undefined;
+ }
+}
+function getJdkVerificationIdentity(verifySignature, publicKey) {
+ if (!verifySignature) {
+ return 'unverified';
+ }
+ if (!publicKey) {
+ return 'verified:bundled';
+ }
+ const normalizedKey = publicKey.replace(/\r\n?/g, '\n').trim();
+ const fingerprint = createHash('sha256').update(normalizedKey).digest('hex');
+ return `verified:custom:sha256:${fingerprint}`;
+}
+async function saveJdkCaches() {
+ const state = lib_core/* getState */.Gu(STATE_JDK_CACHES);
+ if (!state) {
+ return;
+ }
+ const caches = parseJdkCacheState(state);
+ for (const jdk of caches) {
+ if (jdk.matchedKey === jdk.key) {
+ lib_core/* info */.pq(`Cache hit occurred on the JDK primary key ${jdk.key}, not saving cache.`);
+ continue;
+ }
+ if (!external_fs_default().existsSync(jdk.path)) {
+ lib_core/* debug */.Yz(`JDK cache path does not exist, not saving: ${jdk.path}`);
+ continue;
+ }
+ if (!jdk.installation) {
+ lib_core/* debug */.Yz(`No JDK installation was registered for the key ${jdk.key}, not saving cache.`);
+ continue;
+ }
+ if (getInstallationIdentity(jdk.path, jdk.architecture) !== jdk.installation) {
+ lib_core/* warning */.$e(`The JDK installation in ${jdk.path} was replaced after it was registered for the key ${jdk.key}; not saving cache.`);
+ continue;
+ }
+ try {
+ const cacheId = await lib_cache/* saveCache */.Io([jdk.path], jdk.key);
+ if (cacheId !== -1) {
+ lib_core/* info */.pq(`JDK cache saved with the key: ${jdk.key}`);
+ }
+ }
+ catch (error) {
+ const err = error;
+ if (err.name === lib_cache/* ReserveCacheError */.Zh.name) {
+ lib_core/* info */.pq(err.message);
+ }
+ else {
+ // Saving is best-effort and per entry: one failure must not suppress
+ // the remaining JDK caches.
+ lib_core/* warning */.$e(`Failed to save the JDK cache with the key ${jdk.key}: ${err.message}`);
+ }
+ }
+ }
+}
+function buildJdkCacheKey(jdk) {
+ const runnerOs = process.env['RUNNER_OS'] ?? process.platform;
+ const normalizedArchitecture = jdk.architecture.toLowerCase();
+ const identity = JSON.stringify({
+ keyVersion: JDK_CACHE_KEY_VERSION,
+ runnerOs,
+ distribution: jdk.distribution.toLowerCase(),
+ packageType: jdk.packageType.toLowerCase(),
+ architecture: normalizedArchitecture,
+ version: jdk.version,
+ source: jdk.source,
+ verification: jdk.verification
+ });
+ const digest = createHash('sha256').update(identity).digest('hex');
+ return `setup-java-jdk-v${JDK_CACHE_KEY_VERSION}-${runnerOs}-${normalizedArchitecture}-${digest}`;
+}
+function recordJdkCache(jdk) {
+ const existing = restoredCaches.findIndex(item => item.key === jdk.key && item.path === jdk.path);
+ if (existing === -1) {
+ restoredCaches.push(jdk);
+ }
+ else {
+ restoredCaches[existing] = { ...restoredCaches[existing], ...jdk };
+ }
+ core.saveState(STATE_JDK_CACHES, JSON.stringify(restoredCaches));
+}
+function parseJdkCacheState(state) {
+ const value = JSON.parse(state);
+ if (!Array.isArray(value) ||
+ !value.every(item => typeof item === 'object' &&
+ item !== null &&
+ typeof item.key === 'string' &&
+ typeof item.path === 'string' &&
+ typeof item.architecture === 'string' &&
+ (item.matchedKey === undefined ||
+ typeof item.matchedKey === 'string') &&
+ (item.installation === undefined ||
+ typeof item.installation === 'string'))) {
+ throw new Error('Invalid JDK cache information retrieved from state.');
+ }
+ return value;
+}
+
+
+/***/ })
+
+};
diff --git a/dist/cleanup/348.index.js b/dist/cleanup/348.index.js
new file mode 100644
index 000000000..d178a94bb
--- /dev/null
+++ b/dist/cleanup/348.index.js
@@ -0,0 +1,279 @@
+export const id = 348;
+export const ids = [348];
+export const modules = {
+
+/***/ 967:
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ saveJdkResolutionCaches: () => (/* binding */ saveJdkResolutionCaches)
+/* harmony export */ });
+/* unused harmony exports restoreJdkResolution, registerJdkResolution */
+/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6982);
+/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9896);
+/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6928);
+/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _actions_cache__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5767);
+/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3838);
+
+
+
+
+
+const STATE_JDK_RESOLUTIONS = 'jdk-resolutions';
+const JDK_RESOLUTION_KEY_VERSION = 2;
+const RESOLUTION_DIRECTORY = 'setup-java-jdk-resolution';
+const RESOLUTION_FILE_NAME = 'release.json';
+const pendingResolutions = (/* unused pure expression or super */ null && ([]));
+/**
+ * Restores a previously resolved release so a distribution can skip its vendor
+ * metadata API.
+ *
+ * The cache path deliberately excludes the freshness window: `@actions/cache`
+ * derives
+ * a cache version by hashing the requested paths, so a bucket-independent path
+ * is what allows the restore keys to fall back to an older bucket.
+ */
+async function restoreJdkResolution(request) {
+ // Deliberately not `isCacheFeatureAvailable()`: this is an optional
+ // optimization, and the JDK cache already warns once when the service is
+ // unreachable.
+ if (!cache.isFeatureAvailable()) {
+ return undefined;
+ }
+ const cachePath = getResolutionCachePath(request);
+ if (!cachePath) {
+ return undefined;
+ }
+ const keyPrefix = getResolutionKeyPrefix(request);
+ const primaryKey = `${keyPrefix}${getFreshnessBucket()}`;
+ let matchedKey;
+ try {
+ matchedKey = await cache.restoreCache([cachePath], primaryKey, [keyPrefix]);
+ }
+ catch (error) {
+ core.debug(`Failed to restore the JDK resolution cache: ${getErrorMessage(error)}`);
+ return undefined;
+ }
+ if (!matchedKey) {
+ return undefined;
+ }
+ let release;
+ try {
+ const contents = fs.readFileSync(path.join(cachePath, RESOLUTION_FILE_NAME), 'utf8');
+ release = parseResolvedRelease(contents);
+ }
+ catch (error) {
+ core.debug(`Ignoring the JDK resolution cache entry ${matchedKey}: ${getErrorMessage(error)}`);
+ return undefined;
+ }
+ return { release, fresh: matchedKey === primaryKey };
+}
+/**
+ * Persists a freshly resolved release for later jobs. The entry is written to
+ * disk immediately and uploaded by the post-job step.
+ */
+function registerJdkResolution(request, release) {
+ if (!cache.isFeatureAvailable()) {
+ return;
+ }
+ const cachePath = getResolutionCachePath(request);
+ if (!cachePath) {
+ return;
+ }
+ const payload = JSON.stringify(release);
+ try {
+ fs.mkdirSync(cachePath, { recursive: true });
+ fs.writeFileSync(path.join(cachePath, RESOLUTION_FILE_NAME), payload);
+ }
+ catch (error) {
+ core.debug(`Failed to record the JDK resolution cache entry: ${getErrorMessage(error)}`);
+ return;
+ }
+ const key = `${getResolutionKeyPrefix(request)}${getFreshnessBucket()}`;
+ if (!pendingResolutions.some(item => item.key === key)) {
+ pendingResolutions.push({ key, path: cachePath, release: payload });
+ }
+ core.saveState(STATE_JDK_RESOLUTIONS, JSON.stringify(pendingResolutions));
+}
+async function saveJdkResolutionCaches() {
+ const state = _actions_core__WEBPACK_IMPORTED_MODULE_4__/* .getState */ .Gu(STATE_JDK_RESOLUTIONS);
+ if (!state) {
+ return;
+ }
+ let resolutions;
+ try {
+ resolutions = parseJdkResolutionState(state);
+ }
+ catch (error) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_4__/* .debug */ .Yz(`Invalid JDK resolution cache state, not saving: ${getErrorMessage(error)}`);
+ return;
+ }
+ for (const resolution of resolutions) {
+ // A restore performed by a later step overwrites this path, so the payload
+ // the key was computed for is written again rather than trusted to still be
+ // on disk.
+ try {
+ fs__WEBPACK_IMPORTED_MODULE_1___default().mkdirSync(resolution.path, { recursive: true });
+ fs__WEBPACK_IMPORTED_MODULE_1___default().writeFileSync(path__WEBPACK_IMPORTED_MODULE_2___default().join(resolution.path, RESOLUTION_FILE_NAME), resolution.release);
+ }
+ catch (error) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_4__/* .debug */ .Yz(`Failed to write the JDK resolution cache entry for the key ${resolution.key}: ${getErrorMessage(error)}`);
+ continue;
+ }
+ try {
+ await _actions_cache__WEBPACK_IMPORTED_MODULE_3__/* .saveCache */ .Io([resolution.path], resolution.key);
+ }
+ catch (error) {
+ // A matrix of jobs resolving the same JDK races on the same daily key, so
+ // an already-reserved key is the expected outcome rather than a problem.
+ _actions_core__WEBPACK_IMPORTED_MODULE_4__/* .debug */ .Yz(`Failed to save the JDK resolution cache with the key ${resolution.key}: ${getErrorMessage(error)}`);
+ }
+ }
+}
+function getResolutionCachePath(request) {
+ const runnerTemp = process.env['RUNNER_TEMP'];
+ if (!runnerTemp) {
+ return undefined;
+ }
+ return path.join(runnerTemp, RESOLUTION_DIRECTORY, getResolutionIdentity(request));
+}
+function getResolutionIdentity(request) {
+ const identity = JSON.stringify({
+ keyVersion: JDK_RESOLUTION_KEY_VERSION,
+ runnerOs: getRunnerOs(),
+ distribution: request.distribution.toLowerCase(),
+ packageType: request.packageType.toLowerCase(),
+ platform: request.platform.toLowerCase(),
+ architecture: request.architecture.toLowerCase(),
+ versionSpec: request.versionSpec,
+ stable: request.stable,
+ source: request.source
+ });
+ return createHash('sha256').update(identity).digest('hex');
+}
+function getResolutionKeyPrefix(request) {
+ const architecture = request.architecture.toLowerCase();
+ const digest = getResolutionIdentity(request);
+ return `setup-java-jdkres-v${JDK_RESOLUTION_KEY_VERSION}-${getRunnerOs()}-${architecture}-${digest}-`;
+}
+function getRunnerOs() {
+ return process.env['RUNNER_OS'] ?? process.platform;
+}
+/**
+ * Start of the seven-day window the entry was resolved in, which bounds how long
+ * a floating version spec such as `21` can keep resolving to an already known
+ * release.
+ *
+ * Seven days is the longest usable window: GitHub evicts cache entries that have
+ * not been accessed for seven days, so a longer one would mean the previous
+ * entry is already gone when the window rolls over, taking the stale-fallback
+ * path with it. It also comfortably covers the real release cadence, which is
+ * monthly at its fastest and usually quarterly.
+ */
+function getFreshnessBucket() {
+ const week = 7 * 24 * 60 * 60 * 1000;
+ return new Date(Math.floor(Date.now() / week) * week)
+ .toISOString()
+ .slice(0, 10);
+}
+/**
+ * The restored payload drives a download, so it is validated as untrusted input
+ * rather than trusted because it came back from the cache service.
+ */
+function parseResolvedRelease(contents) {
+ const value = JSON.parse(contents);
+ if (typeof value !== 'object' || value === null) {
+ throw new Error('The cached resolution is not an object.');
+ }
+ const candidate = value;
+ const version = candidate['version'];
+ const url = candidate['url'];
+ const signatureUrl = candidate['signatureUrl'];
+ const floating = candidate['floating'];
+ if (typeof version !== 'string' || !version) {
+ throw new Error('The cached resolution has no version.');
+ }
+ assertHttpsUrl(url, 'url');
+ if (signatureUrl !== undefined) {
+ assertHttpsUrl(signatureUrl, 'signatureUrl');
+ }
+ if (floating !== undefined && typeof floating !== 'boolean') {
+ throw new Error('The cached resolution has an invalid floating flag.');
+ }
+ const release = {
+ version,
+ url: url
+ };
+ if (signatureUrl !== undefined) {
+ release.signatureUrl = signatureUrl;
+ }
+ if (floating !== undefined) {
+ release.floating = floating;
+ }
+ const checksum = candidate['checksum'];
+ if (checksum !== undefined) {
+ release.checksum = parseChecksum(checksum);
+ }
+ return release;
+}
+function parseChecksum(value) {
+ if (typeof value !== 'object' || value === null) {
+ throw new Error('The cached checksum is not an object.');
+ }
+ const candidate = value;
+ const algorithm = candidate['algorithm'];
+ const checksumValue = candidate['value'];
+ const source = candidate['source'];
+ if (algorithm !== 'sha256' && algorithm !== 'sha512') {
+ throw new Error(`Unsupported cached checksum algorithm: ${algorithm}`);
+ }
+ if (typeof checksumValue !== 'string' || !checksumValue) {
+ throw new Error('The cached checksum has no value.');
+ }
+ if (source !== undefined && typeof source !== 'string') {
+ throw new Error('The cached checksum source is not a string.');
+ }
+ const checksum = { algorithm, value: checksumValue };
+ if (source !== undefined) {
+ checksum.source = source;
+ }
+ return checksum;
+}
+function assertHttpsUrl(value, field) {
+ if (typeof value !== 'string' || !value) {
+ throw new Error(`The cached resolution has no ${field}.`);
+ }
+ let parsed;
+ try {
+ parsed = new URL(value);
+ }
+ catch {
+ throw new Error(`The cached resolution has a malformed ${field}.`);
+ }
+ if (parsed.protocol !== 'https:') {
+ throw new Error(`The cached resolution ${field} does not use HTTPS: ${parsed.protocol}`);
+ }
+}
+function parseJdkResolutionState(state) {
+ const value = JSON.parse(state);
+ if (!Array.isArray(value) ||
+ !value.every(item => typeof item === 'object' &&
+ item !== null &&
+ typeof item.key === 'string' &&
+ typeof item.path === 'string' &&
+ typeof item.release === 'string')) {
+ throw new Error('Invalid JDK resolution information retrieved from state.');
+ }
+ return value;
+}
+function getErrorMessage(error) {
+ return error instanceof Error ? error.message : String(error);
+}
+
+
+/***/ })
+
+};
diff --git a/dist/cleanup/377.index.js b/dist/cleanup/377.index.js
new file mode 100644
index 000000000..66c5d2a5f
--- /dev/null
+++ b/dist/cleanup/377.index.js
@@ -0,0 +1,360 @@
+export const id = 377;
+export const ids = [377];
+export const modules = {
+
+/***/ 7377:
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ save: () => (/* binding */ save)
+/* harmony export */ });
+/* unused harmony exports validatePackageManager, restore */
+/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6928);
+/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(857);
+/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(os__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _actions_cache__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5767);
+/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3838);
+/* harmony import */ var _actions_glob__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(2377);
+/**
+ * @fileoverview this file provides methods handling dependency cache
+ */
+
+
+
+
+
+const STATE_CACHE_PRIMARY_KEY = 'cache-primary-key';
+const STATE_CACHE_PATHS = 'cache-paths';
+const CACHE_MATCHED_KEY = 'cache-matched-key';
+const CACHE_KEY_PREFIX = 'setup-java';
+const supportedPackageManager = [
+ {
+ id: 'maven',
+ path: [(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.m2', 'repository')],
+ // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
+ pattern: [
+ '**/pom.xml',
+ '**/.mvn/wrapper/maven-wrapper.properties',
+ '**/.mvn/extensions.xml'
+ ],
+ // The Maven wrapper distribution only depends on the wrapper properties,
+ // which change very rarely, so it is cached separately from the local
+ // repository. This keeps it available across the frequent pom.xml changes
+ // that rotate the main cache key. See issue #1095.
+ additionalCaches: [
+ {
+ name: 'maven-wrapper',
+ path: [(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.m2', 'wrapper', 'dists')],
+ pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
+ }
+ ]
+ },
+ {
+ id: 'gradle',
+ path: [(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.gradle', 'caches')],
+ // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
+ pattern: [
+ '**/*.gradle*',
+ '**/gradle.properties',
+ '**/gradle-wrapper.properties',
+ 'buildSrc/**/Versions.kt',
+ 'buildSrc/**/Dependencies.kt',
+ 'gradle/*.versions.toml',
+ '**/versions.properties'
+ ],
+ // The Gradle wrapper distribution only depends on the wrapper properties,
+ // which change very rarely, so it is cached separately from the Gradle
+ // caches. This keeps it available across the frequent *.gradle* changes
+ // that rotate the main cache key. See issue #269.
+ additionalCaches: [
+ {
+ name: 'gradle-wrapper',
+ path: [(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.gradle', 'wrapper')],
+ pattern: ['**/gradle-wrapper.properties']
+ }
+ ]
+ },
+ {
+ id: 'sbt',
+ path: [
+ (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.ivy2', 'cache'),
+ (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.sbt'),
+ getCoursierCachePath(),
+ // Some files should not be cached to avoid resolution problems.
+ // In particular the resolution of snapshots (ideological gap between maven/ivy).
+ '!' + (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.sbt', '*.lock'),
+ '!' + (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '**', 'ivydata-*.properties')
+ ],
+ pattern: [
+ '**/*.sbt',
+ '**/project/build.properties',
+ '**/project/**.scala',
+ '**/project/**.sbt'
+ ]
+ }
+];
+function getCoursierCachePath() {
+ if (os__WEBPACK_IMPORTED_MODULE_1___default().type() === 'Linux')
+ return (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.cache', 'coursier');
+ if (os__WEBPACK_IMPORTED_MODULE_1___default().type() === 'Darwin')
+ return (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), 'Library', 'Caches', 'Coursier');
+ return (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), 'AppData', 'Local', 'Coursier', 'Cache');
+}
+function findPackageManager(id) {
+ const packageManager = supportedPackageManager.find(packageManager => packageManager.id === id);
+ if (packageManager === undefined) {
+ throw new Error(`unknown package manager specified: ${id}`);
+ }
+ return packageManager;
+}
+function validatePackageManager(id) {
+ findPackageManager(id);
+}
+function resolveCachePaths(packageManager, cachePaths) {
+ return cachePaths.length > 0 ? cachePaths : packageManager.path;
+}
+function getCachePathsFromState(packageManager) {
+ const cachePathsState = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(STATE_CACHE_PATHS);
+ if (!cachePathsState) {
+ return packageManager.path;
+ }
+ const cachePaths = JSON.parse(cachePathsState);
+ if (!Array.isArray(cachePaths) ||
+ !cachePaths.every(cachePath => typeof cachePath === 'string')) {
+ throw new Error('Invalid cache paths retrieved from state.');
+ }
+ return cachePaths;
+}
+/**
+ * State keys used to carry an additional cache's restore-time information over
+ * to the post (save) action, scoped by the additional cache name.
+ */
+function additionalCachePrimaryKeyState(name) {
+ return `${STATE_CACHE_PRIMARY_KEY}-${name}`;
+}
+function additionalCacheMatchedKeyState(name) {
+ return `${CACHE_MATCHED_KEY}-${name}`;
+}
+function buildCacheKey(id, fileHash) {
+ return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`;
+}
+/**
+ * A function that generates a cache key to use.
+ * Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
+ * @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key}
+ */
+async function computeCacheKey(packageManager, cacheDependencyPath) {
+ const pattern = cacheDependencyPath
+ ? cacheDependencyPath.trim().split('\n')
+ : packageManager.pattern;
+ const fileHash = await glob.hashFiles(pattern.join('\n'));
+ if (!fileHash) {
+ throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
+ }
+ return buildCacheKey(packageManager.id, fileHash);
+}
+/**
+ * Computes the cache key for an additional cache. Unlike {@link computeCacheKey}
+ * this returns undefined (instead of throwing) when no file matches the pattern,
+ * because additional caches are optional features that many projects do not use.
+ */
+async function computeAdditionalCacheKey(additionalCache) {
+ const fileHash = await glob.hashFiles(additionalCache.pattern.join('\n'));
+ if (!fileHash) {
+ return undefined;
+ }
+ return buildCacheKey(additionalCache.name, fileHash);
+}
+/**
+ * Restore the dependency cache
+ * @param id ID of the package manager, should be "maven", "gradle", or "sbt"
+ * @param cacheDependencyPath The path to a dependency file
+ * @param cachePaths Paths to cache instead of the package manager defaults
+ */
+async function restore(id, cacheDependencyPath, cachePaths = []) {
+ const packageManager = findPackageManager(id);
+ const resolvedCachePaths = resolveCachePaths(packageManager, cachePaths);
+ const [primaryKey, preparedAdditionalCaches] = await Promise.all([
+ computeCacheKey(packageManager, cacheDependencyPath),
+ prepareAdditionalCaches(packageManager.additionalCaches ?? [])
+ ]);
+ core.debug(`primary key is ${primaryKey}`);
+ core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey);
+ core.saveState(STATE_CACHE_PATHS, JSON.stringify(resolvedCachePaths));
+ core.setOutput(STATE_CACHE_PRIMARY_KEY, primaryKey);
+ for (const preparedCache of preparedAdditionalCaches) {
+ core.debug(`${preparedCache.cache.name} primary key is ${preparedCache.primaryKey}`);
+ core.saveState(additionalCachePrimaryKeyState(preparedCache.cache.name), preparedCache.primaryKey);
+ }
+ await Promise.all([
+ restorePrimaryCache(packageManager, resolvedCachePaths, primaryKey),
+ ...preparedAdditionalCaches.map(preparedCache => restoreAdditionalCache(preparedCache))
+ ]);
+}
+async function restorePrimaryCache(packageManager, cachePaths, primaryKey) {
+ // No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269)
+ const matchedKey = await cache.restoreCache(cachePaths, primaryKey);
+ if (matchedKey) {
+ core.saveState(CACHE_MATCHED_KEY, matchedKey);
+ core.setOutput('cache-hit', matchedKey === primaryKey);
+ core.info(`Cache restored from key: ${matchedKey}`);
+ }
+ else {
+ core.setOutput('cache-hit', false);
+ core.info(`${packageManager.id} cache is not found`);
+ }
+}
+/**
+ * Compute keys for additional caches (e.g. build-tool wrapper distributions).
+ * Additional caches without a matching configuration file are omitted.
+ */
+async function prepareAdditionalCaches(additionalCaches) {
+ const preparedCaches = await Promise.all(additionalCaches.map(async (additionalCache) => {
+ const primaryKey = await computeAdditionalCacheKey(additionalCache);
+ if (!primaryKey) {
+ core.debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`);
+ return undefined;
+ }
+ return { cache: additionalCache, primaryKey };
+ }));
+ return preparedCaches.filter((preparedCache) => preparedCache !== undefined);
+}
+/**
+ * Restore an additional cache keyed independently of the main dependency cache.
+ */
+async function restoreAdditionalCache(preparedCache) {
+ const { cache: additionalCache, primaryKey } = preparedCache;
+ const matchedKey = await cache.restoreCache(additionalCache.path, primaryKey);
+ if (matchedKey) {
+ core.saveState(additionalCacheMatchedKeyState(additionalCache.name), matchedKey);
+ core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`);
+ }
+ else {
+ core.info(`${additionalCache.name} cache is not found`);
+ }
+}
+/**
+ * Save the dependency cache
+ * @param id ID of the package manager, should be "maven" or "gradle"
+ */
+async function save(id) {
+ const packageManager = findPackageManager(id);
+ const cachePaths = getCachePathsFromState(packageManager);
+ const matchedKey = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(CACHE_MATCHED_KEY);
+ // Inputs are re-evaluated before the post action, so we want the original key used for restore
+ const primaryKey = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(STATE_CACHE_PRIMARY_KEY);
+ for (const additionalCache of packageManager.additionalCaches ?? []) {
+ try {
+ await saveAdditionalCache(packageManager, additionalCache);
+ }
+ catch (error) {
+ const err = error;
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e(`Failed to save ${additionalCache.name} cache: ${err.message}. Continuing with primary cache save.`);
+ }
+ }
+ if (!primaryKey) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e('Error retrieving key from state.');
+ return;
+ }
+ else if (matchedKey === primaryKey) {
+ // no change in target directories
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
+ return;
+ }
+ try {
+ const cacheId = await _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .saveCache */ .Io(cachePaths, primaryKey);
+ if (cacheId === -1) {
+ // saveCache returns -1 without throwing when the cache was not saved,
+ // e.g. a reserve collision or a read-only token (fork PR). @actions/cache
+ // has already logged the reason at the appropriate severity, so just
+ // trace it instead of misreporting that the cache was saved.
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`Cache was not saved for the key: ${primaryKey}`);
+ return;
+ }
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`Cache saved with the key: ${primaryKey}`);
+ }
+ catch (error) {
+ const err = error;
+ if (err.name === _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .ReserveCacheError */ .Zh.name) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(err.message);
+ }
+ else {
+ if (isProbablyGradleDaemonProblem(packageManager, err)) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e('Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.');
+ }
+ throw error;
+ }
+ }
+}
+/**
+ * Save an additional cache under its own key. Skips when no key was recorded at
+ * restore time (feature unused) or when the exact key was already restored.
+ */
+async function saveAdditionalCache(packageManager, additionalCache) {
+ const primaryKey = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(additionalCachePrimaryKeyState(additionalCache.name));
+ const matchedKey = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(additionalCacheMatchedKeyState(additionalCache.name));
+ if (!primaryKey) {
+ // The feature is not used by this project, nothing to save.
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`No primary key for the ${additionalCache.name} cache, not saving cache.`);
+ return;
+ }
+ else if (matchedKey === primaryKey) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`);
+ return;
+ }
+ const globber = await _actions_glob__WEBPACK_IMPORTED_MODULE_4__/* .create */ .v(additionalCache.path.join('\n'), {
+ implicitDescendants: false
+ });
+ const cachePaths = await globber.glob();
+ if (cachePaths.length === 0) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`${additionalCache.name} cache paths do not exist, not saving cache.`);
+ return;
+ }
+ try {
+ const cacheId = await _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .saveCache */ .Io(cachePaths, primaryKey);
+ if (cacheId === -1) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`);
+ return;
+ }
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`${additionalCache.name} cache saved with the key: ${primaryKey}`);
+ }
+ catch (error) {
+ const err = error;
+ if (err.name === _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .ValidationError */ .yI.name) {
+ // The cache paths did not resolve, e.g. the wrapper distribution was
+ // never downloaded because a system build tool was used or the download
+ // failed. Optional wrapper caches must not fail the post step, so skip.
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`);
+ return;
+ }
+ if (err.name === _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .ReserveCacheError */ .Zh.name) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(err.message);
+ }
+ else {
+ if (isProbablyGradleDaemonProblem(packageManager, err)) {
+ _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e(`Failed to save ${additionalCache.name} cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with \`--no-daemon\` option. Refer to https://github.com/actions/cache/issues/454 for details.`);
+ }
+ throw error;
+ }
+ }
+}
+/**
+ * @param packageManager the specified package manager by user
+ * @param error the error thrown by the saveCache
+ * @returns true if the given error seems related to the {@link https://github.com/actions/cache/issues/454|running Gradle Daemon issue}.
+ * @see {@link https://github.com/actions/cache/issues/454#issuecomment-840493935|why --no-daemon is necessary}
+ */
+function isProbablyGradleDaemonProblem(packageManager, error) {
+ if (packageManager.id !== 'gradle' ||
+ process.env['RUNNER_OS'] !== 'Windows') {
+ return false;
+ }
+ const message = error.message || '';
+ return message.startsWith('Tar failed with error: ');
+}
+
+
+/***/ })
+
+};
diff --git a/dist/cleanup/767.index.js b/dist/cleanup/767.index.js
new file mode 100644
index 000000000..b73e9e9fa
--- /dev/null
+++ b/dist/cleanup/767.index.js
@@ -0,0 +1,62560 @@
+export const id = 767;
+export const ids = [767];
+export const modules = {
+
+/***/ 7889:
+/***/ (function(__unused_webpack_module, exports) {
+
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ClientStreamingCall = void 0;
+/**
+ * A client streaming RPC call. This means that the clients sends 0, 1, or
+ * more messages to the server, and the server replies with exactly one
+ * message.
+ */
+class ClientStreamingCall {
+ constructor(method, requestHeaders, request, headers, response, status, trailers) {
+ this.method = method;
+ this.requestHeaders = requestHeaders;
+ this.requests = request;
+ this.headers = headers;
+ this.response = response;
+ this.status = status;
+ this.trailers = trailers;
+ }
+ /**
+ * Instead of awaiting the response status and trailers, you can
+ * just as well await this call itself to receive the server outcome.
+ * Note that it may still be valid to send more request messages.
+ */
+ then(onfulfilled, onrejected) {
+ return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
+ }
+ promiseFinished() {
+ return __awaiter(this, void 0, void 0, function* () {
+ let [headers, response, status, trailers] = yield Promise.all([this.headers, this.response, this.status, this.trailers]);
+ return {
+ method: this.method,
+ requestHeaders: this.requestHeaders,
+ headers,
+ response,
+ status,
+ trailers
+ };
+ });
+ }
+}
+exports.ClientStreamingCall = ClientStreamingCall;
+
+
+/***/ }),
+
+/***/ 1409:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.Deferred = exports.DeferredState = void 0;
+var DeferredState;
+(function (DeferredState) {
+ DeferredState[DeferredState["PENDING"] = 0] = "PENDING";
+ DeferredState[DeferredState["REJECTED"] = 1] = "REJECTED";
+ DeferredState[DeferredState["RESOLVED"] = 2] = "RESOLVED";
+})(DeferredState = exports.DeferredState || (exports.DeferredState = {}));
+/**
+ * A deferred promise. This is a "controller" for a promise, which lets you
+ * pass a promise around and reject or resolve it from the outside.
+ *
+ * Warning: This class is to be used with care. Using it can make code very
+ * difficult to read. It is intended for use in library code that exposes
+ * promises, not for regular business logic.
+ */
+class Deferred {
+ /**
+ * @param preventUnhandledRejectionWarning - prevents the warning
+ * "Unhandled Promise rejection" by adding a noop rejection handler.
+ * Working with calls returned from the runtime-rpc package in an
+ * async function usually means awaiting one call property after
+ * the other. This means that the "status" is not being awaited when
+ * an earlier await for the "headers" is rejected. This causes the
+ * "unhandled promise reject" warning. A more correct behaviour for
+ * calls might be to become aware whether at least one of the
+ * promises is handled and swallow the rejection warning for the
+ * others.
+ */
+ constructor(preventUnhandledRejectionWarning = true) {
+ this._state = DeferredState.PENDING;
+ this._promise = new Promise((resolve, reject) => {
+ this._resolve = resolve;
+ this._reject = reject;
+ });
+ if (preventUnhandledRejectionWarning) {
+ this._promise.catch(_ => { });
+ }
+ }
+ /**
+ * Get the current state of the promise.
+ */
+ get state() {
+ return this._state;
+ }
+ /**
+ * Get the deferred promise.
+ */
+ get promise() {
+ return this._promise;
+ }
+ /**
+ * Resolve the promise. Throws if the promise is already resolved or rejected.
+ */
+ resolve(value) {
+ if (this.state !== DeferredState.PENDING)
+ throw new Error(`cannot resolve ${DeferredState[this.state].toLowerCase()}`);
+ this._resolve(value);
+ this._state = DeferredState.RESOLVED;
+ }
+ /**
+ * Reject the promise. Throws if the promise is already resolved or rejected.
+ */
+ reject(reason) {
+ if (this.state !== DeferredState.PENDING)
+ throw new Error(`cannot reject ${DeferredState[this.state].toLowerCase()}`);
+ this._reject(reason);
+ this._state = DeferredState.REJECTED;
+ }
+ /**
+ * Resolve the promise. Ignore if not pending.
+ */
+ resolvePending(val) {
+ if (this._state === DeferredState.PENDING)
+ this.resolve(val);
+ }
+ /**
+ * Reject the promise. Ignore if not pending.
+ */
+ rejectPending(reason) {
+ if (this._state === DeferredState.PENDING)
+ this.reject(reason);
+ }
+}
+exports.Deferred = Deferred;
+
+
+/***/ }),
+
+/***/ 6826:
+/***/ (function(__unused_webpack_module, exports) {
+
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.DuplexStreamingCall = void 0;
+/**
+ * A duplex streaming RPC call. This means that the clients sends an
+ * arbitrary amount of messages to the server, while at the same time,
+ * the server sends an arbitrary amount of messages to the client.
+ */
+class DuplexStreamingCall {
+ constructor(method, requestHeaders, request, headers, response, status, trailers) {
+ this.method = method;
+ this.requestHeaders = requestHeaders;
+ this.requests = request;
+ this.headers = headers;
+ this.responses = response;
+ this.status = status;
+ this.trailers = trailers;
+ }
+ /**
+ * Instead of awaiting the response status and trailers, you can
+ * just as well await this call itself to receive the server outcome.
+ * Note that it may still be valid to send more request messages.
+ */
+ then(onfulfilled, onrejected) {
+ return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
+ }
+ promiseFinished() {
+ return __awaiter(this, void 0, void 0, function* () {
+ let [headers, status, trailers] = yield Promise.all([this.headers, this.status, this.trailers]);
+ return {
+ method: this.method,
+ requestHeaders: this.requestHeaders,
+ headers,
+ status,
+ trailers,
+ };
+ });
+ }
+}
+exports.DuplexStreamingCall = DuplexStreamingCall;
+
+
+/***/ }),
+
+/***/ 4420:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+var __webpack_unused_export__;
+
+// Public API of the rpc runtime.
+// Note: we do not use `export * from ...` to help tree shakers,
+// webpack verbose output hints that this should be useful
+__webpack_unused_export__ = ({ value: true });
+var service_type_1 = __webpack_require__(6892);
+Object.defineProperty(exports, "C0", ({ enumerable: true, get: function () { return service_type_1.ServiceType; } }));
+var reflection_info_1 = __webpack_require__(2496);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return reflection_info_1.readMethodOptions; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return reflection_info_1.readMethodOption; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return reflection_info_1.readServiceOption; } });
+var rpc_error_1 = __webpack_require__(8636);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_error_1.RpcError; } });
+var rpc_options_1 = __webpack_require__(8576);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_options_1.mergeRpcOptions; } });
+var rpc_output_stream_1 = __webpack_require__(2726);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_output_stream_1.RpcOutputStreamController; } });
+var test_transport_1 = __webpack_require__(9122);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return test_transport_1.TestTransport; } });
+var deferred_1 = __webpack_require__(1409);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return deferred_1.Deferred; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return deferred_1.DeferredState; } });
+var duplex_streaming_call_1 = __webpack_require__(6826);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return duplex_streaming_call_1.DuplexStreamingCall; } });
+var client_streaming_call_1 = __webpack_require__(7889);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return client_streaming_call_1.ClientStreamingCall; } });
+var server_streaming_call_1 = __webpack_require__(6173);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return server_streaming_call_1.ServerStreamingCall; } });
+var unary_call_1 = __webpack_require__(9288);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return unary_call_1.UnaryCall; } });
+var rpc_interceptor_1 = __webpack_require__(2849);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_interceptor_1.stackIntercept; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_interceptor_1.stackDuplexStreamingInterceptors; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_interceptor_1.stackClientStreamingInterceptors; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_interceptor_1.stackServerStreamingInterceptors; } });
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return rpc_interceptor_1.stackUnaryInterceptors; } });
+var server_call_context_1 = __webpack_require__(3352);
+__webpack_unused_export__ = ({ enumerable: true, get: function () { return server_call_context_1.ServerCallContextController; } });
+
+
+/***/ }),
+
+/***/ 2496:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.readServiceOption = exports.readMethodOption = exports.readMethodOptions = exports.normalizeMethodInfo = void 0;
+const runtime_1 = __webpack_require__(8886);
+/**
+ * Turns PartialMethodInfo into MethodInfo.
+ */
+function normalizeMethodInfo(method, service) {
+ var _a, _b, _c;
+ let m = method;
+ m.service = service;
+ m.localName = (_a = m.localName) !== null && _a !== void 0 ? _a : runtime_1.lowerCamelCase(m.name);
+ // noinspection PointlessBooleanExpressionJS
+ m.serverStreaming = !!m.serverStreaming;
+ // noinspection PointlessBooleanExpressionJS
+ m.clientStreaming = !!m.clientStreaming;
+ m.options = (_b = m.options) !== null && _b !== void 0 ? _b : {};
+ m.idempotency = (_c = m.idempotency) !== null && _c !== void 0 ? _c : undefined;
+ return m;
+}
+exports.normalizeMethodInfo = normalizeMethodInfo;
+/**
+ * Read custom method options from a generated service client.
+ *
+ * @deprecated use readMethodOption()
+ */
+function readMethodOptions(service, methodName, extensionName, extensionType) {
+ var _a;
+ const options = (_a = service.methods.find((m, i) => m.localName === methodName || i === methodName)) === null || _a === void 0 ? void 0 : _a.options;
+ return options && options[extensionName] ? extensionType.fromJson(options[extensionName]) : undefined;
+}
+exports.readMethodOptions = readMethodOptions;
+function readMethodOption(service, methodName, extensionName, extensionType) {
+ var _a;
+ const options = (_a = service.methods.find((m, i) => m.localName === methodName || i === methodName)) === null || _a === void 0 ? void 0 : _a.options;
+ if (!options) {
+ return undefined;
+ }
+ const optionVal = options[extensionName];
+ if (optionVal === undefined) {
+ return optionVal;
+ }
+ return extensionType ? extensionType.fromJson(optionVal) : optionVal;
+}
+exports.readMethodOption = readMethodOption;
+function readServiceOption(service, extensionName, extensionType) {
+ const options = service.options;
+ if (!options) {
+ return undefined;
+ }
+ const optionVal = options[extensionName];
+ if (optionVal === undefined) {
+ return optionVal;
+ }
+ return extensionType ? extensionType.fromJson(optionVal) : optionVal;
+}
+exports.readServiceOption = readServiceOption;
+
+
+/***/ }),
+
+/***/ 8636:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.RpcError = void 0;
+/**
+ * An error that occurred while calling a RPC method.
+ */
+class RpcError extends Error {
+ constructor(message, code = 'UNKNOWN', meta) {
+ super(message);
+ this.name = 'RpcError';
+ // see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#example
+ Object.setPrototypeOf(this, new.target.prototype);
+ this.code = code;
+ this.meta = meta !== null && meta !== void 0 ? meta : {};
+ }
+ toString() {
+ const l = [this.name + ': ' + this.message];
+ if (this.code) {
+ l.push('');
+ l.push('Code: ' + this.code);
+ }
+ if (this.serviceName && this.methodName) {
+ l.push('Method: ' + this.serviceName + '/' + this.methodName);
+ }
+ let m = Object.entries(this.meta);
+ if (m.length) {
+ l.push('');
+ l.push('Meta:');
+ for (let [k, v] of m) {
+ l.push(` ${k}: ${v}`);
+ }
+ }
+ return l.join('\n');
+ }
+}
+exports.RpcError = RpcError;
+
+
+/***/ }),
+
+/***/ 2849:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.stackDuplexStreamingInterceptors = exports.stackClientStreamingInterceptors = exports.stackServerStreamingInterceptors = exports.stackUnaryInterceptors = exports.stackIntercept = void 0;
+const runtime_1 = __webpack_require__(8886);
+/**
+ * Creates a "stack" of of all interceptors specified in the given `RpcOptions`.
+ * Used by generated client implementations.
+ * @internal
+ */
+function stackIntercept(kind, transport, method, options, input) {
+ var _a, _b, _c, _d;
+ if (kind == "unary") {
+ let tail = (mtd, inp, opt) => transport.unary(mtd, inp, opt);
+ for (const curr of ((_a = options.interceptors) !== null && _a !== void 0 ? _a : []).filter(i => i.interceptUnary).reverse()) {
+ const next = tail;
+ tail = (mtd, inp, opt) => curr.interceptUnary(next, mtd, inp, opt);
+ }
+ return tail(method, input, options);
+ }
+ if (kind == "serverStreaming") {
+ let tail = (mtd, inp, opt) => transport.serverStreaming(mtd, inp, opt);
+ for (const curr of ((_b = options.interceptors) !== null && _b !== void 0 ? _b : []).filter(i => i.interceptServerStreaming).reverse()) {
+ const next = tail;
+ tail = (mtd, inp, opt) => curr.interceptServerStreaming(next, mtd, inp, opt);
+ }
+ return tail(method, input, options);
+ }
+ if (kind == "clientStreaming") {
+ let tail = (mtd, opt) => transport.clientStreaming(mtd, opt);
+ for (const curr of ((_c = options.interceptors) !== null && _c !== void 0 ? _c : []).filter(i => i.interceptClientStreaming).reverse()) {
+ const next = tail;
+ tail = (mtd, opt) => curr.interceptClientStreaming(next, mtd, opt);
+ }
+ return tail(method, options);
+ }
+ if (kind == "duplex") {
+ let tail = (mtd, opt) => transport.duplex(mtd, opt);
+ for (const curr of ((_d = options.interceptors) !== null && _d !== void 0 ? _d : []).filter(i => i.interceptDuplex).reverse()) {
+ const next = tail;
+ tail = (mtd, opt) => curr.interceptDuplex(next, mtd, opt);
+ }
+ return tail(method, options);
+ }
+ runtime_1.assertNever(kind);
+}
+exports.stackIntercept = stackIntercept;
+/**
+ * @deprecated replaced by `stackIntercept()`, still here to support older generated code
+ */
+function stackUnaryInterceptors(transport, method, input, options) {
+ return stackIntercept("unary", transport, method, options, input);
+}
+exports.stackUnaryInterceptors = stackUnaryInterceptors;
+/**
+ * @deprecated replaced by `stackIntercept()`, still here to support older generated code
+ */
+function stackServerStreamingInterceptors(transport, method, input, options) {
+ return stackIntercept("serverStreaming", transport, method, options, input);
+}
+exports.stackServerStreamingInterceptors = stackServerStreamingInterceptors;
+/**
+ * @deprecated replaced by `stackIntercept()`, still here to support older generated code
+ */
+function stackClientStreamingInterceptors(transport, method, options) {
+ return stackIntercept("clientStreaming", transport, method, options);
+}
+exports.stackClientStreamingInterceptors = stackClientStreamingInterceptors;
+/**
+ * @deprecated replaced by `stackIntercept()`, still here to support older generated code
+ */
+function stackDuplexStreamingInterceptors(transport, method, options) {
+ return stackIntercept("duplex", transport, method, options);
+}
+exports.stackDuplexStreamingInterceptors = stackDuplexStreamingInterceptors;
+
+
+/***/ }),
+
+/***/ 8576:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.mergeRpcOptions = void 0;
+const runtime_1 = __webpack_require__(8886);
+/**
+ * Merges custom RPC options with defaults. Returns a new instance and keeps
+ * the "defaults" and the "options" unmodified.
+ *
+ * Merges `RpcMetadata` "meta", overwriting values from "defaults" with
+ * values from "options". Does not append values to existing entries.
+ *
+ * Merges "jsonOptions", including "jsonOptions.typeRegistry", by creating
+ * a new array that contains types from "options.jsonOptions.typeRegistry"
+ * first, then types from "defaults.jsonOptions.typeRegistry".
+ *
+ * Merges "binaryOptions".
+ *
+ * Merges "interceptors" by creating a new array that contains interceptors
+ * from "defaults" first, then interceptors from "options".
+ *
+ * Works with objects that extend `RpcOptions`, but only if the added
+ * properties are of type Date, primitive like string, boolean, or Array
+ * of primitives. If you have other property types, you have to merge them
+ * yourself.
+ */
+function mergeRpcOptions(defaults, options) {
+ if (!options)
+ return defaults;
+ let o = {};
+ copy(defaults, o);
+ copy(options, o);
+ for (let key of Object.keys(options)) {
+ let val = options[key];
+ switch (key) {
+ case "jsonOptions":
+ o.jsonOptions = runtime_1.mergeJsonOptions(defaults.jsonOptions, o.jsonOptions);
+ break;
+ case "binaryOptions":
+ o.binaryOptions = runtime_1.mergeBinaryOptions(defaults.binaryOptions, o.binaryOptions);
+ break;
+ case "meta":
+ o.meta = {};
+ copy(defaults.meta, o.meta);
+ copy(options.meta, o.meta);
+ break;
+ case "interceptors":
+ o.interceptors = defaults.interceptors ? defaults.interceptors.concat(val) : val.concat();
+ break;
+ }
+ }
+ return o;
+}
+exports.mergeRpcOptions = mergeRpcOptions;
+function copy(a, into) {
+ if (!a)
+ return;
+ let c = into;
+ for (let [k, v] of Object.entries(a)) {
+ if (v instanceof Date)
+ c[k] = new Date(v.getTime());
+ else if (Array.isArray(v))
+ c[k] = v.concat();
+ else
+ c[k] = v;
+ }
+}
+
+
+/***/ }),
+
+/***/ 2726:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.RpcOutputStreamController = void 0;
+const deferred_1 = __webpack_require__(1409);
+const runtime_1 = __webpack_require__(8886);
+/**
+ * A `RpcOutputStream` that you control.
+ */
+class RpcOutputStreamController {
+ constructor() {
+ this._lis = {
+ nxt: [],
+ msg: [],
+ err: [],
+ cmp: [],
+ };
+ this._closed = false;
+ // --- RpcOutputStream async iterator API
+ // iterator state.
+ // is undefined when no iterator has been acquired yet.
+ this._itState = { q: [] };
+ }
+ // --- RpcOutputStream callback API
+ onNext(callback) {
+ return this.addLis(callback, this._lis.nxt);
+ }
+ onMessage(callback) {
+ return this.addLis(callback, this._lis.msg);
+ }
+ onError(callback) {
+ return this.addLis(callback, this._lis.err);
+ }
+ onComplete(callback) {
+ return this.addLis(callback, this._lis.cmp);
+ }
+ addLis(callback, list) {
+ list.push(callback);
+ return () => {
+ let i = list.indexOf(callback);
+ if (i >= 0)
+ list.splice(i, 1);
+ };
+ }
+ // remove all listeners
+ clearLis() {
+ for (let l of Object.values(this._lis))
+ l.splice(0, l.length);
+ }
+ // --- Controller API
+ /**
+ * Is this stream already closed by a completion or error?
+ */
+ get closed() {
+ return this._closed !== false;
+ }
+ /**
+ * Emit message, close with error, or close successfully, but only one
+ * at a time.
+ * Can be used to wrap a stream by using the other stream's `onNext`.
+ */
+ notifyNext(message, error, complete) {
+ runtime_1.assert((message ? 1 : 0) + (error ? 1 : 0) + (complete ? 1 : 0) <= 1, 'only one emission at a time');
+ if (message)
+ this.notifyMessage(message);
+ if (error)
+ this.notifyError(error);
+ if (complete)
+ this.notifyComplete();
+ }
+ /**
+ * Emits a new message. Throws if stream is closed.
+ *
+ * Triggers onNext and onMessage callbacks.
+ */
+ notifyMessage(message) {
+ runtime_1.assert(!this.closed, 'stream is closed');
+ this.pushIt({ value: message, done: false });
+ this._lis.msg.forEach(l => l(message));
+ this._lis.nxt.forEach(l => l(message, undefined, false));
+ }
+ /**
+ * Closes the stream with an error. Throws if stream is closed.
+ *
+ * Triggers onNext and onError callbacks.
+ */
+ notifyError(error) {
+ runtime_1.assert(!this.closed, 'stream is closed');
+ this._closed = error;
+ this.pushIt(error);
+ this._lis.err.forEach(l => l(error));
+ this._lis.nxt.forEach(l => l(undefined, error, false));
+ this.clearLis();
+ }
+ /**
+ * Closes the stream successfully. Throws if stream is closed.
+ *
+ * Triggers onNext and onComplete callbacks.
+ */
+ notifyComplete() {
+ runtime_1.assert(!this.closed, 'stream is closed');
+ this._closed = true;
+ this.pushIt({ value: null, done: true });
+ this._lis.cmp.forEach(l => l());
+ this._lis.nxt.forEach(l => l(undefined, undefined, true));
+ this.clearLis();
+ }
+ /**
+ * Creates an async iterator (that can be used with `for await {...}`)
+ * to consume the stream.
+ *
+ * Some things to note:
+ * - If an error occurs, the `for await` will throw it.
+ * - If an error occurred before the `for await` was started, `for await`
+ * will re-throw it.
+ * - If the stream is already complete, the `for await` will be empty.
+ * - If your `for await` consumes slower than the stream produces,
+ * for example because you are relaying messages in a slow operation,
+ * messages are queued.
+ */
+ [Symbol.asyncIterator]() {
+ // if we are closed, we are definitely not receiving any more messages.
+ // but we can't let the iterator get stuck. we want to either:
+ // a) finish the new iterator immediately, because we are completed
+ // b) reject the new iterator, because we errored
+ if (this._closed === true)
+ this.pushIt({ value: null, done: true });
+ else if (this._closed !== false)
+ this.pushIt(this._closed);
+ // the async iterator
+ return {
+ next: () => {
+ let state = this._itState;
+ runtime_1.assert(state, "bad state"); // if we don't have a state here, code is broken
+ // there should be no pending result.
+ // did the consumer call next() before we resolved our previous result promise?
+ runtime_1.assert(!state.p, "iterator contract broken");
+ // did we produce faster than the iterator consumed?
+ // return the oldest result from the queue.
+ let first = state.q.shift();
+ if (first)
+ return ("value" in first) ? Promise.resolve(first) : Promise.reject(first);
+ // we have no result ATM, but we promise one.
+ // as soon as we have a result, we must resolve promise.
+ state.p = new deferred_1.Deferred();
+ return state.p.promise;
+ },
+ };
+ }
+ // "push" a new iterator result.
+ // this either resolves a pending promise, or enqueues the result.
+ pushIt(result) {
+ let state = this._itState;
+ // is the consumer waiting for us?
+ if (state.p) {
+ // yes, consumer is waiting for this promise.
+ const p = state.p;
+ runtime_1.assert(p.state == deferred_1.DeferredState.PENDING, "iterator contract broken");
+ // resolve the promise
+ ("value" in result) ? p.resolve(result) : p.reject(result);
+ // must cleanup, otherwise iterator.next() would pick it up again.
+ delete state.p;
+ }
+ else {
+ // we are producing faster than the iterator consumes.
+ // push result onto queue.
+ state.q.push(result);
+ }
+ }
+}
+exports.RpcOutputStreamController = RpcOutputStreamController;
+
+
+/***/ }),
+
+/***/ 3352:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ServerCallContextController = void 0;
+class ServerCallContextController {
+ constructor(method, headers, deadline, sendResponseHeadersFn, defaultStatus = { code: 'OK', detail: '' }) {
+ this._cancelled = false;
+ this._listeners = [];
+ this.method = method;
+ this.headers = headers;
+ this.deadline = deadline;
+ this.trailers = {};
+ this._sendRH = sendResponseHeadersFn;
+ this.status = defaultStatus;
+ }
+ /**
+ * Set the call cancelled.
+ *
+ * Invokes all callbacks registered with onCancel() and
+ * sets `cancelled = true`.
+ */
+ notifyCancelled() {
+ if (!this._cancelled) {
+ this._cancelled = true;
+ for (let l of this._listeners) {
+ l();
+ }
+ }
+ }
+ /**
+ * Send response headers.
+ */
+ sendResponseHeaders(data) {
+ this._sendRH(data);
+ }
+ /**
+ * Is the call cancelled?
+ *
+ * When the client closes the connection before the server
+ * is done, the call is cancelled.
+ *
+ * If you want to cancel a request on the server, throw a
+ * RpcError with the CANCELLED status code.
+ */
+ get cancelled() {
+ return this._cancelled;
+ }
+ /**
+ * Add a callback for cancellation.
+ */
+ onCancel(callback) {
+ const l = this._listeners;
+ l.push(callback);
+ return () => {
+ let i = l.indexOf(callback);
+ if (i >= 0)
+ l.splice(i, 1);
+ };
+ }
+}
+exports.ServerCallContextController = ServerCallContextController;
+
+
+/***/ }),
+
+/***/ 6173:
+/***/ (function(__unused_webpack_module, exports) {
+
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ServerStreamingCall = void 0;
+/**
+ * A server streaming RPC call. The client provides exactly one input message
+ * but the server may respond with 0, 1, or more messages.
+ */
+class ServerStreamingCall {
+ constructor(method, requestHeaders, request, headers, response, status, trailers) {
+ this.method = method;
+ this.requestHeaders = requestHeaders;
+ this.request = request;
+ this.headers = headers;
+ this.responses = response;
+ this.status = status;
+ this.trailers = trailers;
+ }
+ /**
+ * Instead of awaiting the response status and trailers, you can
+ * just as well await this call itself to receive the server outcome.
+ * You should first setup some listeners to the `request` to
+ * see the actual messages the server replied with.
+ */
+ then(onfulfilled, onrejected) {
+ return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
+ }
+ promiseFinished() {
+ return __awaiter(this, void 0, void 0, function* () {
+ let [headers, status, trailers] = yield Promise.all([this.headers, this.status, this.trailers]);
+ return {
+ method: this.method,
+ requestHeaders: this.requestHeaders,
+ request: this.request,
+ headers,
+ status,
+ trailers,
+ };
+ });
+ }
+}
+exports.ServerStreamingCall = ServerStreamingCall;
+
+
+/***/ }),
+
+/***/ 6892:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ServiceType = void 0;
+const reflection_info_1 = __webpack_require__(2496);
+class ServiceType {
+ constructor(typeName, methods, options) {
+ this.typeName = typeName;
+ this.methods = methods.map(i => reflection_info_1.normalizeMethodInfo(i, this));
+ this.options = options !== null && options !== void 0 ? options : {};
+ }
+}
+exports.ServiceType = ServiceType;
+
+
+/***/ }),
+
+/***/ 9122:
+/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.TestTransport = void 0;
+const rpc_error_1 = __webpack_require__(8636);
+const runtime_1 = __webpack_require__(8886);
+const rpc_output_stream_1 = __webpack_require__(2726);
+const rpc_options_1 = __webpack_require__(8576);
+const unary_call_1 = __webpack_require__(9288);
+const server_streaming_call_1 = __webpack_require__(6173);
+const client_streaming_call_1 = __webpack_require__(7889);
+const duplex_streaming_call_1 = __webpack_require__(6826);
+/**
+ * Transport for testing.
+ */
+class TestTransport {
+ /**
+ * Initialize with mock data. Omitted fields have default value.
+ */
+ constructor(data) {
+ /**
+ * Suppress warning / error about uncaught rejections of
+ * "status" and "trailers".
+ */
+ this.suppressUncaughtRejections = true;
+ this.headerDelay = 10;
+ this.responseDelay = 50;
+ this.betweenResponseDelay = 10;
+ this.afterResponseDelay = 10;
+ this.data = data !== null && data !== void 0 ? data : {};
+ }
+ /**
+ * Sent message(s) during the last operation.
+ */
+ get sentMessages() {
+ if (this.lastInput instanceof TestInputStream) {
+ return this.lastInput.sent;
+ }
+ else if (typeof this.lastInput == "object") {
+ return [this.lastInput.single];
+ }
+ return [];
+ }
+ /**
+ * Sending message(s) completed?
+ */
+ get sendComplete() {
+ if (this.lastInput instanceof TestInputStream) {
+ return this.lastInput.completed;
+ }
+ else if (typeof this.lastInput == "object") {
+ return true;
+ }
+ return false;
+ }
+ // Creates a promise for response headers from the mock data.
+ promiseHeaders() {
+ var _a;
+ const headers = (_a = this.data.headers) !== null && _a !== void 0 ? _a : TestTransport.defaultHeaders;
+ return headers instanceof rpc_error_1.RpcError
+ ? Promise.reject(headers)
+ : Promise.resolve(headers);
+ }
+ // Creates a promise for a single, valid, message from the mock data.
+ promiseSingleResponse(method) {
+ if (this.data.response instanceof rpc_error_1.RpcError) {
+ return Promise.reject(this.data.response);
+ }
+ let r;
+ if (Array.isArray(this.data.response)) {
+ runtime_1.assert(this.data.response.length > 0);
+ r = this.data.response[0];
+ }
+ else if (this.data.response !== undefined) {
+ r = this.data.response;
+ }
+ else {
+ r = method.O.create();
+ }
+ runtime_1.assert(method.O.is(r));
+ return Promise.resolve(r);
+ }
+ /**
+ * Pushes response messages from the mock data to the output stream.
+ * If an error response, status or trailers are mocked, the stream is
+ * closed with the respective error.
+ * Otherwise, stream is completed successfully.
+ *
+ * The returned promise resolves when the stream is closed. It should
+ * not reject. If it does, code is broken.
+ */
+ streamResponses(method, stream, abort) {
+ return __awaiter(this, void 0, void 0, function* () {
+ // normalize "data.response" into an array of valid output messages
+ const messages = [];
+ if (this.data.response === undefined) {
+ messages.push(method.O.create());
+ }
+ else if (Array.isArray(this.data.response)) {
+ for (let msg of this.data.response) {
+ runtime_1.assert(method.O.is(msg));
+ messages.push(msg);
+ }
+ }
+ else if (!(this.data.response instanceof rpc_error_1.RpcError)) {
+ runtime_1.assert(method.O.is(this.data.response));
+ messages.push(this.data.response);
+ }
+ // start the stream with an initial delay.
+ // if the request is cancelled, notify() error and exit.
+ try {
+ yield delay(this.responseDelay, abort)(undefined);
+ }
+ catch (error) {
+ stream.notifyError(error);
+ return;
+ }
+ // if error response was mocked, notify() error (stream is now closed with error) and exit.
+ if (this.data.response instanceof rpc_error_1.RpcError) {
+ stream.notifyError(this.data.response);
+ return;
+ }
+ // regular response messages were mocked. notify() them.
+ for (let msg of messages) {
+ stream.notifyMessage(msg);
+ // add a short delay between responses
+ // if the request is cancelled, notify() error and exit.
+ try {
+ yield delay(this.betweenResponseDelay, abort)(undefined);
+ }
+ catch (error) {
+ stream.notifyError(error);
+ return;
+ }
+ }
+ // error status was mocked, notify() error (stream is now closed with error) and exit.
+ if (this.data.status instanceof rpc_error_1.RpcError) {
+ stream.notifyError(this.data.status);
+ return;
+ }
+ // error trailers were mocked, notify() error (stream is now closed with error) and exit.
+ if (this.data.trailers instanceof rpc_error_1.RpcError) {
+ stream.notifyError(this.data.trailers);
+ return;
+ }
+ // stream completed successfully
+ stream.notifyComplete();
+ });
+ }
+ // Creates a promise for response status from the mock data.
+ promiseStatus() {
+ var _a;
+ const status = (_a = this.data.status) !== null && _a !== void 0 ? _a : TestTransport.defaultStatus;
+ return status instanceof rpc_error_1.RpcError
+ ? Promise.reject(status)
+ : Promise.resolve(status);
+ }
+ // Creates a promise for response trailers from the mock data.
+ promiseTrailers() {
+ var _a;
+ const trailers = (_a = this.data.trailers) !== null && _a !== void 0 ? _a : TestTransport.defaultTrailers;
+ return trailers instanceof rpc_error_1.RpcError
+ ? Promise.reject(trailers)
+ : Promise.resolve(trailers);
+ }
+ maybeSuppressUncaught(...promise) {
+ if (this.suppressUncaughtRejections) {
+ for (let p of promise) {
+ p.catch(() => {
+ });
+ }
+ }
+ }
+ mergeOptions(options) {
+ return rpc_options_1.mergeRpcOptions({}, options);
+ }
+ unary(method, input, options) {
+ var _a;
+ const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
+ .then(delay(this.headerDelay, options.abort)), responsePromise = headersPromise
+ .catch(_ => {
+ })
+ .then(delay(this.responseDelay, options.abort))
+ .then(_ => this.promiseSingleResponse(method)), statusPromise = responsePromise
+ .catch(_ => {
+ })
+ .then(delay(this.afterResponseDelay, options.abort))
+ .then(_ => this.promiseStatus()), trailersPromise = responsePromise
+ .catch(_ => {
+ })
+ .then(delay(this.afterResponseDelay, options.abort))
+ .then(_ => this.promiseTrailers());
+ this.maybeSuppressUncaught(statusPromise, trailersPromise);
+ this.lastInput = { single: input };
+ return new unary_call_1.UnaryCall(method, requestHeaders, input, headersPromise, responsePromise, statusPromise, trailersPromise);
+ }
+ serverStreaming(method, input, options) {
+ var _a;
+ const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
+ .then(delay(this.headerDelay, options.abort)), outputStream = new rpc_output_stream_1.RpcOutputStreamController(), responseStreamClosedPromise = headersPromise
+ .then(delay(this.responseDelay, options.abort))
+ .catch(() => {
+ })
+ .then(() => this.streamResponses(method, outputStream, options.abort))
+ .then(delay(this.afterResponseDelay, options.abort)), statusPromise = responseStreamClosedPromise
+ .then(() => this.promiseStatus()), trailersPromise = responseStreamClosedPromise
+ .then(() => this.promiseTrailers());
+ this.maybeSuppressUncaught(statusPromise, trailersPromise);
+ this.lastInput = { single: input };
+ return new server_streaming_call_1.ServerStreamingCall(method, requestHeaders, input, headersPromise, outputStream, statusPromise, trailersPromise);
+ }
+ clientStreaming(method, options) {
+ var _a;
+ const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
+ .then(delay(this.headerDelay, options.abort)), responsePromise = headersPromise
+ .catch(_ => {
+ })
+ .then(delay(this.responseDelay, options.abort))
+ .then(_ => this.promiseSingleResponse(method)), statusPromise = responsePromise
+ .catch(_ => {
+ })
+ .then(delay(this.afterResponseDelay, options.abort))
+ .then(_ => this.promiseStatus()), trailersPromise = responsePromise
+ .catch(_ => {
+ })
+ .then(delay(this.afterResponseDelay, options.abort))
+ .then(_ => this.promiseTrailers());
+ this.maybeSuppressUncaught(statusPromise, trailersPromise);
+ this.lastInput = new TestInputStream(this.data, options.abort);
+ return new client_streaming_call_1.ClientStreamingCall(method, requestHeaders, this.lastInput, headersPromise, responsePromise, statusPromise, trailersPromise);
+ }
+ duplex(method, options) {
+ var _a;
+ const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
+ .then(delay(this.headerDelay, options.abort)), outputStream = new rpc_output_stream_1.RpcOutputStreamController(), responseStreamClosedPromise = headersPromise
+ .then(delay(this.responseDelay, options.abort))
+ .catch(() => {
+ })
+ .then(() => this.streamResponses(method, outputStream, options.abort))
+ .then(delay(this.afterResponseDelay, options.abort)), statusPromise = responseStreamClosedPromise
+ .then(() => this.promiseStatus()), trailersPromise = responseStreamClosedPromise
+ .then(() => this.promiseTrailers());
+ this.maybeSuppressUncaught(statusPromise, trailersPromise);
+ this.lastInput = new TestInputStream(this.data, options.abort);
+ return new duplex_streaming_call_1.DuplexStreamingCall(method, requestHeaders, this.lastInput, headersPromise, outputStream, statusPromise, trailersPromise);
+ }
+}
+exports.TestTransport = TestTransport;
+TestTransport.defaultHeaders = {
+ responseHeader: "test"
+};
+TestTransport.defaultStatus = {
+ code: "OK", detail: "all good"
+};
+TestTransport.defaultTrailers = {
+ responseTrailer: "test"
+};
+function delay(ms, abort) {
+ return (v) => new Promise((resolve, reject) => {
+ if (abort === null || abort === void 0 ? void 0 : abort.aborted) {
+ reject(new rpc_error_1.RpcError("user cancel", "CANCELLED"));
+ }
+ else {
+ const id = setTimeout(() => resolve(v), ms);
+ if (abort) {
+ abort.addEventListener("abort", ev => {
+ clearTimeout(id);
+ reject(new rpc_error_1.RpcError("user cancel", "CANCELLED"));
+ });
+ }
+ }
+ });
+}
+class TestInputStream {
+ constructor(data, abort) {
+ this._completed = false;
+ this._sent = [];
+ this.data = data;
+ this.abort = abort;
+ }
+ get sent() {
+ return this._sent;
+ }
+ get completed() {
+ return this._completed;
+ }
+ send(message) {
+ if (this.data.inputMessage instanceof rpc_error_1.RpcError) {
+ return Promise.reject(this.data.inputMessage);
+ }
+ const delayMs = this.data.inputMessage === undefined
+ ? 10
+ : this.data.inputMessage;
+ return Promise.resolve(undefined)
+ .then(() => {
+ this._sent.push(message);
+ })
+ .then(delay(delayMs, this.abort));
+ }
+ complete() {
+ if (this.data.inputComplete instanceof rpc_error_1.RpcError) {
+ return Promise.reject(this.data.inputComplete);
+ }
+ const delayMs = this.data.inputComplete === undefined
+ ? 10
+ : this.data.inputComplete;
+ return Promise.resolve(undefined)
+ .then(() => {
+ this._completed = true;
+ })
+ .then(delay(delayMs, this.abort));
+ }
+}
+
+
+/***/ }),
+
+/***/ 9288:
+/***/ (function(__unused_webpack_module, exports) {
+
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.UnaryCall = void 0;
+/**
+ * A unary RPC call. Unary means there is exactly one input message and
+ * exactly one output message unless an error occurred.
+ */
+class UnaryCall {
+ constructor(method, requestHeaders, request, headers, response, status, trailers) {
+ this.method = method;
+ this.requestHeaders = requestHeaders;
+ this.request = request;
+ this.headers = headers;
+ this.response = response;
+ this.status = status;
+ this.trailers = trailers;
+ }
+ /**
+ * If you are only interested in the final outcome of this call,
+ * you can await it to receive a `FinishedUnaryCall`.
+ */
+ then(onfulfilled, onrejected) {
+ return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
+ }
+ promiseFinished() {
+ return __awaiter(this, void 0, void 0, function* () {
+ let [headers, response, status, trailers] = yield Promise.all([this.headers, this.response, this.status, this.trailers]);
+ return {
+ method: this.method,
+ requestHeaders: this.requestHeaders,
+ request: this.request,
+ headers,
+ response,
+ status,
+ trailers
+ };
+ });
+ }
+}
+exports.UnaryCall = UnaryCall;
+
+
+/***/ }),
+
+/***/ 8602:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.assertFloat32 = exports.assertUInt32 = exports.assertInt32 = exports.assertNever = exports.assert = void 0;
+/**
+ * assert that condition is true or throw error (with message)
+ */
+function assert(condition, msg) {
+ if (!condition) {
+ throw new Error(msg);
+ }
+}
+exports.assert = assert;
+/**
+ * assert that value cannot exist = type `never`. throw runtime error if it does.
+ */
+function assertNever(value, msg) {
+ throw new Error(msg !== null && msg !== void 0 ? msg : 'Unexpected object: ' + value);
+}
+exports.assertNever = assertNever;
+const FLOAT32_MAX = 3.4028234663852886e+38, FLOAT32_MIN = -3.4028234663852886e+38, UINT32_MAX = 0xFFFFFFFF, INT32_MAX = 0X7FFFFFFF, INT32_MIN = -0X80000000;
+function assertInt32(arg) {
+ if (typeof arg !== "number")
+ throw new Error('invalid int 32: ' + typeof arg);
+ if (!Number.isInteger(arg) || arg > INT32_MAX || arg < INT32_MIN)
+ throw new Error('invalid int 32: ' + arg);
+}
+exports.assertInt32 = assertInt32;
+function assertUInt32(arg) {
+ if (typeof arg !== "number")
+ throw new Error('invalid uint 32: ' + typeof arg);
+ if (!Number.isInteger(arg) || arg > UINT32_MAX || arg < 0)
+ throw new Error('invalid uint 32: ' + arg);
+}
+exports.assertUInt32 = assertUInt32;
+function assertFloat32(arg) {
+ if (typeof arg !== "number")
+ throw new Error('invalid float 32: ' + typeof arg);
+ if (!Number.isFinite(arg))
+ return;
+ if (arg > FLOAT32_MAX || arg < FLOAT32_MIN)
+ throw new Error('invalid float 32: ' + arg);
+}
+exports.assertFloat32 = assertFloat32;
+
+
+/***/ }),
+
+/***/ 6335:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.base64encode = exports.base64decode = void 0;
+// lookup table from base64 character to byte
+let encTable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
+// lookup table from base64 character *code* to byte because lookup by number is fast
+let decTable = [];
+for (let i = 0; i < encTable.length; i++)
+ decTable[encTable[i].charCodeAt(0)] = i;
+// support base64url variants
+decTable["-".charCodeAt(0)] = encTable.indexOf("+");
+decTable["_".charCodeAt(0)] = encTable.indexOf("/");
+/**
+ * Decodes a base64 string to a byte array.
+ *
+ * - ignores white-space, including line breaks and tabs
+ * - allows inner padding (can decode concatenated base64 strings)
+ * - does not require padding
+ * - understands base64url encoding:
+ * "-" instead of "+",
+ * "_" instead of "/",
+ * no padding
+ */
+function base64decode(base64Str) {
+ // estimate byte size, not accounting for inner padding and whitespace
+ let es = base64Str.length * 3 / 4;
+ // if (es % 3 !== 0)
+ // throw new Error('invalid base64 string');
+ if (base64Str[base64Str.length - 2] == '=')
+ es -= 2;
+ else if (base64Str[base64Str.length - 1] == '=')
+ es -= 1;
+ let bytes = new Uint8Array(es), bytePos = 0, // position in byte array
+ groupPos = 0, // position in base64 group
+ b, // current byte
+ p = 0 // previous byte
+ ;
+ for (let i = 0; i < base64Str.length; i++) {
+ b = decTable[base64Str.charCodeAt(i)];
+ if (b === undefined) {
+ // noinspection FallThroughInSwitchStatementJS
+ switch (base64Str[i]) {
+ case '=':
+ groupPos = 0; // reset state when padding found
+ case '\n':
+ case '\r':
+ case '\t':
+ case ' ':
+ continue; // skip white-space, and padding
+ default:
+ throw Error(`invalid base64 string.`);
+ }
+ }
+ switch (groupPos) {
+ case 0:
+ p = b;
+ groupPos = 1;
+ break;
+ case 1:
+ bytes[bytePos++] = p << 2 | (b & 48) >> 4;
+ p = b;
+ groupPos = 2;
+ break;
+ case 2:
+ bytes[bytePos++] = (p & 15) << 4 | (b & 60) >> 2;
+ p = b;
+ groupPos = 3;
+ break;
+ case 3:
+ bytes[bytePos++] = (p & 3) << 6 | b;
+ groupPos = 0;
+ break;
+ }
+ }
+ if (groupPos == 1)
+ throw Error(`invalid base64 string.`);
+ return bytes.subarray(0, bytePos);
+}
+exports.base64decode = base64decode;
+/**
+ * Encodes a byte array to a base64 string.
+ * Adds padding at the end.
+ * Does not insert newlines.
+ */
+function base64encode(bytes) {
+ let base64 = '', groupPos = 0, // position in base64 group
+ b, // current byte
+ p = 0; // carry over from previous byte
+ for (let i = 0; i < bytes.length; i++) {
+ b = bytes[i];
+ switch (groupPos) {
+ case 0:
+ base64 += encTable[b >> 2];
+ p = (b & 3) << 4;
+ groupPos = 1;
+ break;
+ case 1:
+ base64 += encTable[p | b >> 4];
+ p = (b & 15) << 2;
+ groupPos = 2;
+ break;
+ case 2:
+ base64 += encTable[p | b >> 6];
+ base64 += encTable[b & 63];
+ groupPos = 0;
+ break;
+ }
+ }
+ // padding required?
+ if (groupPos) {
+ base64 += encTable[p];
+ base64 += '=';
+ if (groupPos == 1)
+ base64 += '=';
+ }
+ return base64;
+}
+exports.base64encode = base64encode;
+
+
+/***/ }),
+
+/***/ 4816:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.WireType = exports.mergeBinaryOptions = exports.UnknownFieldHandler = void 0;
+/**
+ * This handler implements the default behaviour for unknown fields.
+ * When reading data, unknown fields are stored on the message, in a
+ * symbol property.
+ * When writing data, the symbol property is queried and unknown fields
+ * are serialized into the output again.
+ */
+var UnknownFieldHandler;
+(function (UnknownFieldHandler) {
+ /**
+ * The symbol used to store unknown fields for a message.
+ * The property must conform to `UnknownFieldContainer`.
+ */
+ UnknownFieldHandler.symbol = Symbol.for("protobuf-ts/unknown");
+ /**
+ * Store an unknown field during binary read directly on the message.
+ * This method is compatible with `BinaryReadOptions.readUnknownField`.
+ */
+ UnknownFieldHandler.onRead = (typeName, message, fieldNo, wireType, data) => {
+ let container = is(message) ? message[UnknownFieldHandler.symbol] : message[UnknownFieldHandler.symbol] = [];
+ container.push({ no: fieldNo, wireType, data });
+ };
+ /**
+ * Write unknown fields stored for the message to the writer.
+ * This method is compatible with `BinaryWriteOptions.writeUnknownFields`.
+ */
+ UnknownFieldHandler.onWrite = (typeName, message, writer) => {
+ for (let { no, wireType, data } of UnknownFieldHandler.list(message))
+ writer.tag(no, wireType).raw(data);
+ };
+ /**
+ * List unknown fields stored for the message.
+ * Note that there may be multiples fields with the same number.
+ */
+ UnknownFieldHandler.list = (message, fieldNo) => {
+ if (is(message)) {
+ let all = message[UnknownFieldHandler.symbol];
+ return fieldNo ? all.filter(uf => uf.no == fieldNo) : all;
+ }
+ return [];
+ };
+ /**
+ * Returns the last unknown field by field number.
+ */
+ UnknownFieldHandler.last = (message, fieldNo) => UnknownFieldHandler.list(message, fieldNo).slice(-1)[0];
+ const is = (message) => message && Array.isArray(message[UnknownFieldHandler.symbol]);
+})(UnknownFieldHandler = exports.UnknownFieldHandler || (exports.UnknownFieldHandler = {}));
+/**
+ * Merges binary write or read options. Later values override earlier values.
+ */
+function mergeBinaryOptions(a, b) {
+ return Object.assign(Object.assign({}, a), b);
+}
+exports.mergeBinaryOptions = mergeBinaryOptions;
+/**
+ * Protobuf binary format wire types.
+ *
+ * A wire type provides just enough information to find the length of the
+ * following value.
+ *
+ * See https://developers.google.com/protocol-buffers/docs/encoding#structure
+ */
+var WireType;
+(function (WireType) {
+ /**
+ * Used for int32, int64, uint32, uint64, sint32, sint64, bool, enum
+ */
+ WireType[WireType["Varint"] = 0] = "Varint";
+ /**
+ * Used for fixed64, sfixed64, double.
+ * Always 8 bytes with little-endian byte order.
+ */
+ WireType[WireType["Bit64"] = 1] = "Bit64";
+ /**
+ * Used for string, bytes, embedded messages, packed repeated fields
+ *
+ * Only repeated numeric types (types which use the varint, 32-bit,
+ * or 64-bit wire types) can be packed. In proto3, such fields are
+ * packed by default.
+ */
+ WireType[WireType["LengthDelimited"] = 2] = "LengthDelimited";
+ /**
+ * Used for groups
+ * @deprecated
+ */
+ WireType[WireType["StartGroup"] = 3] = "StartGroup";
+ /**
+ * Used for groups
+ * @deprecated
+ */
+ WireType[WireType["EndGroup"] = 4] = "EndGroup";
+ /**
+ * Used for fixed32, sfixed32, float.
+ * Always 4 bytes with little-endian byte order.
+ */
+ WireType[WireType["Bit32"] = 5] = "Bit32";
+})(WireType = exports.WireType || (exports.WireType = {}));
+
+
+/***/ }),
+
+/***/ 2889:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.BinaryReader = exports.binaryReadOptions = void 0;
+const binary_format_contract_1 = __webpack_require__(4816);
+const pb_long_1 = __webpack_require__(1753);
+const goog_varint_1 = __webpack_require__(3223);
+const defaultsRead = {
+ readUnknownField: true,
+ readerFactory: bytes => new BinaryReader(bytes),
+};
+/**
+ * Make options for reading binary data form partial options.
+ */
+function binaryReadOptions(options) {
+ return options ? Object.assign(Object.assign({}, defaultsRead), options) : defaultsRead;
+}
+exports.binaryReadOptions = binaryReadOptions;
+class BinaryReader {
+ constructor(buf, textDecoder) {
+ this.varint64 = goog_varint_1.varint64read; // dirty cast for `this`
+ /**
+ * Read a `uint32` field, an unsigned 32 bit varint.
+ */
+ this.uint32 = goog_varint_1.varint32read; // dirty cast for `this` and access to protected `buf`
+ this.buf = buf;
+ this.len = buf.length;
+ this.pos = 0;
+ this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
+ this.textDecoder = textDecoder !== null && textDecoder !== void 0 ? textDecoder : new TextDecoder("utf-8", {
+ fatal: true,
+ ignoreBOM: true,
+ });
+ }
+ /**
+ * Reads a tag - field number and wire type.
+ */
+ tag() {
+ let tag = this.uint32(), fieldNo = tag >>> 3, wireType = tag & 7;
+ if (fieldNo <= 0 || wireType < 0 || wireType > 5)
+ throw new Error("illegal tag: field no " + fieldNo + " wire type " + wireType);
+ return [fieldNo, wireType];
+ }
+ /**
+ * Skip one element on the wire and return the skipped data.
+ * Supports WireType.StartGroup since v2.0.0-alpha.23.
+ */
+ skip(wireType) {
+ let start = this.pos;
+ // noinspection FallThroughInSwitchStatementJS
+ switch (wireType) {
+ case binary_format_contract_1.WireType.Varint:
+ while (this.buf[this.pos++] & 0x80) {
+ // ignore
+ }
+ break;
+ case binary_format_contract_1.WireType.Bit64:
+ this.pos += 4;
+ case binary_format_contract_1.WireType.Bit32:
+ this.pos += 4;
+ break;
+ case binary_format_contract_1.WireType.LengthDelimited:
+ let len = this.uint32();
+ this.pos += len;
+ break;
+ case binary_format_contract_1.WireType.StartGroup:
+ // From descriptor.proto: Group type is deprecated, not supported in proto3.
+ // But we must still be able to parse and treat as unknown.
+ let t;
+ while ((t = this.tag()[1]) !== binary_format_contract_1.WireType.EndGroup) {
+ this.skip(t);
+ }
+ break;
+ default:
+ throw new Error("cant skip wire type " + wireType);
+ }
+ this.assertBounds();
+ return this.buf.subarray(start, this.pos);
+ }
+ /**
+ * Throws error if position in byte array is out of range.
+ */
+ assertBounds() {
+ if (this.pos > this.len)
+ throw new RangeError("premature EOF");
+ }
+ /**
+ * Read a `int32` field, a signed 32 bit varint.
+ */
+ int32() {
+ return this.uint32() | 0;
+ }
+ /**
+ * Read a `sint32` field, a signed, zigzag-encoded 32-bit varint.
+ */
+ sint32() {
+ let zze = this.uint32();
+ // decode zigzag
+ return (zze >>> 1) ^ -(zze & 1);
+ }
+ /**
+ * Read a `int64` field, a signed 64-bit varint.
+ */
+ int64() {
+ return new pb_long_1.PbLong(...this.varint64());
+ }
+ /**
+ * Read a `uint64` field, an unsigned 64-bit varint.
+ */
+ uint64() {
+ return new pb_long_1.PbULong(...this.varint64());
+ }
+ /**
+ * Read a `sint64` field, a signed, zig-zag-encoded 64-bit varint.
+ */
+ sint64() {
+ let [lo, hi] = this.varint64();
+ // decode zig zag
+ let s = -(lo & 1);
+ lo = ((lo >>> 1 | (hi & 1) << 31) ^ s);
+ hi = (hi >>> 1 ^ s);
+ return new pb_long_1.PbLong(lo, hi);
+ }
+ /**
+ * Read a `bool` field, a variant.
+ */
+ bool() {
+ let [lo, hi] = this.varint64();
+ return lo !== 0 || hi !== 0;
+ }
+ /**
+ * Read a `fixed32` field, an unsigned, fixed-length 32-bit integer.
+ */
+ fixed32() {
+ return this.view.getUint32((this.pos += 4) - 4, true);
+ }
+ /**
+ * Read a `sfixed32` field, a signed, fixed-length 32-bit integer.
+ */
+ sfixed32() {
+ return this.view.getInt32((this.pos += 4) - 4, true);
+ }
+ /**
+ * Read a `fixed64` field, an unsigned, fixed-length 64 bit integer.
+ */
+ fixed64() {
+ return new pb_long_1.PbULong(this.sfixed32(), this.sfixed32());
+ }
+ /**
+ * Read a `fixed64` field, a signed, fixed-length 64-bit integer.
+ */
+ sfixed64() {
+ return new pb_long_1.PbLong(this.sfixed32(), this.sfixed32());
+ }
+ /**
+ * Read a `float` field, 32-bit floating point number.
+ */
+ float() {
+ return this.view.getFloat32((this.pos += 4) - 4, true);
+ }
+ /**
+ * Read a `double` field, a 64-bit floating point number.
+ */
+ double() {
+ return this.view.getFloat64((this.pos += 8) - 8, true);
+ }
+ /**
+ * Read a `bytes` field, length-delimited arbitrary data.
+ */
+ bytes() {
+ let len = this.uint32();
+ let start = this.pos;
+ this.pos += len;
+ this.assertBounds();
+ return this.buf.subarray(start, start + len);
+ }
+ /**
+ * Read a `string` field, length-delimited data converted to UTF-8 text.
+ */
+ string() {
+ return this.textDecoder.decode(this.bytes());
+ }
+}
+exports.BinaryReader = BinaryReader;
+
+
+/***/ }),
+
+/***/ 3957:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.BinaryWriter = exports.binaryWriteOptions = void 0;
+const pb_long_1 = __webpack_require__(1753);
+const goog_varint_1 = __webpack_require__(3223);
+const assert_1 = __webpack_require__(8602);
+const defaultsWrite = {
+ writeUnknownFields: true,
+ writerFactory: () => new BinaryWriter(),
+};
+/**
+ * Make options for writing binary data form partial options.
+ */
+function binaryWriteOptions(options) {
+ return options ? Object.assign(Object.assign({}, defaultsWrite), options) : defaultsWrite;
+}
+exports.binaryWriteOptions = binaryWriteOptions;
+class BinaryWriter {
+ constructor(textEncoder) {
+ /**
+ * Previous fork states.
+ */
+ this.stack = [];
+ this.textEncoder = textEncoder !== null && textEncoder !== void 0 ? textEncoder : new TextEncoder();
+ this.chunks = [];
+ this.buf = [];
+ }
+ /**
+ * Return all bytes written and reset this writer.
+ */
+ finish() {
+ this.chunks.push(new Uint8Array(this.buf)); // flush the buffer
+ let len = 0;
+ for (let i = 0; i < this.chunks.length; i++)
+ len += this.chunks[i].length;
+ let bytes = new Uint8Array(len);
+ let offset = 0;
+ for (let i = 0; i < this.chunks.length; i++) {
+ bytes.set(this.chunks[i], offset);
+ offset += this.chunks[i].length;
+ }
+ this.chunks = [];
+ return bytes;
+ }
+ /**
+ * Start a new fork for length-delimited data like a message
+ * or a packed repeated field.
+ *
+ * Must be joined later with `join()`.
+ */
+ fork() {
+ this.stack.push({ chunks: this.chunks, buf: this.buf });
+ this.chunks = [];
+ this.buf = [];
+ return this;
+ }
+ /**
+ * Join the last fork. Write its length and bytes, then
+ * return to the previous state.
+ */
+ join() {
+ // get chunk of fork
+ let chunk = this.finish();
+ // restore previous state
+ let prev = this.stack.pop();
+ if (!prev)
+ throw new Error('invalid state, fork stack empty');
+ this.chunks = prev.chunks;
+ this.buf = prev.buf;
+ // write length of chunk as varint
+ this.uint32(chunk.byteLength);
+ return this.raw(chunk);
+ }
+ /**
+ * Writes a tag (field number and wire type).
+ *
+ * Equivalent to `uint32( (fieldNo << 3 | type) >>> 0 )`.
+ *
+ * Generated code should compute the tag ahead of time and call `uint32()`.
+ */
+ tag(fieldNo, type) {
+ return this.uint32((fieldNo << 3 | type) >>> 0);
+ }
+ /**
+ * Write a chunk of raw bytes.
+ */
+ raw(chunk) {
+ if (this.buf.length) {
+ this.chunks.push(new Uint8Array(this.buf));
+ this.buf = [];
+ }
+ this.chunks.push(chunk);
+ return this;
+ }
+ /**
+ * Write a `uint32` value, an unsigned 32 bit varint.
+ */
+ uint32(value) {
+ assert_1.assertUInt32(value);
+ // write value as varint 32, inlined for speed
+ while (value > 0x7f) {
+ this.buf.push((value & 0x7f) | 0x80);
+ value = value >>> 7;
+ }
+ this.buf.push(value);
+ return this;
+ }
+ /**
+ * Write a `int32` value, a signed 32 bit varint.
+ */
+ int32(value) {
+ assert_1.assertInt32(value);
+ goog_varint_1.varint32write(value, this.buf);
+ return this;
+ }
+ /**
+ * Write a `bool` value, a variant.
+ */
+ bool(value) {
+ this.buf.push(value ? 1 : 0);
+ return this;
+ }
+ /**
+ * Write a `bytes` value, length-delimited arbitrary data.
+ */
+ bytes(value) {
+ this.uint32(value.byteLength); // write length of chunk as varint
+ return this.raw(value);
+ }
+ /**
+ * Write a `string` value, length-delimited data converted to UTF-8 text.
+ */
+ string(value) {
+ let chunk = this.textEncoder.encode(value);
+ this.uint32(chunk.byteLength); // write length of chunk as varint
+ return this.raw(chunk);
+ }
+ /**
+ * Write a `float` value, 32-bit floating point number.
+ */
+ float(value) {
+ assert_1.assertFloat32(value);
+ let chunk = new Uint8Array(4);
+ new DataView(chunk.buffer).setFloat32(0, value, true);
+ return this.raw(chunk);
+ }
+ /**
+ * Write a `double` value, a 64-bit floating point number.
+ */
+ double(value) {
+ let chunk = new Uint8Array(8);
+ new DataView(chunk.buffer).setFloat64(0, value, true);
+ return this.raw(chunk);
+ }
+ /**
+ * Write a `fixed32` value, an unsigned, fixed-length 32-bit integer.
+ */
+ fixed32(value) {
+ assert_1.assertUInt32(value);
+ let chunk = new Uint8Array(4);
+ new DataView(chunk.buffer).setUint32(0, value, true);
+ return this.raw(chunk);
+ }
+ /**
+ * Write a `sfixed32` value, a signed, fixed-length 32-bit integer.
+ */
+ sfixed32(value) {
+ assert_1.assertInt32(value);
+ let chunk = new Uint8Array(4);
+ new DataView(chunk.buffer).setInt32(0, value, true);
+ return this.raw(chunk);
+ }
+ /**
+ * Write a `sint32` value, a signed, zigzag-encoded 32-bit varint.
+ */
+ sint32(value) {
+ assert_1.assertInt32(value);
+ // zigzag encode
+ value = ((value << 1) ^ (value >> 31)) >>> 0;
+ goog_varint_1.varint32write(value, this.buf);
+ return this;
+ }
+ /**
+ * Write a `fixed64` value, a signed, fixed-length 64-bit integer.
+ */
+ sfixed64(value) {
+ let chunk = new Uint8Array(8);
+ let view = new DataView(chunk.buffer);
+ let long = pb_long_1.PbLong.from(value);
+ view.setInt32(0, long.lo, true);
+ view.setInt32(4, long.hi, true);
+ return this.raw(chunk);
+ }
+ /**
+ * Write a `fixed64` value, an unsigned, fixed-length 64 bit integer.
+ */
+ fixed64(value) {
+ let chunk = new Uint8Array(8);
+ let view = new DataView(chunk.buffer);
+ let long = pb_long_1.PbULong.from(value);
+ view.setInt32(0, long.lo, true);
+ view.setInt32(4, long.hi, true);
+ return this.raw(chunk);
+ }
+ /**
+ * Write a `int64` value, a signed 64-bit varint.
+ */
+ int64(value) {
+ let long = pb_long_1.PbLong.from(value);
+ goog_varint_1.varint64write(long.lo, long.hi, this.buf);
+ return this;
+ }
+ /**
+ * Write a `sint64` value, a signed, zig-zag-encoded 64-bit varint.
+ */
+ sint64(value) {
+ let long = pb_long_1.PbLong.from(value),
+ // zigzag encode
+ sign = long.hi >> 31, lo = (long.lo << 1) ^ sign, hi = ((long.hi << 1) | (long.lo >>> 31)) ^ sign;
+ goog_varint_1.varint64write(lo, hi, this.buf);
+ return this;
+ }
+ /**
+ * Write a `uint64` value, an unsigned 64-bit varint.
+ */
+ uint64(value) {
+ let long = pb_long_1.PbULong.from(value);
+ goog_varint_1.varint64write(long.lo, long.hi, this.buf);
+ return this;
+ }
+}
+exports.BinaryWriter = BinaryWriter;
+
+
+/***/ }),
+
+/***/ 257:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.listEnumNumbers = exports.listEnumNames = exports.listEnumValues = exports.isEnumObject = void 0;
+/**
+ * Is this a lookup object generated by Typescript, for a Typescript enum
+ * generated by protobuf-ts?
+ *
+ * - No `const enum` (enum must not be inlined, we need reverse mapping).
+ * - No string enum (we need int32 for protobuf).
+ * - Must have a value for 0 (otherwise, we would need to support custom default values).
+ */
+function isEnumObject(arg) {
+ if (typeof arg != 'object' || arg === null) {
+ return false;
+ }
+ if (!arg.hasOwnProperty(0)) {
+ return false;
+ }
+ for (let k of Object.keys(arg)) {
+ let num = parseInt(k);
+ if (!Number.isNaN(num)) {
+ // is there a name for the number?
+ let nam = arg[num];
+ if (nam === undefined)
+ return false;
+ // does the name resolve back to the number?
+ if (arg[nam] !== num)
+ return false;
+ }
+ else {
+ // is there a number for the name?
+ let num = arg[k];
+ if (num === undefined)
+ return false;
+ // is it a string enum?
+ if (typeof num !== 'number')
+ return false;
+ // do we know the number?
+ if (arg[num] === undefined)
+ return false;
+ }
+ }
+ return true;
+}
+exports.isEnumObject = isEnumObject;
+/**
+ * Lists all values of a Typescript enum, as an array of objects with a "name"
+ * property and a "number" property.
+ *
+ * Note that it is possible that a number appears more than once, because it is
+ * possible to have aliases in an enum.
+ *
+ * Throws if the enum does not adhere to the rules of enums generated by
+ * protobuf-ts. See `isEnumObject()`.
+ */
+function listEnumValues(enumObject) {
+ if (!isEnumObject(enumObject))
+ throw new Error("not a typescript enum object");
+ let values = [];
+ for (let [name, number] of Object.entries(enumObject))
+ if (typeof number == "number")
+ values.push({ name, number });
+ return values;
+}
+exports.listEnumValues = listEnumValues;
+/**
+ * Lists the names of a Typescript enum.
+ *
+ * Throws if the enum does not adhere to the rules of enums generated by
+ * protobuf-ts. See `isEnumObject()`.
+ */
+function listEnumNames(enumObject) {
+ return listEnumValues(enumObject).map(val => val.name);
+}
+exports.listEnumNames = listEnumNames;
+/**
+ * Lists the numbers of a Typescript enum.
+ *
+ * Throws if the enum does not adhere to the rules of enums generated by
+ * protobuf-ts. See `isEnumObject()`.
+ */
+function listEnumNumbers(enumObject) {
+ return listEnumValues(enumObject)
+ .map(val => val.number)
+ .filter((num, index, arr) => arr.indexOf(num) == index);
+}
+exports.listEnumNumbers = listEnumNumbers;
+
+
+/***/ }),
+
+/***/ 3223:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+// Copyright 2008 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Code generated by the Protocol Buffer compiler is owned by the owner
+// of the input file used when generating it. This code is not
+// standalone and requires a support library to be linked with it. This
+// support library is itself covered by the above license.
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.varint32read = exports.varint32write = exports.int64toString = exports.int64fromString = exports.varint64write = exports.varint64read = void 0;
+/**
+ * Read a 64 bit varint as two JS numbers.
+ *
+ * Returns tuple:
+ * [0]: low bits
+ * [0]: high bits
+ *
+ * Copyright 2008 Google Inc. All rights reserved.
+ *
+ * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L175
+ */
+function varint64read() {
+ let lowBits = 0;
+ let highBits = 0;
+ for (let shift = 0; shift < 28; shift += 7) {
+ let b = this.buf[this.pos++];
+ lowBits |= (b & 0x7F) << shift;
+ if ((b & 0x80) == 0) {
+ this.assertBounds();
+ return [lowBits, highBits];
+ }
+ }
+ let middleByte = this.buf[this.pos++];
+ // last four bits of the first 32 bit number
+ lowBits |= (middleByte & 0x0F) << 28;
+ // 3 upper bits are part of the next 32 bit number
+ highBits = (middleByte & 0x70) >> 4;
+ if ((middleByte & 0x80) == 0) {
+ this.assertBounds();
+ return [lowBits, highBits];
+ }
+ for (let shift = 3; shift <= 31; shift += 7) {
+ let b = this.buf[this.pos++];
+ highBits |= (b & 0x7F) << shift;
+ if ((b & 0x80) == 0) {
+ this.assertBounds();
+ return [lowBits, highBits];
+ }
+ }
+ throw new Error('invalid varint');
+}
+exports.varint64read = varint64read;
+/**
+ * Write a 64 bit varint, given as two JS numbers, to the given bytes array.
+ *
+ * Copyright 2008 Google Inc. All rights reserved.
+ *
+ * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/writer.js#L344
+ */
+function varint64write(lo, hi, bytes) {
+ for (let i = 0; i < 28; i = i + 7) {
+ const shift = lo >>> i;
+ const hasNext = !((shift >>> 7) == 0 && hi == 0);
+ const byte = (hasNext ? shift | 0x80 : shift) & 0xFF;
+ bytes.push(byte);
+ if (!hasNext) {
+ return;
+ }
+ }
+ const splitBits = ((lo >>> 28) & 0x0F) | ((hi & 0x07) << 4);
+ const hasMoreBits = !((hi >> 3) == 0);
+ bytes.push((hasMoreBits ? splitBits | 0x80 : splitBits) & 0xFF);
+ if (!hasMoreBits) {
+ return;
+ }
+ for (let i = 3; i < 31; i = i + 7) {
+ const shift = hi >>> i;
+ const hasNext = !((shift >>> 7) == 0);
+ const byte = (hasNext ? shift | 0x80 : shift) & 0xFF;
+ bytes.push(byte);
+ if (!hasNext) {
+ return;
+ }
+ }
+ bytes.push((hi >>> 31) & 0x01);
+}
+exports.varint64write = varint64write;
+// constants for binary math
+const TWO_PWR_32_DBL = (1 << 16) * (1 << 16);
+/**
+ * Parse decimal string of 64 bit integer value as two JS numbers.
+ *
+ * Returns tuple:
+ * [0]: minus sign?
+ * [1]: low bits
+ * [2]: high bits
+ *
+ * Copyright 2008 Google Inc.
+ */
+function int64fromString(dec) {
+ // Check for minus sign.
+ let minus = dec[0] == '-';
+ if (minus)
+ dec = dec.slice(1);
+ // Work 6 decimal digits at a time, acting like we're converting base 1e6
+ // digits to binary. This is safe to do with floating point math because
+ // Number.isSafeInteger(ALL_32_BITS * 1e6) == true.
+ const base = 1e6;
+ let lowBits = 0;
+ let highBits = 0;
+ function add1e6digit(begin, end) {
+ // Note: Number('') is 0.
+ const digit1e6 = Number(dec.slice(begin, end));
+ highBits *= base;
+ lowBits = lowBits * base + digit1e6;
+ // Carry bits from lowBits to highBits
+ if (lowBits >= TWO_PWR_32_DBL) {
+ highBits = highBits + ((lowBits / TWO_PWR_32_DBL) | 0);
+ lowBits = lowBits % TWO_PWR_32_DBL;
+ }
+ }
+ add1e6digit(-24, -18);
+ add1e6digit(-18, -12);
+ add1e6digit(-12, -6);
+ add1e6digit(-6);
+ return [minus, lowBits, highBits];
+}
+exports.int64fromString = int64fromString;
+/**
+ * Format 64 bit integer value (as two JS numbers) to decimal string.
+ *
+ * Copyright 2008 Google Inc.
+ */
+function int64toString(bitsLow, bitsHigh) {
+ // Skip the expensive conversion if the number is small enough to use the
+ // built-in conversions.
+ if ((bitsHigh >>> 0) <= 0x1FFFFF) {
+ return '' + (TWO_PWR_32_DBL * bitsHigh + (bitsLow >>> 0));
+ }
+ // What this code is doing is essentially converting the input number from
+ // base-2 to base-1e7, which allows us to represent the 64-bit range with
+ // only 3 (very large) digits. Those digits are then trivial to convert to
+ // a base-10 string.
+ // The magic numbers used here are -
+ // 2^24 = 16777216 = (1,6777216) in base-1e7.
+ // 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7.
+ // Split 32:32 representation into 16:24:24 representation so our
+ // intermediate digits don't overflow.
+ let low = bitsLow & 0xFFFFFF;
+ let mid = (((bitsLow >>> 24) | (bitsHigh << 8)) >>> 0) & 0xFFFFFF;
+ let high = (bitsHigh >> 16) & 0xFFFF;
+ // Assemble our three base-1e7 digits, ignoring carries. The maximum
+ // value in a digit at this step is representable as a 48-bit integer, which
+ // can be stored in a 64-bit floating point number.
+ let digitA = low + (mid * 6777216) + (high * 6710656);
+ let digitB = mid + (high * 8147497);
+ let digitC = (high * 2);
+ // Apply carries from A to B and from B to C.
+ let base = 10000000;
+ if (digitA >= base) {
+ digitB += Math.floor(digitA / base);
+ digitA %= base;
+ }
+ if (digitB >= base) {
+ digitC += Math.floor(digitB / base);
+ digitB %= base;
+ }
+ // Convert base-1e7 digits to base-10, with optional leading zeroes.
+ function decimalFrom1e7(digit1e7, needLeadingZeros) {
+ let partial = digit1e7 ? String(digit1e7) : '';
+ if (needLeadingZeros) {
+ return '0000000'.slice(partial.length) + partial;
+ }
+ return partial;
+ }
+ return decimalFrom1e7(digitC, /*needLeadingZeros=*/ 0) +
+ decimalFrom1e7(digitB, /*needLeadingZeros=*/ digitC) +
+ // If the final 1e7 digit didn't need leading zeros, we would have
+ // returned via the trivial code path at the top.
+ decimalFrom1e7(digitA, /*needLeadingZeros=*/ 1);
+}
+exports.int64toString = int64toString;
+/**
+ * Write a 32 bit varint, signed or unsigned. Same as `varint64write(0, value, bytes)`
+ *
+ * Copyright 2008 Google Inc. All rights reserved.
+ *
+ * See https://github.com/protocolbuffers/protobuf/blob/1b18833f4f2a2f681f4e4a25cdf3b0a43115ec26/js/binary/encoder.js#L144
+ */
+function varint32write(value, bytes) {
+ if (value >= 0) {
+ // write value as varint 32
+ while (value > 0x7f) {
+ bytes.push((value & 0x7f) | 0x80);
+ value = value >>> 7;
+ }
+ bytes.push(value);
+ }
+ else {
+ for (let i = 0; i < 9; i++) {
+ bytes.push(value & 127 | 128);
+ value = value >> 7;
+ }
+ bytes.push(1);
+ }
+}
+exports.varint32write = varint32write;
+/**
+ * Read an unsigned 32 bit varint.
+ *
+ * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L220
+ */
+function varint32read() {
+ let b = this.buf[this.pos++];
+ let result = b & 0x7F;
+ if ((b & 0x80) == 0) {
+ this.assertBounds();
+ return result;
+ }
+ b = this.buf[this.pos++];
+ result |= (b & 0x7F) << 7;
+ if ((b & 0x80) == 0) {
+ this.assertBounds();
+ return result;
+ }
+ b = this.buf[this.pos++];
+ result |= (b & 0x7F) << 14;
+ if ((b & 0x80) == 0) {
+ this.assertBounds();
+ return result;
+ }
+ b = this.buf[this.pos++];
+ result |= (b & 0x7F) << 21;
+ if ((b & 0x80) == 0) {
+ this.assertBounds();
+ return result;
+ }
+ // Extract only last 4 bits
+ b = this.buf[this.pos++];
+ result |= (b & 0x0F) << 28;
+ for (let readBytes = 5; ((b & 0x80) !== 0) && readBytes < 10; readBytes++)
+ b = this.buf[this.pos++];
+ if ((b & 0x80) != 0)
+ throw new Error('invalid varint');
+ this.assertBounds();
+ // Result can have 32 bits, convert it to unsigned
+ return result >>> 0;
+}
+exports.varint32read = varint32read;
+
+
+/***/ }),
+
+/***/ 8886:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+// Public API of the protobuf-ts runtime.
+// Note: we do not use `export * from ...` to help tree shakers,
+// webpack verbose output hints that this should be useful
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+// Convenience JSON typings and corresponding type guards
+var json_typings_1 = __webpack_require__(9999);
+Object.defineProperty(exports, "typeofJsonValue", ({ enumerable: true, get: function () { return json_typings_1.typeofJsonValue; } }));
+Object.defineProperty(exports, "isJsonObject", ({ enumerable: true, get: function () { return json_typings_1.isJsonObject; } }));
+// Base 64 encoding
+var base64_1 = __webpack_require__(6335);
+Object.defineProperty(exports, "base64decode", ({ enumerable: true, get: function () { return base64_1.base64decode; } }));
+Object.defineProperty(exports, "base64encode", ({ enumerable: true, get: function () { return base64_1.base64encode; } }));
+// UTF8 encoding
+var protobufjs_utf8_1 = __webpack_require__(8950);
+Object.defineProperty(exports, "utf8read", ({ enumerable: true, get: function () { return protobufjs_utf8_1.utf8read; } }));
+// Binary format contracts, options for reading and writing, for example
+var binary_format_contract_1 = __webpack_require__(4816);
+Object.defineProperty(exports, "WireType", ({ enumerable: true, get: function () { return binary_format_contract_1.WireType; } }));
+Object.defineProperty(exports, "mergeBinaryOptions", ({ enumerable: true, get: function () { return binary_format_contract_1.mergeBinaryOptions; } }));
+Object.defineProperty(exports, "UnknownFieldHandler", ({ enumerable: true, get: function () { return binary_format_contract_1.UnknownFieldHandler; } }));
+// Standard IBinaryReader implementation
+var binary_reader_1 = __webpack_require__(2889);
+Object.defineProperty(exports, "BinaryReader", ({ enumerable: true, get: function () { return binary_reader_1.BinaryReader; } }));
+Object.defineProperty(exports, "binaryReadOptions", ({ enumerable: true, get: function () { return binary_reader_1.binaryReadOptions; } }));
+// Standard IBinaryWriter implementation
+var binary_writer_1 = __webpack_require__(3957);
+Object.defineProperty(exports, "BinaryWriter", ({ enumerable: true, get: function () { return binary_writer_1.BinaryWriter; } }));
+Object.defineProperty(exports, "binaryWriteOptions", ({ enumerable: true, get: function () { return binary_writer_1.binaryWriteOptions; } }));
+// Int64 and UInt64 implementations required for the binary format
+var pb_long_1 = __webpack_require__(1753);
+Object.defineProperty(exports, "PbLong", ({ enumerable: true, get: function () { return pb_long_1.PbLong; } }));
+Object.defineProperty(exports, "PbULong", ({ enumerable: true, get: function () { return pb_long_1.PbULong; } }));
+// JSON format contracts, options for reading and writing, for example
+var json_format_contract_1 = __webpack_require__(9367);
+Object.defineProperty(exports, "jsonReadOptions", ({ enumerable: true, get: function () { return json_format_contract_1.jsonReadOptions; } }));
+Object.defineProperty(exports, "jsonWriteOptions", ({ enumerable: true, get: function () { return json_format_contract_1.jsonWriteOptions; } }));
+Object.defineProperty(exports, "mergeJsonOptions", ({ enumerable: true, get: function () { return json_format_contract_1.mergeJsonOptions; } }));
+// Message type contract
+var message_type_contract_1 = __webpack_require__(3785);
+Object.defineProperty(exports, "MESSAGE_TYPE", ({ enumerable: true, get: function () { return message_type_contract_1.MESSAGE_TYPE; } }));
+// Message type implementation via reflection
+var message_type_1 = __webpack_require__(5106);
+Object.defineProperty(exports, "MessageType", ({ enumerable: true, get: function () { return message_type_1.MessageType; } }));
+// Reflection info, generated by the plugin, exposed to the user, used by reflection ops
+var reflection_info_1 = __webpack_require__(7910);
+Object.defineProperty(exports, "ScalarType", ({ enumerable: true, get: function () { return reflection_info_1.ScalarType; } }));
+Object.defineProperty(exports, "LongType", ({ enumerable: true, get: function () { return reflection_info_1.LongType; } }));
+Object.defineProperty(exports, "RepeatType", ({ enumerable: true, get: function () { return reflection_info_1.RepeatType; } }));
+Object.defineProperty(exports, "normalizeFieldInfo", ({ enumerable: true, get: function () { return reflection_info_1.normalizeFieldInfo; } }));
+Object.defineProperty(exports, "readFieldOptions", ({ enumerable: true, get: function () { return reflection_info_1.readFieldOptions; } }));
+Object.defineProperty(exports, "readFieldOption", ({ enumerable: true, get: function () { return reflection_info_1.readFieldOption; } }));
+Object.defineProperty(exports, "readMessageOption", ({ enumerable: true, get: function () { return reflection_info_1.readMessageOption; } }));
+// Message operations via reflection
+var reflection_type_check_1 = __webpack_require__(5167);
+Object.defineProperty(exports, "ReflectionTypeCheck", ({ enumerable: true, get: function () { return reflection_type_check_1.ReflectionTypeCheck; } }));
+var reflection_create_1 = __webpack_require__(5726);
+Object.defineProperty(exports, "reflectionCreate", ({ enumerable: true, get: function () { return reflection_create_1.reflectionCreate; } }));
+var reflection_scalar_default_1 = __webpack_require__(9526);
+Object.defineProperty(exports, "reflectionScalarDefault", ({ enumerable: true, get: function () { return reflection_scalar_default_1.reflectionScalarDefault; } }));
+var reflection_merge_partial_1 = __webpack_require__(8044);
+Object.defineProperty(exports, "reflectionMergePartial", ({ enumerable: true, get: function () { return reflection_merge_partial_1.reflectionMergePartial; } }));
+var reflection_equals_1 = __webpack_require__(4827);
+Object.defineProperty(exports, "reflectionEquals", ({ enumerable: true, get: function () { return reflection_equals_1.reflectionEquals; } }));
+var reflection_binary_reader_1 = __webpack_require__(9611);
+Object.defineProperty(exports, "ReflectionBinaryReader", ({ enumerable: true, get: function () { return reflection_binary_reader_1.ReflectionBinaryReader; } }));
+var reflection_binary_writer_1 = __webpack_require__(6907);
+Object.defineProperty(exports, "ReflectionBinaryWriter", ({ enumerable: true, get: function () { return reflection_binary_writer_1.ReflectionBinaryWriter; } }));
+var reflection_json_reader_1 = __webpack_require__(6790);
+Object.defineProperty(exports, "ReflectionJsonReader", ({ enumerable: true, get: function () { return reflection_json_reader_1.ReflectionJsonReader; } }));
+var reflection_json_writer_1 = __webpack_require__(1094);
+Object.defineProperty(exports, "ReflectionJsonWriter", ({ enumerable: true, get: function () { return reflection_json_writer_1.ReflectionJsonWriter; } }));
+var reflection_contains_message_type_1 = __webpack_require__(9946);
+Object.defineProperty(exports, "containsMessageType", ({ enumerable: true, get: function () { return reflection_contains_message_type_1.containsMessageType; } }));
+// Oneof helpers
+var oneof_1 = __webpack_require__(8063);
+Object.defineProperty(exports, "isOneofGroup", ({ enumerable: true, get: function () { return oneof_1.isOneofGroup; } }));
+Object.defineProperty(exports, "setOneofValue", ({ enumerable: true, get: function () { return oneof_1.setOneofValue; } }));
+Object.defineProperty(exports, "getOneofValue", ({ enumerable: true, get: function () { return oneof_1.getOneofValue; } }));
+Object.defineProperty(exports, "clearOneofValue", ({ enumerable: true, get: function () { return oneof_1.clearOneofValue; } }));
+Object.defineProperty(exports, "getSelectedOneofValue", ({ enumerable: true, get: function () { return oneof_1.getSelectedOneofValue; } }));
+// Enum object type guard and reflection util, may be interesting to the user.
+var enum_object_1 = __webpack_require__(257);
+Object.defineProperty(exports, "listEnumValues", ({ enumerable: true, get: function () { return enum_object_1.listEnumValues; } }));
+Object.defineProperty(exports, "listEnumNames", ({ enumerable: true, get: function () { return enum_object_1.listEnumNames; } }));
+Object.defineProperty(exports, "listEnumNumbers", ({ enumerable: true, get: function () { return enum_object_1.listEnumNumbers; } }));
+Object.defineProperty(exports, "isEnumObject", ({ enumerable: true, get: function () { return enum_object_1.isEnumObject; } }));
+// lowerCamelCase() is exported for plugin, rpc-runtime and other rpc packages
+var lower_camel_case_1 = __webpack_require__(4073);
+Object.defineProperty(exports, "lowerCamelCase", ({ enumerable: true, get: function () { return lower_camel_case_1.lowerCamelCase; } }));
+// assertion functions are exported for plugin, may also be useful to user
+var assert_1 = __webpack_require__(8602);
+Object.defineProperty(exports, "assert", ({ enumerable: true, get: function () { return assert_1.assert; } }));
+Object.defineProperty(exports, "assertNever", ({ enumerable: true, get: function () { return assert_1.assertNever; } }));
+Object.defineProperty(exports, "assertInt32", ({ enumerable: true, get: function () { return assert_1.assertInt32; } }));
+Object.defineProperty(exports, "assertUInt32", ({ enumerable: true, get: function () { return assert_1.assertUInt32; } }));
+Object.defineProperty(exports, "assertFloat32", ({ enumerable: true, get: function () { return assert_1.assertFloat32; } }));
+
+
+/***/ }),
+
+/***/ 9367:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.mergeJsonOptions = exports.jsonWriteOptions = exports.jsonReadOptions = void 0;
+const defaultsWrite = {
+ emitDefaultValues: false,
+ enumAsInteger: false,
+ useProtoFieldName: false,
+ prettySpaces: 0,
+}, defaultsRead = {
+ ignoreUnknownFields: false,
+};
+/**
+ * Make options for reading JSON data from partial options.
+ */
+function jsonReadOptions(options) {
+ return options ? Object.assign(Object.assign({}, defaultsRead), options) : defaultsRead;
+}
+exports.jsonReadOptions = jsonReadOptions;
+/**
+ * Make options for writing JSON data from partial options.
+ */
+function jsonWriteOptions(options) {
+ return options ? Object.assign(Object.assign({}, defaultsWrite), options) : defaultsWrite;
+}
+exports.jsonWriteOptions = jsonWriteOptions;
+/**
+ * Merges JSON write or read options. Later values override earlier values. Type registries are merged.
+ */
+function mergeJsonOptions(a, b) {
+ var _a, _b;
+ let c = Object.assign(Object.assign({}, a), b);
+ c.typeRegistry = [...((_a = a === null || a === void 0 ? void 0 : a.typeRegistry) !== null && _a !== void 0 ? _a : []), ...((_b = b === null || b === void 0 ? void 0 : b.typeRegistry) !== null && _b !== void 0 ? _b : [])];
+ return c;
+}
+exports.mergeJsonOptions = mergeJsonOptions;
+
+
+/***/ }),
+
+/***/ 9999:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.isJsonObject = exports.typeofJsonValue = void 0;
+/**
+ * Get the type of a JSON value.
+ * Distinguishes between array, null and object.
+ */
+function typeofJsonValue(value) {
+ let t = typeof value;
+ if (t == "object") {
+ if (Array.isArray(value))
+ return "array";
+ if (value === null)
+ return "null";
+ }
+ return t;
+}
+exports.typeofJsonValue = typeofJsonValue;
+/**
+ * Is this a JSON object (instead of an array or null)?
+ */
+function isJsonObject(value) {
+ return value !== null && typeof value == "object" && !Array.isArray(value);
+}
+exports.isJsonObject = isJsonObject;
+
+
+/***/ }),
+
+/***/ 4073:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.lowerCamelCase = void 0;
+/**
+ * Converts snake_case to lowerCamelCase.
+ *
+ * Should behave like protoc:
+ * https://github.com/protocolbuffers/protobuf/blob/e8ae137c96444ea313485ed1118c5e43b2099cf1/src/google/protobuf/compiler/java/java_helpers.cc#L118
+ */
+function lowerCamelCase(snakeCase) {
+ let capNext = false;
+ const sb = [];
+ for (let i = 0; i < snakeCase.length; i++) {
+ let next = snakeCase.charAt(i);
+ if (next == '_') {
+ capNext = true;
+ }
+ else if (/\d/.test(next)) {
+ sb.push(next);
+ capNext = true;
+ }
+ else if (capNext) {
+ sb.push(next.toUpperCase());
+ capNext = false;
+ }
+ else if (i == 0) {
+ sb.push(next.toLowerCase());
+ }
+ else {
+ sb.push(next);
+ }
+ }
+ return sb.join('');
+}
+exports.lowerCamelCase = lowerCamelCase;
+
+
+/***/ }),
+
+/***/ 3785:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.MESSAGE_TYPE = void 0;
+/**
+ * The symbol used as a key on message objects to store the message type.
+ *
+ * Note that this is an experimental feature - it is here to stay, but
+ * implementation details may change without notice.
+ */
+exports.MESSAGE_TYPE = Symbol.for("protobuf-ts/message-type");
+
+
+/***/ }),
+
+/***/ 5106:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.MessageType = void 0;
+const message_type_contract_1 = __webpack_require__(3785);
+const reflection_info_1 = __webpack_require__(7910);
+const reflection_type_check_1 = __webpack_require__(5167);
+const reflection_json_reader_1 = __webpack_require__(6790);
+const reflection_json_writer_1 = __webpack_require__(1094);
+const reflection_binary_reader_1 = __webpack_require__(9611);
+const reflection_binary_writer_1 = __webpack_require__(6907);
+const reflection_create_1 = __webpack_require__(5726);
+const reflection_merge_partial_1 = __webpack_require__(8044);
+const json_typings_1 = __webpack_require__(9999);
+const json_format_contract_1 = __webpack_require__(9367);
+const reflection_equals_1 = __webpack_require__(4827);
+const binary_writer_1 = __webpack_require__(3957);
+const binary_reader_1 = __webpack_require__(2889);
+const baseDescriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf({}));
+const messageTypeDescriptor = baseDescriptors[message_type_contract_1.MESSAGE_TYPE] = {};
+/**
+ * This standard message type provides reflection-based
+ * operations to work with a message.
+ */
+class MessageType {
+ constructor(name, fields, options) {
+ this.defaultCheckDepth = 16;
+ this.typeName = name;
+ this.fields = fields.map(reflection_info_1.normalizeFieldInfo);
+ this.options = options !== null && options !== void 0 ? options : {};
+ messageTypeDescriptor.value = this;
+ this.messagePrototype = Object.create(null, baseDescriptors);
+ this.refTypeCheck = new reflection_type_check_1.ReflectionTypeCheck(this);
+ this.refJsonReader = new reflection_json_reader_1.ReflectionJsonReader(this);
+ this.refJsonWriter = new reflection_json_writer_1.ReflectionJsonWriter(this);
+ this.refBinReader = new reflection_binary_reader_1.ReflectionBinaryReader(this);
+ this.refBinWriter = new reflection_binary_writer_1.ReflectionBinaryWriter(this);
+ }
+ create(value) {
+ let message = reflection_create_1.reflectionCreate(this);
+ if (value !== undefined) {
+ reflection_merge_partial_1.reflectionMergePartial(this, message, value);
+ }
+ return message;
+ }
+ /**
+ * Clone the message.
+ *
+ * Unknown fields are discarded.
+ */
+ clone(message) {
+ let copy = this.create();
+ reflection_merge_partial_1.reflectionMergePartial(this, copy, message);
+ return copy;
+ }
+ /**
+ * Determines whether two message of the same type have the same field values.
+ * Checks for deep equality, traversing repeated fields, oneof groups, maps
+ * and messages recursively.
+ * Will also return true if both messages are `undefined`.
+ */
+ equals(a, b) {
+ return reflection_equals_1.reflectionEquals(this, a, b);
+ }
+ /**
+ * Is the given value assignable to our message type
+ * and contains no [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)?
+ */
+ is(arg, depth = this.defaultCheckDepth) {
+ return this.refTypeCheck.is(arg, depth, false);
+ }
+ /**
+ * Is the given value assignable to our message type,
+ * regardless of [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)?
+ */
+ isAssignable(arg, depth = this.defaultCheckDepth) {
+ return this.refTypeCheck.is(arg, depth, true);
+ }
+ /**
+ * Copy partial data into the target message.
+ */
+ mergePartial(target, source) {
+ reflection_merge_partial_1.reflectionMergePartial(this, target, source);
+ }
+ /**
+ * Create a new message from binary format.
+ */
+ fromBinary(data, options) {
+ let opt = binary_reader_1.binaryReadOptions(options);
+ return this.internalBinaryRead(opt.readerFactory(data), data.byteLength, opt);
+ }
+ /**
+ * Read a new message from a JSON value.
+ */
+ fromJson(json, options) {
+ return this.internalJsonRead(json, json_format_contract_1.jsonReadOptions(options));
+ }
+ /**
+ * Read a new message from a JSON string.
+ * This is equivalent to `T.fromJson(JSON.parse(json))`.
+ */
+ fromJsonString(json, options) {
+ let value = JSON.parse(json);
+ return this.fromJson(value, options);
+ }
+ /**
+ * Write the message to canonical JSON value.
+ */
+ toJson(message, options) {
+ return this.internalJsonWrite(message, json_format_contract_1.jsonWriteOptions(options));
+ }
+ /**
+ * Convert the message to canonical JSON string.
+ * This is equivalent to `JSON.stringify(T.toJson(t))`
+ */
+ toJsonString(message, options) {
+ var _a;
+ let value = this.toJson(message, options);
+ return JSON.stringify(value, null, (_a = options === null || options === void 0 ? void 0 : options.prettySpaces) !== null && _a !== void 0 ? _a : 0);
+ }
+ /**
+ * Write the message to binary format.
+ */
+ toBinary(message, options) {
+ let opt = binary_writer_1.binaryWriteOptions(options);
+ return this.internalBinaryWrite(message, opt.writerFactory(), opt).finish();
+ }
+ /**
+ * This is an internal method. If you just want to read a message from
+ * JSON, use `fromJson()` or `fromJsonString()`.
+ *
+ * Reads JSON value and merges the fields into the target
+ * according to protobuf rules. If the target is omitted,
+ * a new instance is created first.
+ */
+ internalJsonRead(json, options, target) {
+ if (json !== null && typeof json == "object" && !Array.isArray(json)) {
+ let message = target !== null && target !== void 0 ? target : this.create();
+ this.refJsonReader.read(json, message, options);
+ return message;
+ }
+ throw new Error(`Unable to parse message ${this.typeName} from JSON ${json_typings_1.typeofJsonValue(json)}.`);
+ }
+ /**
+ * This is an internal method. If you just want to write a message
+ * to JSON, use `toJson()` or `toJsonString().
+ *
+ * Writes JSON value and returns it.
+ */
+ internalJsonWrite(message, options) {
+ return this.refJsonWriter.write(message, options);
+ }
+ /**
+ * This is an internal method. If you just want to write a message
+ * in binary format, use `toBinary()`.
+ *
+ * Serializes the message in binary format and appends it to the given
+ * writer. Returns passed writer.
+ */
+ internalBinaryWrite(message, writer, options) {
+ this.refBinWriter.write(message, writer, options);
+ return writer;
+ }
+ /**
+ * This is an internal method. If you just want to read a message from
+ * binary data, use `fromBinary()`.
+ *
+ * Reads data from binary format and merges the fields into
+ * the target according to protobuf rules. If the target is
+ * omitted, a new instance is created first.
+ */
+ internalBinaryRead(reader, length, options, target) {
+ let message = target !== null && target !== void 0 ? target : this.create();
+ this.refBinReader.read(reader, message, options, length);
+ return message;
+ }
+}
+exports.MessageType = MessageType;
+
+
+/***/ }),
+
+/***/ 8063:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.getSelectedOneofValue = exports.clearOneofValue = exports.setUnknownOneofValue = exports.setOneofValue = exports.getOneofValue = exports.isOneofGroup = void 0;
+/**
+ * Is the given value a valid oneof group?
+ *
+ * We represent protobuf `oneof` as algebraic data types (ADT) in generated
+ * code. But when working with messages of unknown type, the ADT does not
+ * help us.
+ *
+ * This type guard checks if the given object adheres to the ADT rules, which
+ * are as follows:
+ *
+ * 1) Must be an object.
+ *
+ * 2) Must have a "oneofKind" discriminator property.
+ *
+ * 3) If "oneofKind" is `undefined`, no member field is selected. The object
+ * must not have any other properties.
+ *
+ * 4) If "oneofKind" is a `string`, the member field with this name is
+ * selected.
+ *
+ * 5) If a member field is selected, the object must have a second property
+ * with this name. The property must not be `undefined`.
+ *
+ * 6) No extra properties are allowed. The object has either one property
+ * (no selection) or two properties (selection).
+ *
+ */
+function isOneofGroup(any) {
+ if (typeof any != 'object' || any === null || !any.hasOwnProperty('oneofKind')) {
+ return false;
+ }
+ switch (typeof any.oneofKind) {
+ case "string":
+ if (any[any.oneofKind] === undefined)
+ return false;
+ return Object.keys(any).length == 2;
+ case "undefined":
+ return Object.keys(any).length == 1;
+ default:
+ return false;
+ }
+}
+exports.isOneofGroup = isOneofGroup;
+/**
+ * Returns the value of the given field in a oneof group.
+ */
+function getOneofValue(oneof, kind) {
+ return oneof[kind];
+}
+exports.getOneofValue = getOneofValue;
+function setOneofValue(oneof, kind, value) {
+ if (oneof.oneofKind !== undefined) {
+ delete oneof[oneof.oneofKind];
+ }
+ oneof.oneofKind = kind;
+ if (value !== undefined) {
+ oneof[kind] = value;
+ }
+}
+exports.setOneofValue = setOneofValue;
+function setUnknownOneofValue(oneof, kind, value) {
+ if (oneof.oneofKind !== undefined) {
+ delete oneof[oneof.oneofKind];
+ }
+ oneof.oneofKind = kind;
+ if (value !== undefined && kind !== undefined) {
+ oneof[kind] = value;
+ }
+}
+exports.setUnknownOneofValue = setUnknownOneofValue;
+/**
+ * Removes the selected field in a oneof group.
+ *
+ * Note that the recommended way to modify a oneof group is to set
+ * a new object:
+ *
+ * ```ts
+ * message.result = { oneofKind: undefined };
+ * ```
+ */
+function clearOneofValue(oneof) {
+ if (oneof.oneofKind !== undefined) {
+ delete oneof[oneof.oneofKind];
+ }
+ oneof.oneofKind = undefined;
+}
+exports.clearOneofValue = clearOneofValue;
+/**
+ * Returns the selected value of the given oneof group.
+ *
+ * Not that the recommended way to access a oneof group is to check
+ * the "oneofKind" property and let TypeScript narrow down the union
+ * type for you:
+ *
+ * ```ts
+ * if (message.result.oneofKind === "error") {
+ * message.result.error; // string
+ * }
+ * ```
+ *
+ * In the rare case you just need the value, and do not care about
+ * which protobuf field is selected, you can use this function
+ * for convenience.
+ */
+function getSelectedOneofValue(oneof) {
+ if (oneof.oneofKind === undefined) {
+ return undefined;
+ }
+ return oneof[oneof.oneofKind];
+}
+exports.getSelectedOneofValue = getSelectedOneofValue;
+
+
+/***/ }),
+
+/***/ 1753:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PbLong = exports.PbULong = exports.detectBi = void 0;
+const goog_varint_1 = __webpack_require__(3223);
+let BI;
+function detectBi() {
+ const dv = new DataView(new ArrayBuffer(8));
+ const ok = globalThis.BigInt !== undefined
+ && typeof dv.getBigInt64 === "function"
+ && typeof dv.getBigUint64 === "function"
+ && typeof dv.setBigInt64 === "function"
+ && typeof dv.setBigUint64 === "function";
+ BI = ok ? {
+ MIN: BigInt("-9223372036854775808"),
+ MAX: BigInt("9223372036854775807"),
+ UMIN: BigInt("0"),
+ UMAX: BigInt("18446744073709551615"),
+ C: BigInt,
+ V: dv,
+ } : undefined;
+}
+exports.detectBi = detectBi;
+detectBi();
+function assertBi(bi) {
+ if (!bi)
+ throw new Error("BigInt unavailable, see https://github.com/timostamm/protobuf-ts/blob/v1.0.8/MANUAL.md#bigint-support");
+}
+// used to validate from(string) input (when bigint is unavailable)
+const RE_DECIMAL_STR = /^-?[0-9]+$/;
+// constants for binary math
+const TWO_PWR_32_DBL = 0x100000000;
+const HALF_2_PWR_32 = 0x080000000;
+// base class for PbLong and PbULong provides shared code
+class SharedPbLong {
+ /**
+ * Create a new instance with the given bits.
+ */
+ constructor(lo, hi) {
+ this.lo = lo | 0;
+ this.hi = hi | 0;
+ }
+ /**
+ * Is this instance equal to 0?
+ */
+ isZero() {
+ return this.lo == 0 && this.hi == 0;
+ }
+ /**
+ * Convert to a native number.
+ */
+ toNumber() {
+ let result = this.hi * TWO_PWR_32_DBL + (this.lo >>> 0);
+ if (!Number.isSafeInteger(result))
+ throw new Error("cannot convert to safe number");
+ return result;
+ }
+}
+/**
+ * 64-bit unsigned integer as two 32-bit values.
+ * Converts between `string`, `number` and `bigint` representations.
+ */
+class PbULong extends SharedPbLong {
+ /**
+ * Create instance from a `string`, `number` or `bigint`.
+ */
+ static from(value) {
+ if (BI)
+ // noinspection FallThroughInSwitchStatementJS
+ switch (typeof value) {
+ case "string":
+ if (value == "0")
+ return this.ZERO;
+ if (value == "")
+ throw new Error('string is no integer');
+ value = BI.C(value);
+ case "number":
+ if (value === 0)
+ return this.ZERO;
+ value = BI.C(value);
+ case "bigint":
+ if (!value)
+ return this.ZERO;
+ if (value < BI.UMIN)
+ throw new Error('signed value for ulong');
+ if (value > BI.UMAX)
+ throw new Error('ulong too large');
+ BI.V.setBigUint64(0, value, true);
+ return new PbULong(BI.V.getInt32(0, true), BI.V.getInt32(4, true));
+ }
+ else
+ switch (typeof value) {
+ case "string":
+ if (value == "0")
+ return this.ZERO;
+ value = value.trim();
+ if (!RE_DECIMAL_STR.test(value))
+ throw new Error('string is no integer');
+ let [minus, lo, hi] = goog_varint_1.int64fromString(value);
+ if (minus)
+ throw new Error('signed value for ulong');
+ return new PbULong(lo, hi);
+ case "number":
+ if (value == 0)
+ return this.ZERO;
+ if (!Number.isSafeInteger(value))
+ throw new Error('number is no integer');
+ if (value < 0)
+ throw new Error('signed value for ulong');
+ return new PbULong(value, value / TWO_PWR_32_DBL);
+ }
+ throw new Error('unknown value ' + typeof value);
+ }
+ /**
+ * Convert to decimal string.
+ */
+ toString() {
+ return BI ? this.toBigInt().toString() : goog_varint_1.int64toString(this.lo, this.hi);
+ }
+ /**
+ * Convert to native bigint.
+ */
+ toBigInt() {
+ assertBi(BI);
+ BI.V.setInt32(0, this.lo, true);
+ BI.V.setInt32(4, this.hi, true);
+ return BI.V.getBigUint64(0, true);
+ }
+}
+exports.PbULong = PbULong;
+/**
+ * ulong 0 singleton.
+ */
+PbULong.ZERO = new PbULong(0, 0);
+/**
+ * 64-bit signed integer as two 32-bit values.
+ * Converts between `string`, `number` and `bigint` representations.
+ */
+class PbLong extends SharedPbLong {
+ /**
+ * Create instance from a `string`, `number` or `bigint`.
+ */
+ static from(value) {
+ if (BI)
+ // noinspection FallThroughInSwitchStatementJS
+ switch (typeof value) {
+ case "string":
+ if (value == "0")
+ return this.ZERO;
+ if (value == "")
+ throw new Error('string is no integer');
+ value = BI.C(value);
+ case "number":
+ if (value === 0)
+ return this.ZERO;
+ value = BI.C(value);
+ case "bigint":
+ if (!value)
+ return this.ZERO;
+ if (value < BI.MIN)
+ throw new Error('signed long too small');
+ if (value > BI.MAX)
+ throw new Error('signed long too large');
+ BI.V.setBigInt64(0, value, true);
+ return new PbLong(BI.V.getInt32(0, true), BI.V.getInt32(4, true));
+ }
+ else
+ switch (typeof value) {
+ case "string":
+ if (value == "0")
+ return this.ZERO;
+ value = value.trim();
+ if (!RE_DECIMAL_STR.test(value))
+ throw new Error('string is no integer');
+ let [minus, lo, hi] = goog_varint_1.int64fromString(value);
+ if (minus) {
+ if (hi > HALF_2_PWR_32 || (hi == HALF_2_PWR_32 && lo != 0))
+ throw new Error('signed long too small');
+ }
+ else if (hi >= HALF_2_PWR_32)
+ throw new Error('signed long too large');
+ let pbl = new PbLong(lo, hi);
+ return minus ? pbl.negate() : pbl;
+ case "number":
+ if (value == 0)
+ return this.ZERO;
+ if (!Number.isSafeInteger(value))
+ throw new Error('number is no integer');
+ return value > 0
+ ? new PbLong(value, value / TWO_PWR_32_DBL)
+ : new PbLong(-value, -value / TWO_PWR_32_DBL).negate();
+ }
+ throw new Error('unknown value ' + typeof value);
+ }
+ /**
+ * Do we have a minus sign?
+ */
+ isNegative() {
+ return (this.hi & HALF_2_PWR_32) !== 0;
+ }
+ /**
+ * Negate two's complement.
+ * Invert all the bits and add one to the result.
+ */
+ negate() {
+ let hi = ~this.hi, lo = this.lo;
+ if (lo)
+ lo = ~lo + 1;
+ else
+ hi += 1;
+ return new PbLong(lo, hi);
+ }
+ /**
+ * Convert to decimal string.
+ */
+ toString() {
+ if (BI)
+ return this.toBigInt().toString();
+ if (this.isNegative()) {
+ let n = this.negate();
+ return '-' + goog_varint_1.int64toString(n.lo, n.hi);
+ }
+ return goog_varint_1.int64toString(this.lo, this.hi);
+ }
+ /**
+ * Convert to native bigint.
+ */
+ toBigInt() {
+ assertBi(BI);
+ BI.V.setInt32(0, this.lo, true);
+ BI.V.setInt32(4, this.hi, true);
+ return BI.V.getBigInt64(0, true);
+ }
+}
+exports.PbLong = PbLong;
+/**
+ * long 0 singleton.
+ */
+PbLong.ZERO = new PbLong(0, 0);
+
+
+/***/ }),
+
+/***/ 8950:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+// Copyright (c) 2016, Daniel Wirtz All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of its author, nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.utf8read = void 0;
+const fromCharCodes = (chunk) => String.fromCharCode.apply(String, chunk);
+/**
+ * @deprecated This function will no longer be exported with the next major
+ * release, since protobuf-ts has switch to TextDecoder API. If you need this
+ * function, please migrate to @protobufjs/utf8. For context, see
+ * https://github.com/timostamm/protobuf-ts/issues/184
+ *
+ * Reads UTF8 bytes as a string.
+ *
+ * See [protobufjs / utf8](https://github.com/protobufjs/protobuf.js/blob/9893e35b854621cce64af4bf6be2cff4fb892796/lib/utf8/index.js#L40)
+ *
+ * Copyright (c) 2016, Daniel Wirtz
+ */
+function utf8read(bytes) {
+ if (bytes.length < 1)
+ return "";
+ let pos = 0, // position in bytes
+ parts = [], chunk = [], i = 0, // char offset
+ t; // temporary
+ let len = bytes.length;
+ while (pos < len) {
+ t = bytes[pos++];
+ if (t < 128)
+ chunk[i++] = t;
+ else if (t > 191 && t < 224)
+ chunk[i++] = (t & 31) << 6 | bytes[pos++] & 63;
+ else if (t > 239 && t < 365) {
+ t = ((t & 7) << 18 | (bytes[pos++] & 63) << 12 | (bytes[pos++] & 63) << 6 | bytes[pos++] & 63) - 0x10000;
+ chunk[i++] = 0xD800 + (t >> 10);
+ chunk[i++] = 0xDC00 + (t & 1023);
+ }
+ else
+ chunk[i++] = (t & 15) << 12 | (bytes[pos++] & 63) << 6 | bytes[pos++] & 63;
+ if (i > 8191) {
+ parts.push(fromCharCodes(chunk));
+ i = 0;
+ }
+ }
+ if (parts.length) {
+ if (i)
+ parts.push(fromCharCodes(chunk.slice(0, i)));
+ return parts.join("");
+ }
+ return fromCharCodes(chunk.slice(0, i));
+}
+exports.utf8read = utf8read;
+
+
+/***/ }),
+
+/***/ 9611:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ReflectionBinaryReader = void 0;
+const binary_format_contract_1 = __webpack_require__(4816);
+const reflection_info_1 = __webpack_require__(7910);
+const reflection_long_convert_1 = __webpack_require__(3402);
+const reflection_scalar_default_1 = __webpack_require__(9526);
+/**
+ * Reads proto3 messages in binary format using reflection information.
+ *
+ * https://developers.google.com/protocol-buffers/docs/encoding
+ */
+class ReflectionBinaryReader {
+ constructor(info) {
+ this.info = info;
+ }
+ prepare() {
+ var _a;
+ if (!this.fieldNoToField) {
+ const fieldsInput = (_a = this.info.fields) !== null && _a !== void 0 ? _a : [];
+ this.fieldNoToField = new Map(fieldsInput.map(field => [field.no, field]));
+ }
+ }
+ /**
+ * Reads a message from binary format into the target message.
+ *
+ * Repeated fields are appended. Map entries are added, overwriting
+ * existing keys.
+ *
+ * If a message field is already present, it will be merged with the
+ * new data.
+ */
+ read(reader, message, options, length) {
+ this.prepare();
+ const end = length === undefined ? reader.len : reader.pos + length;
+ while (reader.pos < end) {
+ // read the tag and find the field
+ const [fieldNo, wireType] = reader.tag(), field = this.fieldNoToField.get(fieldNo);
+ if (!field) {
+ let u = options.readUnknownField;
+ if (u == "throw")
+ throw new Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.info.typeName}`);
+ let d = reader.skip(wireType);
+ if (u !== false)
+ (u === true ? binary_format_contract_1.UnknownFieldHandler.onRead : u)(this.info.typeName, message, fieldNo, wireType, d);
+ continue;
+ }
+ // target object for the field we are reading
+ let target = message, repeated = field.repeat, localName = field.localName;
+ // if field is member of oneof ADT, use ADT as target
+ if (field.oneof) {
+ target = target[field.oneof];
+ // if other oneof member selected, set new ADT
+ if (target.oneofKind !== localName)
+ target = message[field.oneof] = {
+ oneofKind: localName
+ };
+ }
+ // we have handled oneof above, we just have read the value into `target[localName]`
+ switch (field.kind) {
+ case "scalar":
+ case "enum":
+ let T = field.kind == "enum" ? reflection_info_1.ScalarType.INT32 : field.T;
+ let L = field.kind == "scalar" ? field.L : undefined;
+ if (repeated) {
+ let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values
+ if (wireType == binary_format_contract_1.WireType.LengthDelimited && T != reflection_info_1.ScalarType.STRING && T != reflection_info_1.ScalarType.BYTES) {
+ let e = reader.uint32() + reader.pos;
+ while (reader.pos < e)
+ arr.push(this.scalar(reader, T, L));
+ }
+ else
+ arr.push(this.scalar(reader, T, L));
+ }
+ else
+ target[localName] = this.scalar(reader, T, L);
+ break;
+ case "message":
+ if (repeated) {
+ let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values
+ let msg = field.T().internalBinaryRead(reader, reader.uint32(), options);
+ arr.push(msg);
+ }
+ else
+ target[localName] = field.T().internalBinaryRead(reader, reader.uint32(), options, target[localName]);
+ break;
+ case "map":
+ let [mapKey, mapVal] = this.mapEntry(field, reader, options);
+ // safe to assume presence of map object, oneof cannot contain repeated values
+ target[localName][mapKey] = mapVal;
+ break;
+ }
+ }
+ }
+ /**
+ * Read a map field, expecting key field = 1, value field = 2
+ */
+ mapEntry(field, reader, options) {
+ let length = reader.uint32();
+ let end = reader.pos + length;
+ let key = undefined; // javascript only allows number or string for object properties
+ let val = undefined;
+ while (reader.pos < end) {
+ let [fieldNo, wireType] = reader.tag();
+ switch (fieldNo) {
+ case 1:
+ if (field.K == reflection_info_1.ScalarType.BOOL)
+ key = reader.bool().toString();
+ else
+ // long types are read as string, number types are okay as number
+ key = this.scalar(reader, field.K, reflection_info_1.LongType.STRING);
+ break;
+ case 2:
+ switch (field.V.kind) {
+ case "scalar":
+ val = this.scalar(reader, field.V.T, field.V.L);
+ break;
+ case "enum":
+ val = reader.int32();
+ break;
+ case "message":
+ val = field.V.T().internalBinaryRead(reader, reader.uint32(), options);
+ break;
+ }
+ break;
+ default:
+ throw new Error(`Unknown field ${fieldNo} (wire type ${wireType}) in map entry for ${this.info.typeName}#${field.name}`);
+ }
+ }
+ if (key === undefined) {
+ let keyRaw = reflection_scalar_default_1.reflectionScalarDefault(field.K);
+ key = field.K == reflection_info_1.ScalarType.BOOL ? keyRaw.toString() : keyRaw;
+ }
+ if (val === undefined)
+ switch (field.V.kind) {
+ case "scalar":
+ val = reflection_scalar_default_1.reflectionScalarDefault(field.V.T, field.V.L);
+ break;
+ case "enum":
+ val = 0;
+ break;
+ case "message":
+ val = field.V.T().create();
+ break;
+ }
+ return [key, val];
+ }
+ scalar(reader, type, longType) {
+ switch (type) {
+ case reflection_info_1.ScalarType.INT32:
+ return reader.int32();
+ case reflection_info_1.ScalarType.STRING:
+ return reader.string();
+ case reflection_info_1.ScalarType.BOOL:
+ return reader.bool();
+ case reflection_info_1.ScalarType.DOUBLE:
+ return reader.double();
+ case reflection_info_1.ScalarType.FLOAT:
+ return reader.float();
+ case reflection_info_1.ScalarType.INT64:
+ return reflection_long_convert_1.reflectionLongConvert(reader.int64(), longType);
+ case reflection_info_1.ScalarType.UINT64:
+ return reflection_long_convert_1.reflectionLongConvert(reader.uint64(), longType);
+ case reflection_info_1.ScalarType.FIXED64:
+ return reflection_long_convert_1.reflectionLongConvert(reader.fixed64(), longType);
+ case reflection_info_1.ScalarType.FIXED32:
+ return reader.fixed32();
+ case reflection_info_1.ScalarType.BYTES:
+ return reader.bytes();
+ case reflection_info_1.ScalarType.UINT32:
+ return reader.uint32();
+ case reflection_info_1.ScalarType.SFIXED32:
+ return reader.sfixed32();
+ case reflection_info_1.ScalarType.SFIXED64:
+ return reflection_long_convert_1.reflectionLongConvert(reader.sfixed64(), longType);
+ case reflection_info_1.ScalarType.SINT32:
+ return reader.sint32();
+ case reflection_info_1.ScalarType.SINT64:
+ return reflection_long_convert_1.reflectionLongConvert(reader.sint64(), longType);
+ }
+ }
+}
+exports.ReflectionBinaryReader = ReflectionBinaryReader;
+
+
+/***/ }),
+
+/***/ 6907:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ReflectionBinaryWriter = void 0;
+const binary_format_contract_1 = __webpack_require__(4816);
+const reflection_info_1 = __webpack_require__(7910);
+const assert_1 = __webpack_require__(8602);
+const pb_long_1 = __webpack_require__(1753);
+/**
+ * Writes proto3 messages in binary format using reflection information.
+ *
+ * https://developers.google.com/protocol-buffers/docs/encoding
+ */
+class ReflectionBinaryWriter {
+ constructor(info) {
+ this.info = info;
+ }
+ prepare() {
+ if (!this.fields) {
+ const fieldsInput = this.info.fields ? this.info.fields.concat() : [];
+ this.fields = fieldsInput.sort((a, b) => a.no - b.no);
+ }
+ }
+ /**
+ * Writes the message to binary format.
+ */
+ write(message, writer, options) {
+ this.prepare();
+ for (const field of this.fields) {
+ let value, // this will be our field value, whether it is member of a oneof or not
+ emitDefault, // whether we emit the default value (only true for oneof members)
+ repeated = field.repeat, localName = field.localName;
+ // handle oneof ADT
+ if (field.oneof) {
+ const group = message[field.oneof];
+ if (group.oneofKind !== localName)
+ continue; // if field is not selected, skip
+ value = group[localName];
+ emitDefault = true;
+ }
+ else {
+ value = message[localName];
+ emitDefault = false;
+ }
+ // we have handled oneof above. we just have to honor `emitDefault`.
+ switch (field.kind) {
+ case "scalar":
+ case "enum":
+ let T = field.kind == "enum" ? reflection_info_1.ScalarType.INT32 : field.T;
+ if (repeated) {
+ assert_1.assert(Array.isArray(value));
+ if (repeated == reflection_info_1.RepeatType.PACKED)
+ this.packed(writer, T, field.no, value);
+ else
+ for (const item of value)
+ this.scalar(writer, T, field.no, item, true);
+ }
+ else if (value === undefined)
+ assert_1.assert(field.opt);
+ else
+ this.scalar(writer, T, field.no, value, emitDefault || field.opt);
+ break;
+ case "message":
+ if (repeated) {
+ assert_1.assert(Array.isArray(value));
+ for (const item of value)
+ this.message(writer, options, field.T(), field.no, item);
+ }
+ else {
+ this.message(writer, options, field.T(), field.no, value);
+ }
+ break;
+ case "map":
+ assert_1.assert(typeof value == 'object' && value !== null);
+ for (const [key, val] of Object.entries(value))
+ this.mapEntry(writer, options, field, key, val);
+ break;
+ }
+ }
+ let u = options.writeUnknownFields;
+ if (u !== false)
+ (u === true ? binary_format_contract_1.UnknownFieldHandler.onWrite : u)(this.info.typeName, message, writer);
+ }
+ mapEntry(writer, options, field, key, value) {
+ writer.tag(field.no, binary_format_contract_1.WireType.LengthDelimited);
+ writer.fork();
+ // javascript only allows number or string for object properties
+ // we convert from our representation to the protobuf type
+ let keyValue = key;
+ switch (field.K) {
+ case reflection_info_1.ScalarType.INT32:
+ case reflection_info_1.ScalarType.FIXED32:
+ case reflection_info_1.ScalarType.UINT32:
+ case reflection_info_1.ScalarType.SFIXED32:
+ case reflection_info_1.ScalarType.SINT32:
+ keyValue = Number.parseInt(key);
+ break;
+ case reflection_info_1.ScalarType.BOOL:
+ assert_1.assert(key == 'true' || key == 'false');
+ keyValue = key == 'true';
+ break;
+ }
+ // write key, expecting key field number = 1
+ this.scalar(writer, field.K, 1, keyValue, true);
+ // write value, expecting value field number = 2
+ switch (field.V.kind) {
+ case 'scalar':
+ this.scalar(writer, field.V.T, 2, value, true);
+ break;
+ case 'enum':
+ this.scalar(writer, reflection_info_1.ScalarType.INT32, 2, value, true);
+ break;
+ case 'message':
+ this.message(writer, options, field.V.T(), 2, value);
+ break;
+ }
+ writer.join();
+ }
+ message(writer, options, handler, fieldNo, value) {
+ if (value === undefined)
+ return;
+ handler.internalBinaryWrite(value, writer.tag(fieldNo, binary_format_contract_1.WireType.LengthDelimited).fork(), options);
+ writer.join();
+ }
+ /**
+ * Write a single scalar value.
+ */
+ scalar(writer, type, fieldNo, value, emitDefault) {
+ let [wireType, method, isDefault] = this.scalarInfo(type, value);
+ if (!isDefault || emitDefault) {
+ writer.tag(fieldNo, wireType);
+ writer[method](value);
+ }
+ }
+ /**
+ * Write an array of scalar values in packed format.
+ */
+ packed(writer, type, fieldNo, value) {
+ if (!value.length)
+ return;
+ assert_1.assert(type !== reflection_info_1.ScalarType.BYTES && type !== reflection_info_1.ScalarType.STRING);
+ // write tag
+ writer.tag(fieldNo, binary_format_contract_1.WireType.LengthDelimited);
+ // begin length-delimited
+ writer.fork();
+ // write values without tags
+ let [, method,] = this.scalarInfo(type);
+ for (let i = 0; i < value.length; i++)
+ writer[method](value[i]);
+ // end length delimited
+ writer.join();
+ }
+ /**
+ * Get information for writing a scalar value.
+ *
+ * Returns tuple:
+ * [0]: appropriate WireType
+ * [1]: name of the appropriate method of IBinaryWriter
+ * [2]: whether the given value is a default value
+ *
+ * If argument `value` is omitted, [2] is always false.
+ */
+ scalarInfo(type, value) {
+ let t = binary_format_contract_1.WireType.Varint;
+ let m;
+ let i = value === undefined;
+ let d = value === 0;
+ switch (type) {
+ case reflection_info_1.ScalarType.INT32:
+ m = "int32";
+ break;
+ case reflection_info_1.ScalarType.STRING:
+ d = i || !value.length;
+ t = binary_format_contract_1.WireType.LengthDelimited;
+ m = "string";
+ break;
+ case reflection_info_1.ScalarType.BOOL:
+ d = value === false;
+ m = "bool";
+ break;
+ case reflection_info_1.ScalarType.UINT32:
+ m = "uint32";
+ break;
+ case reflection_info_1.ScalarType.DOUBLE:
+ t = binary_format_contract_1.WireType.Bit64;
+ m = "double";
+ break;
+ case reflection_info_1.ScalarType.FLOAT:
+ t = binary_format_contract_1.WireType.Bit32;
+ m = "float";
+ break;
+ case reflection_info_1.ScalarType.INT64:
+ d = i || pb_long_1.PbLong.from(value).isZero();
+ m = "int64";
+ break;
+ case reflection_info_1.ScalarType.UINT64:
+ d = i || pb_long_1.PbULong.from(value).isZero();
+ m = "uint64";
+ break;
+ case reflection_info_1.ScalarType.FIXED64:
+ d = i || pb_long_1.PbULong.from(value).isZero();
+ t = binary_format_contract_1.WireType.Bit64;
+ m = "fixed64";
+ break;
+ case reflection_info_1.ScalarType.BYTES:
+ d = i || !value.byteLength;
+ t = binary_format_contract_1.WireType.LengthDelimited;
+ m = "bytes";
+ break;
+ case reflection_info_1.ScalarType.FIXED32:
+ t = binary_format_contract_1.WireType.Bit32;
+ m = "fixed32";
+ break;
+ case reflection_info_1.ScalarType.SFIXED32:
+ t = binary_format_contract_1.WireType.Bit32;
+ m = "sfixed32";
+ break;
+ case reflection_info_1.ScalarType.SFIXED64:
+ d = i || pb_long_1.PbLong.from(value).isZero();
+ t = binary_format_contract_1.WireType.Bit64;
+ m = "sfixed64";
+ break;
+ case reflection_info_1.ScalarType.SINT32:
+ m = "sint32";
+ break;
+ case reflection_info_1.ScalarType.SINT64:
+ d = i || pb_long_1.PbLong.from(value).isZero();
+ m = "sint64";
+ break;
+ }
+ return [t, m, i || d];
+ }
+}
+exports.ReflectionBinaryWriter = ReflectionBinaryWriter;
+
+
+/***/ }),
+
+/***/ 9946:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.containsMessageType = void 0;
+const message_type_contract_1 = __webpack_require__(3785);
+/**
+ * Check if the provided object is a proto message.
+ *
+ * Note that this is an experimental feature - it is here to stay, but
+ * implementation details may change without notice.
+ */
+function containsMessageType(msg) {
+ return msg[message_type_contract_1.MESSAGE_TYPE] != null;
+}
+exports.containsMessageType = containsMessageType;
+
+
+/***/ }),
+
+/***/ 5726:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.reflectionCreate = void 0;
+const reflection_scalar_default_1 = __webpack_require__(9526);
+const message_type_contract_1 = __webpack_require__(3785);
+/**
+ * Creates an instance of the generic message, using the field
+ * information.
+ */
+function reflectionCreate(type) {
+ /**
+ * This ternary can be removed in the next major version.
+ * The `Object.create()` code path utilizes a new `messagePrototype`
+ * property on the `IMessageType` which has this same `MESSAGE_TYPE`
+ * non-enumerable property on it. Doing it this way means that we only
+ * pay the cost of `Object.defineProperty()` once per `IMessageType`
+ * class of once per "instance". The falsy code path is only provided
+ * for backwards compatibility in cases where the runtime library is
+ * updated without also updating the generated code.
+ */
+ const msg = type.messagePrototype
+ ? Object.create(type.messagePrototype)
+ : Object.defineProperty({}, message_type_contract_1.MESSAGE_TYPE, { value: type });
+ for (let field of type.fields) {
+ let name = field.localName;
+ if (field.opt)
+ continue;
+ if (field.oneof)
+ msg[field.oneof] = { oneofKind: undefined };
+ else if (field.repeat)
+ msg[name] = [];
+ else
+ switch (field.kind) {
+ case "scalar":
+ msg[name] = reflection_scalar_default_1.reflectionScalarDefault(field.T, field.L);
+ break;
+ case "enum":
+ // we require 0 to be default value for all enums
+ msg[name] = 0;
+ break;
+ case "map":
+ msg[name] = {};
+ break;
+ }
+ }
+ return msg;
+}
+exports.reflectionCreate = reflectionCreate;
+
+
+/***/ }),
+
+/***/ 4827:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.reflectionEquals = void 0;
+const reflection_info_1 = __webpack_require__(7910);
+/**
+ * Determines whether two message of the same type have the same field values.
+ * Checks for deep equality, traversing repeated fields, oneof groups, maps
+ * and messages recursively.
+ * Will also return true if both messages are `undefined`.
+ */
+function reflectionEquals(info, a, b) {
+ if (a === b)
+ return true;
+ if (!a || !b)
+ return false;
+ for (let field of info.fields) {
+ let localName = field.localName;
+ let val_a = field.oneof ? a[field.oneof][localName] : a[localName];
+ let val_b = field.oneof ? b[field.oneof][localName] : b[localName];
+ switch (field.kind) {
+ case "enum":
+ case "scalar":
+ let t = field.kind == "enum" ? reflection_info_1.ScalarType.INT32 : field.T;
+ if (!(field.repeat
+ ? repeatedPrimitiveEq(t, val_a, val_b)
+ : primitiveEq(t, val_a, val_b)))
+ return false;
+ break;
+ case "map":
+ if (!(field.V.kind == "message"
+ ? repeatedMsgEq(field.V.T(), objectValues(val_a), objectValues(val_b))
+ : repeatedPrimitiveEq(field.V.kind == "enum" ? reflection_info_1.ScalarType.INT32 : field.V.T, objectValues(val_a), objectValues(val_b))))
+ return false;
+ break;
+ case "message":
+ let T = field.T();
+ if (!(field.repeat
+ ? repeatedMsgEq(T, val_a, val_b)
+ : T.equals(val_a, val_b)))
+ return false;
+ break;
+ }
+ }
+ return true;
+}
+exports.reflectionEquals = reflectionEquals;
+const objectValues = Object.values;
+function primitiveEq(type, a, b) {
+ if (a === b)
+ return true;
+ if (type !== reflection_info_1.ScalarType.BYTES)
+ return false;
+ let ba = a;
+ let bb = b;
+ if (ba.length !== bb.length)
+ return false;
+ for (let i = 0; i < ba.length; i++)
+ if (ba[i] != bb[i])
+ return false;
+ return true;
+}
+function repeatedPrimitiveEq(type, a, b) {
+ if (a.length !== b.length)
+ return false;
+ for (let i = 0; i < a.length; i++)
+ if (!primitiveEq(type, a[i], b[i]))
+ return false;
+ return true;
+}
+function repeatedMsgEq(type, a, b) {
+ if (a.length !== b.length)
+ return false;
+ for (let i = 0; i < a.length; i++)
+ if (!type.equals(a[i], b[i]))
+ return false;
+ return true;
+}
+
+
+/***/ }),
+
+/***/ 7910:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.readMessageOption = exports.readFieldOption = exports.readFieldOptions = exports.normalizeFieldInfo = exports.RepeatType = exports.LongType = exports.ScalarType = void 0;
+const lower_camel_case_1 = __webpack_require__(4073);
+/**
+ * Scalar value types. This is a subset of field types declared by protobuf
+ * enum google.protobuf.FieldDescriptorProto.Type The types GROUP and MESSAGE
+ * are omitted, but the numerical values are identical.
+ */
+var ScalarType;
+(function (ScalarType) {
+ // 0 is reserved for errors.
+ // Order is weird for historical reasons.
+ ScalarType[ScalarType["DOUBLE"] = 1] = "DOUBLE";
+ ScalarType[ScalarType["FLOAT"] = 2] = "FLOAT";
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
+ // negative values are likely.
+ ScalarType[ScalarType["INT64"] = 3] = "INT64";
+ ScalarType[ScalarType["UINT64"] = 4] = "UINT64";
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
+ // negative values are likely.
+ ScalarType[ScalarType["INT32"] = 5] = "INT32";
+ ScalarType[ScalarType["FIXED64"] = 6] = "FIXED64";
+ ScalarType[ScalarType["FIXED32"] = 7] = "FIXED32";
+ ScalarType[ScalarType["BOOL"] = 8] = "BOOL";
+ ScalarType[ScalarType["STRING"] = 9] = "STRING";
+ // Tag-delimited aggregate.
+ // Group type is deprecated and not supported in proto3. However, Proto3
+ // implementations should still be able to parse the group wire format and
+ // treat group fields as unknown fields.
+ // TYPE_GROUP = 10,
+ // TYPE_MESSAGE = 11, // Length-delimited aggregate.
+ // New in version 2.
+ ScalarType[ScalarType["BYTES"] = 12] = "BYTES";
+ ScalarType[ScalarType["UINT32"] = 13] = "UINT32";
+ // TYPE_ENUM = 14,
+ ScalarType[ScalarType["SFIXED32"] = 15] = "SFIXED32";
+ ScalarType[ScalarType["SFIXED64"] = 16] = "SFIXED64";
+ ScalarType[ScalarType["SINT32"] = 17] = "SINT32";
+ ScalarType[ScalarType["SINT64"] = 18] = "SINT64";
+})(ScalarType = exports.ScalarType || (exports.ScalarType = {}));
+/**
+ * JavaScript representation of 64 bit integral types. Equivalent to the
+ * field option "jstype".
+ *
+ * By default, protobuf-ts represents 64 bit types as `bigint`.
+ *
+ * You can change the default behaviour by enabling the plugin parameter
+ * `long_type_string`, which will represent 64 bit types as `string`.
+ *
+ * Alternatively, you can change the behaviour for individual fields
+ * with the field option "jstype":
+ *
+ * ```protobuf
+ * uint64 my_field = 1 [jstype = JS_STRING];
+ * uint64 other_field = 2 [jstype = JS_NUMBER];
+ * ```
+ */
+var LongType;
+(function (LongType) {
+ /**
+ * Use JavaScript `bigint`.
+ *
+ * Field option `[jstype = JS_NORMAL]`.
+ */
+ LongType[LongType["BIGINT"] = 0] = "BIGINT";
+ /**
+ * Use JavaScript `string`.
+ *
+ * Field option `[jstype = JS_STRING]`.
+ */
+ LongType[LongType["STRING"] = 1] = "STRING";
+ /**
+ * Use JavaScript `number`.
+ *
+ * Large values will loose precision.
+ *
+ * Field option `[jstype = JS_NUMBER]`.
+ */
+ LongType[LongType["NUMBER"] = 2] = "NUMBER";
+})(LongType = exports.LongType || (exports.LongType = {}));
+/**
+ * Protobuf 2.1.0 introduced packed repeated fields.
+ * Setting the field option `[packed = true]` enables packing.
+ *
+ * In proto3, all repeated fields are packed by default.
+ * Setting the field option `[packed = false]` disables packing.
+ *
+ * Packed repeated fields are encoded with a single tag,
+ * then a length-delimiter, then the element values.
+ *
+ * Unpacked repeated fields are encoded with a tag and
+ * value for each element.
+ *
+ * `bytes` and `string` cannot be packed.
+ */
+var RepeatType;
+(function (RepeatType) {
+ /**
+ * The field is not repeated.
+ */
+ RepeatType[RepeatType["NO"] = 0] = "NO";
+ /**
+ * The field is repeated and should be packed.
+ * Invalid for `bytes` and `string`, they cannot be packed.
+ */
+ RepeatType[RepeatType["PACKED"] = 1] = "PACKED";
+ /**
+ * The field is repeated but should not be packed.
+ * The only valid repeat type for repeated `bytes` and `string`.
+ */
+ RepeatType[RepeatType["UNPACKED"] = 2] = "UNPACKED";
+})(RepeatType = exports.RepeatType || (exports.RepeatType = {}));
+/**
+ * Turns PartialFieldInfo into FieldInfo.
+ */
+function normalizeFieldInfo(field) {
+ var _a, _b, _c, _d;
+ field.localName = (_a = field.localName) !== null && _a !== void 0 ? _a : lower_camel_case_1.lowerCamelCase(field.name);
+ field.jsonName = (_b = field.jsonName) !== null && _b !== void 0 ? _b : lower_camel_case_1.lowerCamelCase(field.name);
+ field.repeat = (_c = field.repeat) !== null && _c !== void 0 ? _c : RepeatType.NO;
+ field.opt = (_d = field.opt) !== null && _d !== void 0 ? _d : (field.repeat ? false : field.oneof ? false : field.kind == "message");
+ return field;
+}
+exports.normalizeFieldInfo = normalizeFieldInfo;
+/**
+ * Read custom field options from a generated message type.
+ *
+ * @deprecated use readFieldOption()
+ */
+function readFieldOptions(messageType, fieldName, extensionName, extensionType) {
+ var _a;
+ const options = (_a = messageType.fields.find((m, i) => m.localName == fieldName || i == fieldName)) === null || _a === void 0 ? void 0 : _a.options;
+ return options && options[extensionName] ? extensionType.fromJson(options[extensionName]) : undefined;
+}
+exports.readFieldOptions = readFieldOptions;
+function readFieldOption(messageType, fieldName, extensionName, extensionType) {
+ var _a;
+ const options = (_a = messageType.fields.find((m, i) => m.localName == fieldName || i == fieldName)) === null || _a === void 0 ? void 0 : _a.options;
+ if (!options) {
+ return undefined;
+ }
+ const optionVal = options[extensionName];
+ if (optionVal === undefined) {
+ return optionVal;
+ }
+ return extensionType ? extensionType.fromJson(optionVal) : optionVal;
+}
+exports.readFieldOption = readFieldOption;
+function readMessageOption(messageType, extensionName, extensionType) {
+ const options = messageType.options;
+ const optionVal = options[extensionName];
+ if (optionVal === undefined) {
+ return optionVal;
+ }
+ return extensionType ? extensionType.fromJson(optionVal) : optionVal;
+}
+exports.readMessageOption = readMessageOption;
+
+
+/***/ }),
+
+/***/ 6790:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ReflectionJsonReader = void 0;
+const json_typings_1 = __webpack_require__(9999);
+const base64_1 = __webpack_require__(6335);
+const reflection_info_1 = __webpack_require__(7910);
+const pb_long_1 = __webpack_require__(1753);
+const assert_1 = __webpack_require__(8602);
+const reflection_long_convert_1 = __webpack_require__(3402);
+/**
+ * Reads proto3 messages in canonical JSON format using reflection information.
+ *
+ * https://developers.google.com/protocol-buffers/docs/proto3#json
+ */
+class ReflectionJsonReader {
+ constructor(info) {
+ this.info = info;
+ }
+ prepare() {
+ var _a;
+ if (this.fMap === undefined) {
+ this.fMap = {};
+ const fieldsInput = (_a = this.info.fields) !== null && _a !== void 0 ? _a : [];
+ for (const field of fieldsInput) {
+ this.fMap[field.name] = field;
+ this.fMap[field.jsonName] = field;
+ this.fMap[field.localName] = field;
+ }
+ }
+ }
+ // Cannot parse JSON for #.
+ assert(condition, fieldName, jsonValue) {
+ if (!condition) {
+ let what = json_typings_1.typeofJsonValue(jsonValue);
+ if (what == "number" || what == "boolean")
+ what = jsonValue.toString();
+ throw new Error(`Cannot parse JSON ${what} for ${this.info.typeName}#${fieldName}`);
+ }
+ }
+ /**
+ * Reads a message from canonical JSON format into the target message.
+ *
+ * Repeated fields are appended. Map entries are added, overwriting
+ * existing keys.
+ *
+ * If a message field is already present, it will be merged with the
+ * new data.
+ */
+ read(input, message, options) {
+ this.prepare();
+ const oneofsHandled = [];
+ for (const [jsonKey, jsonValue] of Object.entries(input)) {
+ const field = this.fMap[jsonKey];
+ if (!field) {
+ if (!options.ignoreUnknownFields)
+ throw new Error(`Found unknown field while reading ${this.info.typeName} from JSON format. JSON key: ${jsonKey}`);
+ continue;
+ }
+ const localName = field.localName;
+ // handle oneof ADT
+ let target; // this will be the target for the field value, whether it is member of a oneof or not
+ if (field.oneof) {
+ if (jsonValue === null && (field.kind !== 'enum' || field.T()[0] !== 'google.protobuf.NullValue')) {
+ continue;
+ }
+ // since json objects are unordered by specification, it is not possible to take the last of multiple oneofs
+ if (oneofsHandled.includes(field.oneof))
+ throw new Error(`Multiple members of the oneof group "${field.oneof}" of ${this.info.typeName} are present in JSON.`);
+ oneofsHandled.push(field.oneof);
+ target = message[field.oneof] = {
+ oneofKind: localName
+ };
+ }
+ else {
+ target = message;
+ }
+ // we have handled oneof above. we just have read the value into `target`.
+ if (field.kind == 'map') {
+ if (jsonValue === null) {
+ continue;
+ }
+ // check input
+ this.assert(json_typings_1.isJsonObject(jsonValue), field.name, jsonValue);
+ // our target to put map entries into
+ const fieldObj = target[localName];
+ // read entries
+ for (const [jsonObjKey, jsonObjValue] of Object.entries(jsonValue)) {
+ this.assert(jsonObjValue !== null, field.name + " map value", null);
+ // read value
+ let val;
+ switch (field.V.kind) {
+ case "message":
+ val = field.V.T().internalJsonRead(jsonObjValue, options);
+ break;
+ case "enum":
+ val = this.enum(field.V.T(), jsonObjValue, field.name, options.ignoreUnknownFields);
+ if (val === false)
+ continue;
+ break;
+ case "scalar":
+ val = this.scalar(jsonObjValue, field.V.T, field.V.L, field.name);
+ break;
+ }
+ this.assert(val !== undefined, field.name + " map value", jsonObjValue);
+ // read key
+ let key = jsonObjKey;
+ if (field.K == reflection_info_1.ScalarType.BOOL)
+ key = key == "true" ? true : key == "false" ? false : key;
+ key = this.scalar(key, field.K, reflection_info_1.LongType.STRING, field.name).toString();
+ fieldObj[key] = val;
+ }
+ }
+ else if (field.repeat) {
+ if (jsonValue === null)
+ continue;
+ // check input
+ this.assert(Array.isArray(jsonValue), field.name, jsonValue);
+ // our target to put array entries into
+ const fieldArr = target[localName];
+ // read array entries
+ for (const jsonItem of jsonValue) {
+ this.assert(jsonItem !== null, field.name, null);
+ let val;
+ switch (field.kind) {
+ case "message":
+ val = field.T().internalJsonRead(jsonItem, options);
+ break;
+ case "enum":
+ val = this.enum(field.T(), jsonItem, field.name, options.ignoreUnknownFields);
+ if (val === false)
+ continue;
+ break;
+ case "scalar":
+ val = this.scalar(jsonItem, field.T, field.L, field.name);
+ break;
+ }
+ this.assert(val !== undefined, field.name, jsonValue);
+ fieldArr.push(val);
+ }
+ }
+ else {
+ switch (field.kind) {
+ case "message":
+ if (jsonValue === null && field.T().typeName != 'google.protobuf.Value') {
+ this.assert(field.oneof === undefined, field.name + " (oneof member)", null);
+ continue;
+ }
+ target[localName] = field.T().internalJsonRead(jsonValue, options, target[localName]);
+ break;
+ case "enum":
+ if (jsonValue === null)
+ continue;
+ let val = this.enum(field.T(), jsonValue, field.name, options.ignoreUnknownFields);
+ if (val === false)
+ continue;
+ target[localName] = val;
+ break;
+ case "scalar":
+ if (jsonValue === null)
+ continue;
+ target[localName] = this.scalar(jsonValue, field.T, field.L, field.name);
+ break;
+ }
+ }
+ }
+ }
+ /**
+ * Returns `false` for unrecognized string representations.
+ *
+ * google.protobuf.NullValue accepts only JSON `null` (or the old `"NULL_VALUE"`).
+ */
+ enum(type, json, fieldName, ignoreUnknownFields) {
+ if (type[0] == 'google.protobuf.NullValue')
+ assert_1.assert(json === null || json === "NULL_VALUE", `Unable to parse field ${this.info.typeName}#${fieldName}, enum ${type[0]} only accepts null.`);
+ if (json === null)
+ // we require 0 to be default value for all enums
+ return 0;
+ switch (typeof json) {
+ case "number":
+ assert_1.assert(Number.isInteger(json), `Unable to parse field ${this.info.typeName}#${fieldName}, enum can only be integral number, got ${json}.`);
+ return json;
+ case "string":
+ let localEnumName = json;
+ if (type[2] && json.substring(0, type[2].length) === type[2])
+ // lookup without the shared prefix
+ localEnumName = json.substring(type[2].length);
+ let enumNumber = type[1][localEnumName];
+ if (typeof enumNumber === 'undefined' && ignoreUnknownFields) {
+ return false;
+ }
+ assert_1.assert(typeof enumNumber == "number", `Unable to parse field ${this.info.typeName}#${fieldName}, enum ${type[0]} has no value for "${json}".`);
+ return enumNumber;
+ }
+ assert_1.assert(false, `Unable to parse field ${this.info.typeName}#${fieldName}, cannot parse enum value from ${typeof json}".`);
+ }
+ scalar(json, type, longType, fieldName) {
+ let e;
+ try {
+ switch (type) {
+ // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
+ // Either numbers or strings are accepted. Exponent notation is also accepted.
+ case reflection_info_1.ScalarType.DOUBLE:
+ case reflection_info_1.ScalarType.FLOAT:
+ if (json === null)
+ return .0;
+ if (json === "NaN")
+ return Number.NaN;
+ if (json === "Infinity")
+ return Number.POSITIVE_INFINITY;
+ if (json === "-Infinity")
+ return Number.NEGATIVE_INFINITY;
+ if (json === "") {
+ e = "empty string";
+ break;
+ }
+ if (typeof json == "string" && json.trim().length !== json.length) {
+ e = "extra whitespace";
+ break;
+ }
+ if (typeof json != "string" && typeof json != "number") {
+ break;
+ }
+ let float = Number(json);
+ if (Number.isNaN(float)) {
+ e = "not a number";
+ break;
+ }
+ if (!Number.isFinite(float)) {
+ // infinity and -infinity are handled by string representation above, so this is an error
+ e = "too large or small";
+ break;
+ }
+ if (type == reflection_info_1.ScalarType.FLOAT)
+ assert_1.assertFloat32(float);
+ return float;
+ // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
+ case reflection_info_1.ScalarType.INT32:
+ case reflection_info_1.ScalarType.FIXED32:
+ case reflection_info_1.ScalarType.SFIXED32:
+ case reflection_info_1.ScalarType.SINT32:
+ case reflection_info_1.ScalarType.UINT32:
+ if (json === null)
+ return 0;
+ let int32;
+ if (typeof json == "number")
+ int32 = json;
+ else if (json === "")
+ e = "empty string";
+ else if (typeof json == "string") {
+ if (json.trim().length !== json.length)
+ e = "extra whitespace";
+ else
+ int32 = Number(json);
+ }
+ if (int32 === undefined)
+ break;
+ if (type == reflection_info_1.ScalarType.UINT32)
+ assert_1.assertUInt32(int32);
+ else
+ assert_1.assertInt32(int32);
+ return int32;
+ // int64, fixed64, uint64: JSON value will be a decimal string. Either numbers or strings are accepted.
+ case reflection_info_1.ScalarType.INT64:
+ case reflection_info_1.ScalarType.SFIXED64:
+ case reflection_info_1.ScalarType.SINT64:
+ if (json === null)
+ return reflection_long_convert_1.reflectionLongConvert(pb_long_1.PbLong.ZERO, longType);
+ if (typeof json != "number" && typeof json != "string")
+ break;
+ return reflection_long_convert_1.reflectionLongConvert(pb_long_1.PbLong.from(json), longType);
+ case reflection_info_1.ScalarType.FIXED64:
+ case reflection_info_1.ScalarType.UINT64:
+ if (json === null)
+ return reflection_long_convert_1.reflectionLongConvert(pb_long_1.PbULong.ZERO, longType);
+ if (typeof json != "number" && typeof json != "string")
+ break;
+ return reflection_long_convert_1.reflectionLongConvert(pb_long_1.PbULong.from(json), longType);
+ // bool:
+ case reflection_info_1.ScalarType.BOOL:
+ if (json === null)
+ return false;
+ if (typeof json !== "boolean")
+ break;
+ return json;
+ // string:
+ case reflection_info_1.ScalarType.STRING:
+ if (json === null)
+ return "";
+ if (typeof json !== "string") {
+ e = "extra whitespace";
+ break;
+ }
+ try {
+ encodeURIComponent(json);
+ }
+ catch (e) {
+ e = "invalid UTF8";
+ break;
+ }
+ return json;
+ // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
+ // Either standard or URL-safe base64 encoding with/without paddings are accepted.
+ case reflection_info_1.ScalarType.BYTES:
+ if (json === null || json === "")
+ return new Uint8Array(0);
+ if (typeof json !== 'string')
+ break;
+ return base64_1.base64decode(json);
+ }
+ }
+ catch (error) {
+ e = error.message;
+ }
+ this.assert(false, fieldName + (e ? " - " + e : ""), json);
+ }
+}
+exports.ReflectionJsonReader = ReflectionJsonReader;
+
+
+/***/ }),
+
+/***/ 1094:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ReflectionJsonWriter = void 0;
+const base64_1 = __webpack_require__(6335);
+const pb_long_1 = __webpack_require__(1753);
+const reflection_info_1 = __webpack_require__(7910);
+const assert_1 = __webpack_require__(8602);
+/**
+ * Writes proto3 messages in canonical JSON format using reflection
+ * information.
+ *
+ * https://developers.google.com/protocol-buffers/docs/proto3#json
+ */
+class ReflectionJsonWriter {
+ constructor(info) {
+ var _a;
+ this.fields = (_a = info.fields) !== null && _a !== void 0 ? _a : [];
+ }
+ /**
+ * Converts the message to a JSON object, based on the field descriptors.
+ */
+ write(message, options) {
+ const json = {}, source = message;
+ for (const field of this.fields) {
+ // field is not part of a oneof, simply write as is
+ if (!field.oneof) {
+ let jsonValue = this.field(field, source[field.localName], options);
+ if (jsonValue !== undefined)
+ json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue;
+ continue;
+ }
+ // field is part of a oneof
+ const group = source[field.oneof];
+ if (group.oneofKind !== field.localName)
+ continue; // not selected, skip
+ const opt = field.kind == 'scalar' || field.kind == 'enum'
+ ? Object.assign(Object.assign({}, options), { emitDefaultValues: true }) : options;
+ let jsonValue = this.field(field, group[field.localName], opt);
+ assert_1.assert(jsonValue !== undefined);
+ json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue;
+ }
+ return json;
+ }
+ field(field, value, options) {
+ let jsonValue = undefined;
+ if (field.kind == 'map') {
+ assert_1.assert(typeof value == "object" && value !== null);
+ const jsonObj = {};
+ switch (field.V.kind) {
+ case "scalar":
+ for (const [entryKey, entryValue] of Object.entries(value)) {
+ const val = this.scalar(field.V.T, entryValue, field.name, false, true);
+ assert_1.assert(val !== undefined);
+ jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
+ }
+ break;
+ case "message":
+ const messageType = field.V.T();
+ for (const [entryKey, entryValue] of Object.entries(value)) {
+ const val = this.message(messageType, entryValue, field.name, options);
+ assert_1.assert(val !== undefined);
+ jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
+ }
+ break;
+ case "enum":
+ const enumInfo = field.V.T();
+ for (const [entryKey, entryValue] of Object.entries(value)) {
+ assert_1.assert(entryValue === undefined || typeof entryValue == 'number');
+ const val = this.enum(enumInfo, entryValue, field.name, false, true, options.enumAsInteger);
+ assert_1.assert(val !== undefined);
+ jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
+ }
+ break;
+ }
+ if (options.emitDefaultValues || Object.keys(jsonObj).length > 0)
+ jsonValue = jsonObj;
+ }
+ else if (field.repeat) {
+ assert_1.assert(Array.isArray(value));
+ const jsonArr = [];
+ switch (field.kind) {
+ case "scalar":
+ for (let i = 0; i < value.length; i++) {
+ const val = this.scalar(field.T, value[i], field.name, field.opt, true);
+ assert_1.assert(val !== undefined);
+ jsonArr.push(val);
+ }
+ break;
+ case "enum":
+ const enumInfo = field.T();
+ for (let i = 0; i < value.length; i++) {
+ assert_1.assert(value[i] === undefined || typeof value[i] == 'number');
+ const val = this.enum(enumInfo, value[i], field.name, field.opt, true, options.enumAsInteger);
+ assert_1.assert(val !== undefined);
+ jsonArr.push(val);
+ }
+ break;
+ case "message":
+ const messageType = field.T();
+ for (let i = 0; i < value.length; i++) {
+ const val = this.message(messageType, value[i], field.name, options);
+ assert_1.assert(val !== undefined);
+ jsonArr.push(val);
+ }
+ break;
+ }
+ // add converted array to json output
+ if (options.emitDefaultValues || jsonArr.length > 0 || options.emitDefaultValues)
+ jsonValue = jsonArr;
+ }
+ else {
+ switch (field.kind) {
+ case "scalar":
+ jsonValue = this.scalar(field.T, value, field.name, field.opt, options.emitDefaultValues);
+ break;
+ case "enum":
+ jsonValue = this.enum(field.T(), value, field.name, field.opt, options.emitDefaultValues, options.enumAsInteger);
+ break;
+ case "message":
+ jsonValue = this.message(field.T(), value, field.name, options);
+ break;
+ }
+ }
+ return jsonValue;
+ }
+ /**
+ * Returns `null` as the default for google.protobuf.NullValue.
+ */
+ enum(type, value, fieldName, optional, emitDefaultValues, enumAsInteger) {
+ if (type[0] == 'google.protobuf.NullValue')
+ return !emitDefaultValues && !optional ? undefined : null;
+ if (value === undefined) {
+ assert_1.assert(optional);
+ return undefined;
+ }
+ if (value === 0 && !emitDefaultValues && !optional)
+ // we require 0 to be default value for all enums
+ return undefined;
+ assert_1.assert(typeof value == 'number');
+ assert_1.assert(Number.isInteger(value));
+ if (enumAsInteger || !type[1].hasOwnProperty(value))
+ // if we don't now the enum value, just return the number
+ return value;
+ if (type[2])
+ // restore the dropped prefix
+ return type[2] + type[1][value];
+ return type[1][value];
+ }
+ message(type, value, fieldName, options) {
+ if (value === undefined)
+ return options.emitDefaultValues ? null : undefined;
+ return type.internalJsonWrite(value, options);
+ }
+ scalar(type, value, fieldName, optional, emitDefaultValues) {
+ if (value === undefined) {
+ assert_1.assert(optional);
+ return undefined;
+ }
+ const ed = emitDefaultValues || optional;
+ // noinspection FallThroughInSwitchStatementJS
+ switch (type) {
+ // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
+ case reflection_info_1.ScalarType.INT32:
+ case reflection_info_1.ScalarType.SFIXED32:
+ case reflection_info_1.ScalarType.SINT32:
+ if (value === 0)
+ return ed ? 0 : undefined;
+ assert_1.assertInt32(value);
+ return value;
+ case reflection_info_1.ScalarType.FIXED32:
+ case reflection_info_1.ScalarType.UINT32:
+ if (value === 0)
+ return ed ? 0 : undefined;
+ assert_1.assertUInt32(value);
+ return value;
+ // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
+ // Either numbers or strings are accepted. Exponent notation is also accepted.
+ case reflection_info_1.ScalarType.FLOAT:
+ assert_1.assertFloat32(value);
+ case reflection_info_1.ScalarType.DOUBLE:
+ if (value === 0)
+ return ed ? 0 : undefined;
+ assert_1.assert(typeof value == 'number');
+ if (Number.isNaN(value))
+ return 'NaN';
+ if (value === Number.POSITIVE_INFINITY)
+ return 'Infinity';
+ if (value === Number.NEGATIVE_INFINITY)
+ return '-Infinity';
+ return value;
+ // string:
+ case reflection_info_1.ScalarType.STRING:
+ if (value === "")
+ return ed ? '' : undefined;
+ assert_1.assert(typeof value == 'string');
+ return value;
+ // bool:
+ case reflection_info_1.ScalarType.BOOL:
+ if (value === false)
+ return ed ? false : undefined;
+ assert_1.assert(typeof value == 'boolean');
+ return value;
+ // JSON value will be a decimal string. Either numbers or strings are accepted.
+ case reflection_info_1.ScalarType.UINT64:
+ case reflection_info_1.ScalarType.FIXED64:
+ assert_1.assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint');
+ let ulong = pb_long_1.PbULong.from(value);
+ if (ulong.isZero() && !ed)
+ return undefined;
+ return ulong.toString();
+ // JSON value will be a decimal string. Either numbers or strings are accepted.
+ case reflection_info_1.ScalarType.INT64:
+ case reflection_info_1.ScalarType.SFIXED64:
+ case reflection_info_1.ScalarType.SINT64:
+ assert_1.assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint');
+ let long = pb_long_1.PbLong.from(value);
+ if (long.isZero() && !ed)
+ return undefined;
+ return long.toString();
+ // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
+ // Either standard or URL-safe base64 encoding with/without paddings are accepted.
+ case reflection_info_1.ScalarType.BYTES:
+ assert_1.assert(value instanceof Uint8Array);
+ if (!value.byteLength)
+ return ed ? "" : undefined;
+ return base64_1.base64encode(value);
+ }
+ }
+}
+exports.ReflectionJsonWriter = ReflectionJsonWriter;
+
+
+/***/ }),
+
+/***/ 3402:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.reflectionLongConvert = void 0;
+const reflection_info_1 = __webpack_require__(7910);
+/**
+ * Utility method to convert a PbLong or PbUlong to a JavaScript
+ * representation during runtime.
+ *
+ * Works with generated field information, `undefined` is equivalent
+ * to `STRING`.
+ */
+function reflectionLongConvert(long, type) {
+ switch (type) {
+ case reflection_info_1.LongType.BIGINT:
+ return long.toBigInt();
+ case reflection_info_1.LongType.NUMBER:
+ return long.toNumber();
+ default:
+ // case undefined:
+ // case LongType.STRING:
+ return long.toString();
+ }
+}
+exports.reflectionLongConvert = reflectionLongConvert;
+
+
+/***/ }),
+
+/***/ 8044:
+/***/ ((__unused_webpack_module, exports) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.reflectionMergePartial = void 0;
+/**
+ * Copy partial data into the target message.
+ *
+ * If a singular scalar or enum field is present in the source, it
+ * replaces the field in the target.
+ *
+ * If a singular message field is present in the source, it is merged
+ * with the target field by calling mergePartial() of the responsible
+ * message type.
+ *
+ * If a repeated field is present in the source, its values replace
+ * all values in the target array, removing extraneous values.
+ * Repeated message fields are copied, not merged.
+ *
+ * If a map field is present in the source, entries are added to the
+ * target map, replacing entries with the same key. Entries that only
+ * exist in the target remain. Entries with message values are copied,
+ * not merged.
+ *
+ * Note that this function differs from protobuf merge semantics,
+ * which appends repeated fields.
+ */
+function reflectionMergePartial(info, target, source) {
+ let fieldValue, // the field value we are working with
+ input = source, output; // where we want our field value to go
+ for (let field of info.fields) {
+ let name = field.localName;
+ if (field.oneof) {
+ const group = input[field.oneof]; // this is the oneof`s group in the source
+ if ((group === null || group === void 0 ? void 0 : group.oneofKind) == undefined) { // the user is free to omit
+ continue; // we skip this field, and all other members too
+ }
+ fieldValue = group[name]; // our value comes from the the oneof group of the source
+ output = target[field.oneof]; // and our output is the oneof group of the target
+ output.oneofKind = group.oneofKind; // always update discriminator
+ if (fieldValue == undefined) {
+ delete output[name]; // remove any existing value
+ continue; // skip further work on field
+ }
+ }
+ else {
+ fieldValue = input[name]; // we are using the source directly
+ output = target; // we want our field value to go directly into the target
+ if (fieldValue == undefined) {
+ continue; // skip further work on field, existing value is used as is
+ }
+ }
+ if (field.repeat)
+ output[name].length = fieldValue.length; // resize target array to match source array
+ // now we just work with `fieldValue` and `output` to merge the value
+ switch (field.kind) {
+ case "scalar":
+ case "enum":
+ if (field.repeat)
+ for (let i = 0; i < fieldValue.length; i++)
+ output[name][i] = fieldValue[i]; // not a reference type
+ else
+ output[name] = fieldValue; // not a reference type
+ break;
+ case "message":
+ let T = field.T();
+ if (field.repeat)
+ for (let i = 0; i < fieldValue.length; i++)
+ output[name][i] = T.create(fieldValue[i]);
+ else if (output[name] === undefined)
+ output[name] = T.create(fieldValue); // nothing to merge with
+ else
+ T.mergePartial(output[name], fieldValue);
+ break;
+ case "map":
+ // Map and repeated fields are simply overwritten, not appended or merged
+ switch (field.V.kind) {
+ case "scalar":
+ case "enum":
+ Object.assign(output[name], fieldValue); // elements are not reference types
+ break;
+ case "message":
+ let T = field.V.T();
+ for (let k of Object.keys(fieldValue))
+ output[name][k] = T.create(fieldValue[k]);
+ break;
+ }
+ break;
+ }
+ }
+}
+exports.reflectionMergePartial = reflectionMergePartial;
+
+
+/***/ }),
+
+/***/ 9526:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.reflectionScalarDefault = void 0;
+const reflection_info_1 = __webpack_require__(7910);
+const reflection_long_convert_1 = __webpack_require__(3402);
+const pb_long_1 = __webpack_require__(1753);
+/**
+ * Creates the default value for a scalar type.
+ */
+function reflectionScalarDefault(type, longType = reflection_info_1.LongType.STRING) {
+ switch (type) {
+ case reflection_info_1.ScalarType.BOOL:
+ return false;
+ case reflection_info_1.ScalarType.UINT64:
+ case reflection_info_1.ScalarType.FIXED64:
+ return reflection_long_convert_1.reflectionLongConvert(pb_long_1.PbULong.ZERO, longType);
+ case reflection_info_1.ScalarType.INT64:
+ case reflection_info_1.ScalarType.SFIXED64:
+ case reflection_info_1.ScalarType.SINT64:
+ return reflection_long_convert_1.reflectionLongConvert(pb_long_1.PbLong.ZERO, longType);
+ case reflection_info_1.ScalarType.DOUBLE:
+ case reflection_info_1.ScalarType.FLOAT:
+ return 0.0;
+ case reflection_info_1.ScalarType.BYTES:
+ return new Uint8Array(0);
+ case reflection_info_1.ScalarType.STRING:
+ return "";
+ default:
+ // case ScalarType.INT32:
+ // case ScalarType.UINT32:
+ // case ScalarType.SINT32:
+ // case ScalarType.FIXED32:
+ // case ScalarType.SFIXED32:
+ return 0;
+ }
+}
+exports.reflectionScalarDefault = reflectionScalarDefault;
+
+
+/***/ }),
+
+/***/ 5167:
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.ReflectionTypeCheck = void 0;
+const reflection_info_1 = __webpack_require__(7910);
+const oneof_1 = __webpack_require__(8063);
+// noinspection JSMethodCanBeStatic
+class ReflectionTypeCheck {
+ constructor(info) {
+ var _a;
+ this.fields = (_a = info.fields) !== null && _a !== void 0 ? _a : [];
+ }
+ prepare() {
+ if (this.data)
+ return;
+ const req = [], known = [], oneofs = [];
+ for (let field of this.fields) {
+ if (field.oneof) {
+ if (!oneofs.includes(field.oneof)) {
+ oneofs.push(field.oneof);
+ req.push(field.oneof);
+ known.push(field.oneof);
+ }
+ }
+ else {
+ known.push(field.localName);
+ switch (field.kind) {
+ case "scalar":
+ case "enum":
+ if (!field.opt || field.repeat)
+ req.push(field.localName);
+ break;
+ case "message":
+ if (field.repeat)
+ req.push(field.localName);
+ break;
+ case "map":
+ req.push(field.localName);
+ break;
+ }
+ }
+ }
+ this.data = { req, known, oneofs: Object.values(oneofs) };
+ }
+ /**
+ * Is the argument a valid message as specified by the
+ * reflection information?
+ *
+ * Checks all field types recursively. The `depth`
+ * specifies how deep into the structure the check will be.
+ *
+ * With a depth of 0, only the presence of fields
+ * is checked.
+ *
+ * With a depth of 1 or more, the field types are checked.
+ *
+ * With a depth of 2 or more, the members of map, repeated
+ * and message fields are checked.
+ *
+ * Message fields will be checked recursively with depth - 1.
+ *
+ * The number of map entries / repeated values being checked
+ * is < depth.
+ */
+ is(message, depth, allowExcessProperties = false) {
+ if (depth < 0)
+ return true;
+ if (message === null || message === undefined || typeof message != 'object')
+ return false;
+ this.prepare();
+ let keys = Object.keys(message), data = this.data;
+ // if a required field is missing in arg, this cannot be a T
+ if (keys.length < data.req.length || data.req.some(n => !keys.includes(n)))
+ return false;
+ if (!allowExcessProperties) {
+ // if the arg contains a key we dont know, this is not a literal T
+ if (keys.some(k => !data.known.includes(k)))
+ return false;
+ }
+ // "With a depth of 0, only the presence and absence of fields is checked."
+ // "With a depth of 1 or more, the field types are checked."
+ if (depth < 1) {
+ return true;
+ }
+ // check oneof group
+ for (const name of data.oneofs) {
+ const group = message[name];
+ if (!oneof_1.isOneofGroup(group))
+ return false;
+ if (group.oneofKind === undefined)
+ continue;
+ const field = this.fields.find(f => f.localName === group.oneofKind);
+ if (!field)
+ return false; // we found no field, but have a kind, something is wrong
+ if (!this.field(group[group.oneofKind], field, allowExcessProperties, depth))
+ return false;
+ }
+ // check types
+ for (const field of this.fields) {
+ if (field.oneof !== undefined)
+ continue;
+ if (!this.field(message[field.localName], field, allowExcessProperties, depth))
+ return false;
+ }
+ return true;
+ }
+ field(arg, field, allowExcessProperties, depth) {
+ let repeated = field.repeat;
+ switch (field.kind) {
+ case "scalar":
+ if (arg === undefined)
+ return field.opt;
+ if (repeated)
+ return this.scalars(arg, field.T, depth, field.L);
+ return this.scalar(arg, field.T, field.L);
+ case "enum":
+ if (arg === undefined)
+ return field.opt;
+ if (repeated)
+ return this.scalars(arg, reflection_info_1.ScalarType.INT32, depth);
+ return this.scalar(arg, reflection_info_1.ScalarType.INT32);
+ case "message":
+ if (arg === undefined)
+ return true;
+ if (repeated)
+ return this.messages(arg, field.T(), allowExcessProperties, depth);
+ return this.message(arg, field.T(), allowExcessProperties, depth);
+ case "map":
+ if (typeof arg != 'object' || arg === null)
+ return false;
+ if (depth < 2)
+ return true;
+ if (!this.mapKeys(arg, field.K, depth))
+ return false;
+ switch (field.V.kind) {
+ case "scalar":
+ return this.scalars(Object.values(arg), field.V.T, depth, field.V.L);
+ case "enum":
+ return this.scalars(Object.values(arg), reflection_info_1.ScalarType.INT32, depth);
+ case "message":
+ return this.messages(Object.values(arg), field.V.T(), allowExcessProperties, depth);
+ }
+ break;
+ }
+ return true;
+ }
+ message(arg, type, allowExcessProperties, depth) {
+ if (allowExcessProperties) {
+ return type.isAssignable(arg, depth);
+ }
+ return type.is(arg, depth);
+ }
+ messages(arg, type, allowExcessProperties, depth) {
+ if (!Array.isArray(arg))
+ return false;
+ if (depth < 2)
+ return true;
+ if (allowExcessProperties) {
+ for (let i = 0; i < arg.length && i < depth; i++)
+ if (!type.isAssignable(arg[i], depth - 1))
+ return false;
+ }
+ else {
+ for (let i = 0; i < arg.length && i < depth; i++)
+ if (!type.is(arg[i], depth - 1))
+ return false;
+ }
+ return true;
+ }
+ scalar(arg, type, longType) {
+ let argType = typeof arg;
+ switch (type) {
+ case reflection_info_1.ScalarType.UINT64:
+ case reflection_info_1.ScalarType.FIXED64:
+ case reflection_info_1.ScalarType.INT64:
+ case reflection_info_1.ScalarType.SFIXED64:
+ case reflection_info_1.ScalarType.SINT64:
+ switch (longType) {
+ case reflection_info_1.LongType.BIGINT:
+ return argType == "bigint";
+ case reflection_info_1.LongType.NUMBER:
+ return argType == "number" && !isNaN(arg);
+ default:
+ return argType == "string";
+ }
+ case reflection_info_1.ScalarType.BOOL:
+ return argType == 'boolean';
+ case reflection_info_1.ScalarType.STRING:
+ return argType == 'string';
+ case reflection_info_1.ScalarType.BYTES:
+ return arg instanceof Uint8Array;
+ case reflection_info_1.ScalarType.DOUBLE:
+ case reflection_info_1.ScalarType.FLOAT:
+ return argType == 'number' && !isNaN(arg);
+ default:
+ // case ScalarType.UINT32:
+ // case ScalarType.FIXED32:
+ // case ScalarType.INT32:
+ // case ScalarType.SINT32:
+ // case ScalarType.SFIXED32:
+ return argType == 'number' && Number.isInteger(arg);
+ }
+ }
+ scalars(arg, type, depth, longType) {
+ if (!Array.isArray(arg))
+ return false;
+ if (depth < 2)
+ return true;
+ if (Array.isArray(arg))
+ for (let i = 0; i < arg.length && i < depth; i++)
+ if (!this.scalar(arg[i], type, longType))
+ return false;
+ return true;
+ }
+ mapKeys(map, type, depth) {
+ let keys = Object.keys(map);
+ switch (type) {
+ case reflection_info_1.ScalarType.INT32:
+ case reflection_info_1.ScalarType.FIXED32:
+ case reflection_info_1.ScalarType.SFIXED32:
+ case reflection_info_1.ScalarType.SINT32:
+ case reflection_info_1.ScalarType.UINT32:
+ return this.scalars(keys.slice(0, depth).map(k => parseInt(k)), type, depth);
+ case reflection_info_1.ScalarType.BOOL:
+ return this.scalars(keys.slice(0, depth).map(k => k == 'true' ? true : k == 'false' ? false : k), type, depth);
+ default:
+ return this.scalars(keys, type, depth, reflection_info_1.LongType.STRING);
+ }
+ }
+}
+exports.ReflectionTypeCheck = ReflectionTypeCheck;
+
+
+/***/ }),
+
+/***/ 5183:
+/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.req = exports.json = exports.toBuffer = void 0;
+const http = __importStar(__webpack_require__(8611));
+const https = __importStar(__webpack_require__(5692));
+async function toBuffer(stream) {
+ let length = 0;
+ const chunks = [];
+ for await (const chunk of stream) {
+ length += chunk.length;
+ chunks.push(chunk);
+ }
+ return Buffer.concat(chunks, length);
+}
+exports.toBuffer = toBuffer;
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+async function json(stream) {
+ const buf = await toBuffer(stream);
+ const str = buf.toString('utf8');
+ try {
+ return JSON.parse(str);
+ }
+ catch (_err) {
+ const err = _err;
+ err.message += ` (input: ${str})`;
+ throw err;
+ }
+}
+exports.json = json;
+function req(url, opts = {}) {
+ const href = typeof url === 'string' ? url : url.href;
+ const req = (href.startsWith('https:') ? https : http).request(url, opts);
+ const promise = new Promise((resolve, reject) => {
+ req
+ .once('response', resolve)
+ .once('error', reject)
+ .end();
+ });
+ req.then = promise.then.bind(promise);
+ return req;
+}
+exports.req = req;
+//# sourceMappingURL=helpers.js.map
+
+/***/ }),
+
+/***/ 8894:
+/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.Agent = void 0;
+const net = __importStar(__webpack_require__(9278));
+const http = __importStar(__webpack_require__(8611));
+const https_1 = __webpack_require__(5692);
+__exportStar(__webpack_require__(5183), exports);
+const INTERNAL = Symbol('AgentBaseInternalState');
+class Agent extends http.Agent {
+ constructor(opts) {
+ super(opts);
+ this[INTERNAL] = {};
+ }
+ /**
+ * Determine whether this is an `http` or `https` request.
+ */
+ isSecureEndpoint(options) {
+ if (options) {
+ // First check the `secureEndpoint` property explicitly, since this
+ // means that a parent `Agent` is "passing through" to this instance.
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ if (typeof options.secureEndpoint === 'boolean') {
+ return options.secureEndpoint;
+ }
+ // If no explicit `secure` endpoint, check if `protocol` property is
+ // set. This will usually be the case since using a full string URL
+ // or `URL` instance should be the most common usage.
+ if (typeof options.protocol === 'string') {
+ return options.protocol === 'https:';
+ }
+ }
+ // Finally, if no `protocol` property was set, then fall back to
+ // checking the stack trace of the current call stack, and try to
+ // detect the "https" module.
+ const { stack } = new Error();
+ if (typeof stack !== 'string')
+ return false;
+ return stack
+ .split('\n')
+ .some((l) => l.indexOf('(https.js:') !== -1 ||
+ l.indexOf('node:https:') !== -1);
+ }
+ // In order to support async signatures in `connect()` and Node's native
+ // connection pooling in `http.Agent`, the array of sockets for each origin
+ // has to be updated synchronously. This is so the length of the array is
+ // accurate when `addRequest()` is next called. We achieve this by creating a
+ // fake socket and adding it to `sockets[origin]` and incrementing
+ // `totalSocketCount`.
+ incrementSockets(name) {
+ // If `maxSockets` and `maxTotalSockets` are both Infinity then there is no
+ // need to create a fake socket because Node.js native connection pooling
+ // will never be invoked.
+ if (this.maxSockets === Infinity && this.maxTotalSockets === Infinity) {
+ return null;
+ }
+ // All instances of `sockets` are expected TypeScript errors. The
+ // alternative is to add it as a private property of this class but that
+ // will break TypeScript subclassing.
+ if (!this.sockets[name]) {
+ // @ts-expect-error `sockets` is readonly in `@types/node`
+ this.sockets[name] = [];
+ }
+ const fakeSocket = new net.Socket({ writable: false });
+ this.sockets[name].push(fakeSocket);
+ // @ts-expect-error `totalSocketCount` isn't defined in `@types/node`
+ this.totalSocketCount++;
+ return fakeSocket;
+ }
+ decrementSockets(name, socket) {
+ if (!this.sockets[name] || socket === null) {
+ return;
+ }
+ const sockets = this.sockets[name];
+ const index = sockets.indexOf(socket);
+ if (index !== -1) {
+ sockets.splice(index, 1);
+ // @ts-expect-error `totalSocketCount` isn't defined in `@types/node`
+ this.totalSocketCount--;
+ if (sockets.length === 0) {
+ // @ts-expect-error `sockets` is readonly in `@types/node`
+ delete this.sockets[name];
+ }
+ }
+ }
+ // In order to properly update the socket pool, we need to call `getName()` on
+ // the core `https.Agent` if it is a secureEndpoint.
+ getName(options) {
+ const secureEndpoint = this.isSecureEndpoint(options);
+ if (secureEndpoint) {
+ // @ts-expect-error `getName()` isn't defined in `@types/node`
+ return https_1.Agent.prototype.getName.call(this, options);
+ }
+ // @ts-expect-error `getName()` isn't defined in `@types/node`
+ return super.getName(options);
+ }
+ createSocket(req, options, cb) {
+ const connectOpts = {
+ ...options,
+ secureEndpoint: this.isSecureEndpoint(options),
+ };
+ const name = this.getName(connectOpts);
+ const fakeSocket = this.incrementSockets(name);
+ Promise.resolve()
+ .then(() => this.connect(req, connectOpts))
+ .then((socket) => {
+ this.decrementSockets(name, fakeSocket);
+ if (socket instanceof http.Agent) {
+ try {
+ // @ts-expect-error `addRequest()` isn't defined in `@types/node`
+ return socket.addRequest(req, connectOpts);
+ }
+ catch (err) {
+ return cb(err);
+ }
+ }
+ this[INTERNAL].currentSocket = socket;
+ // @ts-expect-error `createSocket()` isn't defined in `@types/node`
+ super.createSocket(req, options, cb);
+ }, (err) => {
+ this.decrementSockets(name, fakeSocket);
+ cb(err);
+ });
+ }
+ createConnection() {
+ const socket = this[INTERNAL].currentSocket;
+ this[INTERNAL].currentSocket = undefined;
+ if (!socket) {
+ throw new Error('No socket was returned in the `connect()` function');
+ }
+ return socket;
+ }
+ get defaultPort() {
+ return (this[INTERNAL].defaultPort ??
+ (this.protocol === 'https:' ? 443 : 80));
+ }
+ set defaultPort(v) {
+ if (this[INTERNAL]) {
+ this[INTERNAL].defaultPort = v;
+ }
+ }
+ get protocol() {
+ return (this[INTERNAL].protocol ??
+ (this.isSecureEndpoint() ? 'https:' : 'http:'));
+ }
+ set protocol(v) {
+ if (this[INTERNAL]) {
+ this[INTERNAL].protocol = v;
+ }
+ }
+}
+exports.Agent = Agent;
+//# sourceMappingURL=index.js.map
+
+/***/ }),
+
+/***/ 6110:
+/***/ ((module, exports, __webpack_require__) => {
+
+/* eslint-env browser */
+
+/**
+ * This is the web browser implementation of `debug()`.
+ */
+
+exports.formatArgs = formatArgs;
+exports.save = save;
+exports.load = load;
+exports.useColors = useColors;
+exports.storage = localstorage();
+exports.destroy = (() => {
+ let warned = false;
+
+ return () => {
+ if (!warned) {
+ warned = true;
+ console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
+ }
+ };
+})();
+
+/**
+ * Colors.
+ */
+
+exports.colors = [
+ '#0000CC',
+ '#0000FF',
+ '#0033CC',
+ '#0033FF',
+ '#0066CC',
+ '#0066FF',
+ '#0099CC',
+ '#0099FF',
+ '#00CC00',
+ '#00CC33',
+ '#00CC66',
+ '#00CC99',
+ '#00CCCC',
+ '#00CCFF',
+ '#3300CC',
+ '#3300FF',
+ '#3333CC',
+ '#3333FF',
+ '#3366CC',
+ '#3366FF',
+ '#3399CC',
+ '#3399FF',
+ '#33CC00',
+ '#33CC33',
+ '#33CC66',
+ '#33CC99',
+ '#33CCCC',
+ '#33CCFF',
+ '#6600CC',
+ '#6600FF',
+ '#6633CC',
+ '#6633FF',
+ '#66CC00',
+ '#66CC33',
+ '#9900CC',
+ '#9900FF',
+ '#9933CC',
+ '#9933FF',
+ '#99CC00',
+ '#99CC33',
+ '#CC0000',
+ '#CC0033',
+ '#CC0066',
+ '#CC0099',
+ '#CC00CC',
+ '#CC00FF',
+ '#CC3300',
+ '#CC3333',
+ '#CC3366',
+ '#CC3399',
+ '#CC33CC',
+ '#CC33FF',
+ '#CC6600',
+ '#CC6633',
+ '#CC9900',
+ '#CC9933',
+ '#CCCC00',
+ '#CCCC33',
+ '#FF0000',
+ '#FF0033',
+ '#FF0066',
+ '#FF0099',
+ '#FF00CC',
+ '#FF00FF',
+ '#FF3300',
+ '#FF3333',
+ '#FF3366',
+ '#FF3399',
+ '#FF33CC',
+ '#FF33FF',
+ '#FF6600',
+ '#FF6633',
+ '#FF9900',
+ '#FF9933',
+ '#FFCC00',
+ '#FFCC33'
+];
+
+/**
+ * Currently only WebKit-based Web Inspectors, Firefox >= v31,
+ * and the Firebug extension (any Firefox version) are known
+ * to support "%c" CSS customizations.
+ *
+ * TODO: add a `localStorage` variable to explicitly enable/disable colors
+ */
+
+// eslint-disable-next-line complexity
+function useColors() {
+ // NB: In an Electron preload script, document will be defined but not fully
+ // initialized. Since we know we're in Chrome, we'll just detect this case
+ // explicitly
+ if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
+ return true;
+ }
+
+ // Internet Explorer and Edge do not support colors.
+ if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
+ return false;
+ }
+
+ let m;
+
+ // Is webkit? http://stackoverflow.com/a/16459606/376773
+ // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
+ // eslint-disable-next-line no-return-assign
+ return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
+ // Is firebug? http://stackoverflow.com/a/398120/376773
+ (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
+ // Is firefox >= v31?
+ // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
+ (typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31) ||
+ // Double check webkit in userAgent just in case we are in a worker
+ (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
+}
+
+/**
+ * Colorize log arguments if enabled.
+ *
+ * @api public
+ */
+
+function formatArgs(args) {
+ args[0] = (this.useColors ? '%c' : '') +
+ this.namespace +
+ (this.useColors ? ' %c' : ' ') +
+ args[0] +
+ (this.useColors ? '%c ' : ' ') +
+ '+' + module.exports.humanize(this.diff);
+
+ if (!this.useColors) {
+ return;
+ }
+
+ const c = 'color: ' + this.color;
+ args.splice(1, 0, c, 'color: inherit');
+
+ // The final "%c" is somewhat tricky, because there could be other
+ // arguments passed either before or after the %c, so we need to
+ // figure out the correct index to insert the CSS into
+ let index = 0;
+ let lastC = 0;
+ args[0].replace(/%[a-zA-Z%]/g, match => {
+ if (match === '%%') {
+ return;
+ }
+ index++;
+ if (match === '%c') {
+ // We only are interested in the *last* %c
+ // (the user may have provided their own)
+ lastC = index;
+ }
+ });
+
+ args.splice(lastC, 0, c);
+}
+
+/**
+ * Invokes `console.debug()` when available.
+ * No-op when `console.debug` is not a "function".
+ * If `console.debug` is not available, falls back
+ * to `console.log`.
+ *
+ * @api public
+ */
+exports.log = console.debug || console.log || (() => {});
+
+/**
+ * Save `namespaces`.
+ *
+ * @param {String} namespaces
+ * @api private
+ */
+function save(namespaces) {
+ try {
+ if (namespaces) {
+ exports.storage.setItem('debug', namespaces);
+ } else {
+ exports.storage.removeItem('debug');
+ }
+ } catch (error) {
+ // Swallow
+ // XXX (@Qix-) should we be logging these?
+ }
+}
+
+/**
+ * Load `namespaces`.
+ *
+ * @return {String} returns the previously persisted debug modes
+ * @api private
+ */
+function load() {
+ let r;
+ try {
+ r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ;
+ } catch (error) {
+ // Swallow
+ // XXX (@Qix-) should we be logging these?
+ }
+
+ // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
+ if (!r && typeof process !== 'undefined' && 'env' in process) {
+ r = process.env.DEBUG;
+ }
+
+ return r;
+}
+
+/**
+ * Localstorage attempts to return the localstorage.
+ *
+ * This is necessary because safari throws
+ * when a user disables cookies/localstorage
+ * and you attempt to access it.
+ *
+ * @return {LocalStorage}
+ * @api private
+ */
+
+function localstorage() {
+ try {
+ // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
+ // The Browser also has localStorage in the global context.
+ return localStorage;
+ } catch (error) {
+ // Swallow
+ // XXX (@Qix-) should we be logging these?
+ }
+}
+
+module.exports = __webpack_require__(897)(exports);
+
+const {formatters} = module.exports;
+
+/**
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
+ */
+
+formatters.j = function (v) {
+ try {
+ return JSON.stringify(v);
+ } catch (error) {
+ return '[UnexpectedJSONParseError]: ' + error.message;
+ }
+};
+
+
+/***/ }),
+
+/***/ 897:
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+
+/**
+ * This is the common logic for both the Node.js and web browser
+ * implementations of `debug()`.
+ */
+
+function setup(env) {
+ createDebug.debug = createDebug;
+ createDebug.default = createDebug;
+ createDebug.coerce = coerce;
+ createDebug.disable = disable;
+ createDebug.enable = enable;
+ createDebug.enabled = enabled;
+ createDebug.humanize = __webpack_require__(744);
+ createDebug.destroy = destroy;
+
+ Object.keys(env).forEach(key => {
+ createDebug[key] = env[key];
+ });
+
+ /**
+ * The currently active debug mode names, and names to skip.
+ */
+
+ createDebug.names = [];
+ createDebug.skips = [];
+
+ /**
+ * Map of special "%n" handling functions, for the debug "format" argument.
+ *
+ * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
+ */
+ createDebug.formatters = {};
+
+ /**
+ * Selects a color for a debug namespace
+ * @param {String} namespace The namespace string for the debug instance to be colored
+ * @return {Number|String} An ANSI color code for the given namespace
+ * @api private
+ */
+ function selectColor(namespace) {
+ let hash = 0;
+
+ for (let i = 0; i < namespace.length; i++) {
+ hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
+ hash |= 0; // Convert to 32bit integer
+ }
+
+ return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
+ }
+ createDebug.selectColor = selectColor;
+
+ /**
+ * Create a debugger with the given `namespace`.
+ *
+ * @param {String} namespace
+ * @return {Function}
+ * @api public
+ */
+ function createDebug(namespace) {
+ let prevTime;
+ let enableOverride = null;
+ let namespacesCache;
+ let enabledCache;
+
+ function debug(...args) {
+ // Disabled?
+ if (!debug.enabled) {
+ return;
+ }
+
+ const self = debug;
+
+ // Set `diff` timestamp
+ const curr = Number(new Date());
+ const ms = curr - (prevTime || curr);
+ self.diff = ms;
+ self.prev = prevTime;
+ self.curr = curr;
+ prevTime = curr;
+
+ args[0] = createDebug.coerce(args[0]);
+
+ if (typeof args[0] !== 'string') {
+ // Anything else let's inspect with %O
+ args.unshift('%O');
+ }
+
+ // Apply any `formatters` transformations
+ let index = 0;
+ args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
+ // If we encounter an escaped % then don't increase the array index
+ if (match === '%%') {
+ return '%';
+ }
+ index++;
+ const formatter = createDebug.formatters[format];
+ if (typeof formatter === 'function') {
+ const val = args[index];
+ match = formatter.call(self, val);
+
+ // Now we need to remove `args[index]` since it's inlined in the `format`
+ args.splice(index, 1);
+ index--;
+ }
+ return match;
+ });
+
+ // Apply env-specific formatting (colors, etc.)
+ createDebug.formatArgs.call(self, args);
+
+ const logFn = self.log || createDebug.log;
+ logFn.apply(self, args);
+ }
+
+ debug.namespace = namespace;
+ debug.useColors = createDebug.useColors();
+ debug.color = createDebug.selectColor(namespace);
+ debug.extend = extend;
+ debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
+
+ Object.defineProperty(debug, 'enabled', {
+ enumerable: true,
+ configurable: false,
+ get: () => {
+ if (enableOverride !== null) {
+ return enableOverride;
+ }
+ if (namespacesCache !== createDebug.namespaces) {
+ namespacesCache = createDebug.namespaces;
+ enabledCache = createDebug.enabled(namespace);
+ }
+
+ return enabledCache;
+ },
+ set: v => {
+ enableOverride = v;
+ }
+ });
+
+ // Env-specific initialization logic for debug instances
+ if (typeof createDebug.init === 'function') {
+ createDebug.init(debug);
+ }
+
+ return debug;
+ }
+
+ function extend(namespace, delimiter) {
+ const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
+ newDebug.log = this.log;
+ return newDebug;
+ }
+
+ /**
+ * Enables a debug mode by namespaces. This can include modes
+ * separated by a colon and wildcards.
+ *
+ * @param {String} namespaces
+ * @api public
+ */
+ function enable(namespaces) {
+ createDebug.save(namespaces);
+ createDebug.namespaces = namespaces;
+
+ createDebug.names = [];
+ createDebug.skips = [];
+
+ const split = (typeof namespaces === 'string' ? namespaces : '')
+ .trim()
+ .replace(/\s+/g, ',')
+ .split(',')
+ .filter(Boolean);
+
+ for (const ns of split) {
+ if (ns[0] === '-') {
+ createDebug.skips.push(ns.slice(1));
+ } else {
+ createDebug.names.push(ns);
+ }
+ }
+ }
+
+ /**
+ * Checks if the given string matches a namespace template, honoring
+ * asterisks as wildcards.
+ *
+ * @param {String} search
+ * @param {String} template
+ * @return {Boolean}
+ */
+ function matchesTemplate(search, template) {
+ let searchIndex = 0;
+ let templateIndex = 0;
+ let starIndex = -1;
+ let matchIndex = 0;
+
+ while (searchIndex < search.length) {
+ if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {
+ // Match character or proceed with wildcard
+ if (template[templateIndex] === '*') {
+ starIndex = templateIndex;
+ matchIndex = searchIndex;
+ templateIndex++; // Skip the '*'
+ } else {
+ searchIndex++;
+ templateIndex++;
+ }
+ } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition
+ // Backtrack to the last '*' and try to match more characters
+ templateIndex = starIndex + 1;
+ matchIndex++;
+ searchIndex = matchIndex;
+ } else {
+ return false; // No match
+ }
+ }
+
+ // Handle trailing '*' in template
+ while (templateIndex < template.length && template[templateIndex] === '*') {
+ templateIndex++;
+ }
+
+ return templateIndex === template.length;
+ }
+
+ /**
+ * Disable debug output.
+ *
+ * @return {String} namespaces
+ * @api public
+ */
+ function disable() {
+ const namespaces = [
+ ...createDebug.names,
+ ...createDebug.skips.map(namespace => '-' + namespace)
+ ].join(',');
+ createDebug.enable('');
+ return namespaces;
+ }
+
+ /**
+ * Returns true if the given mode name is enabled, false otherwise.
+ *
+ * @param {String} name
+ * @return {Boolean}
+ * @api public
+ */
+ function enabled(name) {
+ for (const skip of createDebug.skips) {
+ if (matchesTemplate(name, skip)) {
+ return false;
+ }
+ }
+
+ for (const ns of createDebug.names) {
+ if (matchesTemplate(name, ns)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Coerce `val`.
+ *
+ * @param {Mixed} val
+ * @return {Mixed}
+ * @api private
+ */
+ function coerce(val) {
+ if (val instanceof Error) {
+ return val.stack || val.message;
+ }
+ return val;
+ }
+
+ /**
+ * XXX DO NOT USE. This is a temporary stub function.
+ * XXX It WILL be removed in the next major release.
+ */
+ function destroy() {
+ console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
+ }
+
+ createDebug.enable(createDebug.load());
+
+ return createDebug;
+}
+
+module.exports = setup;
+
+
+/***/ }),
+
+/***/ 2830:
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+/**
+ * Detect Electron renderer / nwjs process, which is node, but we should
+ * treat as a browser.
+ */
+
+if (typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs) {
+ module.exports = __webpack_require__(6110);
+} else {
+ module.exports = __webpack_require__(5108);
+}
+
+
+/***/ }),
+
+/***/ 5108:
+/***/ ((module, exports, __webpack_require__) => {
+
+/**
+ * Module dependencies.
+ */
+
+const tty = __webpack_require__(2018);
+const util = __webpack_require__(9023);
+
+/**
+ * This is the Node.js implementation of `debug()`.
+ */
+
+exports.init = init;
+exports.log = log;
+exports.formatArgs = formatArgs;
+exports.save = save;
+exports.load = load;
+exports.useColors = useColors;
+exports.destroy = util.deprecate(
+ () => {},
+ 'Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'
+);
+
+/**
+ * Colors.
+ */
+
+exports.colors = [6, 2, 3, 4, 5, 1];
+
+try {
+ // Optional dependency (as in, doesn't need to be installed, NOT like optionalDependencies in package.json)
+ // eslint-disable-next-line import/no-extraneous-dependencies
+ const supportsColor = __webpack_require__(1450);
+
+ if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
+ exports.colors = [
+ 20,
+ 21,
+ 26,
+ 27,
+ 32,
+ 33,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 56,
+ 57,
+ 62,
+ 63,
+ 68,
+ 69,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 92,
+ 93,
+ 98,
+ 99,
+ 112,
+ 113,
+ 128,
+ 129,
+ 134,
+ 135,
+ 148,
+ 149,
+ 160,
+ 161,
+ 162,
+ 163,
+ 164,
+ 165,
+ 166,
+ 167,
+ 168,
+ 169,
+ 170,
+ 171,
+ 172,
+ 173,
+ 178,
+ 179,
+ 184,
+ 185,
+ 196,
+ 197,
+ 198,
+ 199,
+ 200,
+ 201,
+ 202,
+ 203,
+ 204,
+ 205,
+ 206,
+ 207,
+ 208,
+ 209,
+ 214,
+ 215,
+ 220,
+ 221
+ ];
+ }
+} catch (error) {
+ // Swallow - we only care if `supports-color` is available; it doesn't have to be.
+}
+
+/**
+ * Build up the default `inspectOpts` object from the environment variables.
+ *
+ * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
+ */
+
+exports.inspectOpts = Object.keys(process.env).filter(key => {
+ return /^debug_/i.test(key);
+}).reduce((obj, key) => {
+ // Camel-case
+ const prop = key
+ .substring(6)
+ .toLowerCase()
+ .replace(/_([a-z])/g, (_, k) => {
+ return k.toUpperCase();
+ });
+
+ // Coerce string value into JS value
+ let val = process.env[key];
+ if (/^(yes|on|true|enabled)$/i.test(val)) {
+ val = true;
+ } else if (/^(no|off|false|disabled)$/i.test(val)) {
+ val = false;
+ } else if (val === 'null') {
+ val = null;
+ } else {
+ val = Number(val);
+ }
+
+ obj[prop] = val;
+ return obj;
+}, {});
+
+/**
+ * Is stdout a TTY? Colored output is enabled when `true`.
+ */
+
+function useColors() {
+ return 'colors' in exports.inspectOpts ?
+ Boolean(exports.inspectOpts.colors) :
+ tty.isatty(process.stderr.fd);
+}
+
+/**
+ * Adds ANSI color escape codes if enabled.
+ *
+ * @api public
+ */
+
+function formatArgs(args) {
+ const {namespace: name, useColors} = this;
+
+ if (useColors) {
+ const c = this.color;
+ const colorCode = '\u001B[3' + (c < 8 ? c : '8;5;' + c);
+ const prefix = ` ${colorCode};1m${name} \u001B[0m`;
+
+ args[0] = prefix + args[0].split('\n').join('\n' + prefix);
+ args.push(colorCode + 'm+' + module.exports.humanize(this.diff) + '\u001B[0m');
+ } else {
+ args[0] = getDate() + name + ' ' + args[0];
+ }
+}
+
+function getDate() {
+ if (exports.inspectOpts.hideDate) {
+ return '';
+ }
+ return new Date().toISOString() + ' ';
+}
+
+/**
+ * Invokes `util.formatWithOptions()` with the specified arguments and writes to stderr.
+ */
+
+function log(...args) {
+ return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + '\n');
+}
+
+/**
+ * Save `namespaces`.
+ *
+ * @param {String} namespaces
+ * @api private
+ */
+function save(namespaces) {
+ if (namespaces) {
+ process.env.DEBUG = namespaces;
+ } else {
+ // If you set a process.env field to null or undefined, it gets cast to the
+ // string 'null' or 'undefined'. Just delete instead.
+ delete process.env.DEBUG;
+ }
+}
+
+/**
+ * Load `namespaces`.
+ *
+ * @return {String} returns the previously persisted debug modes
+ * @api private
+ */
+
+function load() {
+ return process.env.DEBUG;
+}
+
+/**
+ * Init logic for `debug` instances.
+ *
+ * Create a new `inspectOpts` object in case `useColors` is set
+ * differently for a particular `debug` instance.
+ */
+
+function init(debug) {
+ debug.inspectOpts = {};
+
+ const keys = Object.keys(exports.inspectOpts);
+ for (let i = 0; i < keys.length; i++) {
+ debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
+ }
+}
+
+module.exports = __webpack_require__(897)(exports);
+
+const {formatters} = module.exports;
+
+/**
+ * Map %o to `util.inspect()`, all on a single line.
+ */
+
+formatters.o = function (v) {
+ this.inspectOpts.colors = this.useColors;
+ return util.inspect(v, this.inspectOpts)
+ .split('\n')
+ .map(str => str.trim())
+ .join(' ');
+};
+
+/**
+ * Map %O to `util.inspect()`, allowing multiple lines if needed.
+ */
+
+formatters.O = function (v) {
+ this.inspectOpts.colors = this.useColors;
+ return util.inspect(v, this.inspectOpts);
+};
+
+
+/***/ }),
+
+/***/ 3813:
+/***/ ((module) => {
+
+
+
+module.exports = (flag, argv = process.argv) => {
+ const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
+ const position = argv.indexOf(prefix + flag);
+ const terminatorPosition = argv.indexOf('--');
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
+};
+
+
+/***/ }),
+
+/***/ 1970:
+/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.HttpProxyAgent = void 0;
+const net = __importStar(__webpack_require__(9278));
+const tls = __importStar(__webpack_require__(4756));
+const debug_1 = __importDefault(__webpack_require__(2830));
+const events_1 = __webpack_require__(4434);
+const agent_base_1 = __webpack_require__(8894);
+const url_1 = __webpack_require__(7016);
+const debug = (0, debug_1.default)('http-proxy-agent');
+/**
+ * The `HttpProxyAgent` implements an HTTP Agent subclass that connects
+ * to the specified "HTTP proxy server" in order to proxy HTTP requests.
+ */
+class HttpProxyAgent extends agent_base_1.Agent {
+ constructor(proxy, opts) {
+ super(opts);
+ this.proxy = typeof proxy === 'string' ? new url_1.URL(proxy) : proxy;
+ this.proxyHeaders = opts?.headers ?? {};
+ debug('Creating new HttpProxyAgent instance: %o', this.proxy.href);
+ // Trim off the brackets from IPv6 addresses
+ const host = (this.proxy.hostname || this.proxy.host).replace(/^\[|\]$/g, '');
+ const port = this.proxy.port
+ ? parseInt(this.proxy.port, 10)
+ : this.proxy.protocol === 'https:'
+ ? 443
+ : 80;
+ this.connectOpts = {
+ ...(opts ? omit(opts, 'headers') : null),
+ host,
+ port,
+ };
+ }
+ addRequest(req, opts) {
+ req._header = null;
+ this.setRequestProps(req, opts);
+ // @ts-expect-error `addRequest()` isn't defined in `@types/node`
+ super.addRequest(req, opts);
+ }
+ setRequestProps(req, opts) {
+ const { proxy } = this;
+ const protocol = opts.secureEndpoint ? 'https:' : 'http:';
+ const hostname = req.getHeader('host') || 'localhost';
+ const base = `${protocol}//${hostname}`;
+ const url = new url_1.URL(req.path, base);
+ if (opts.port !== 80) {
+ url.port = String(opts.port);
+ }
+ // Change the `http.ClientRequest` instance's "path" field
+ // to the absolute path of the URL that will be requested.
+ req.path = String(url);
+ // Inject the `Proxy-Authorization` header if necessary.
+ const headers = typeof this.proxyHeaders === 'function'
+ ? this.proxyHeaders()
+ : { ...this.proxyHeaders };
+ if (proxy.username || proxy.password) {
+ const auth = `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`;
+ headers['Proxy-Authorization'] = `Basic ${Buffer.from(auth).toString('base64')}`;
+ }
+ if (!headers['Proxy-Connection']) {
+ headers['Proxy-Connection'] = this.keepAlive
+ ? 'Keep-Alive'
+ : 'close';
+ }
+ for (const name of Object.keys(headers)) {
+ const value = headers[name];
+ if (value) {
+ req.setHeader(name, value);
+ }
+ }
+ }
+ async connect(req, opts) {
+ req._header = null;
+ if (!req.path.includes('://')) {
+ this.setRequestProps(req, opts);
+ }
+ // At this point, the http ClientRequest's internal `_header` field
+ // might have already been set. If this is the case then we'll need
+ // to re-generate the string since we just changed the `req.path`.
+ let first;
+ let endOfHeaders;
+ debug('Regenerating stored HTTP header string for request');
+ req._implicitHeader();
+ if (req.outputData && req.outputData.length > 0) {
+ debug('Patching connection write() output buffer with updated header');
+ first = req.outputData[0].data;
+ endOfHeaders = first.indexOf('\r\n\r\n') + 4;
+ req.outputData[0].data =
+ req._header + first.substring(endOfHeaders);
+ debug('Output buffer: %o', req.outputData[0].data);
+ }
+ // Create a socket connection to the proxy server.
+ let socket;
+ if (this.proxy.protocol === 'https:') {
+ debug('Creating `tls.Socket`: %o', this.connectOpts);
+ socket = tls.connect(this.connectOpts);
+ }
+ else {
+ debug('Creating `net.Socket`: %o', this.connectOpts);
+ socket = net.connect(this.connectOpts);
+ }
+ // Wait for the socket's `connect` event, so that this `callback()`
+ // function throws instead of the `http` request machinery. This is
+ // important for i.e. `PacProxyAgent` which determines a failed proxy
+ // connection via the `callback()` function throwing.
+ await (0, events_1.once)(socket, 'connect');
+ return socket;
+ }
+}
+HttpProxyAgent.protocols = ['http', 'https'];
+exports.HttpProxyAgent = HttpProxyAgent;
+function omit(obj, ...keys) {
+ const ret = {};
+ let key;
+ for (key in obj) {
+ if (!keys.includes(key)) {
+ ret[key] = obj[key];
+ }
+ }
+ return ret;
+}
+//# sourceMappingURL=index.js.map
+
+/***/ }),
+
+/***/ 3669:
+/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.HttpsProxyAgent = void 0;
+const net = __importStar(__webpack_require__(9278));
+const tls = __importStar(__webpack_require__(4756));
+const assert_1 = __importDefault(__webpack_require__(2613));
+const debug_1 = __importDefault(__webpack_require__(2830));
+const agent_base_1 = __webpack_require__(8894);
+const url_1 = __webpack_require__(7016);
+const parse_proxy_response_1 = __webpack_require__(7943);
+const debug = (0, debug_1.default)('https-proxy-agent');
+const setServernameFromNonIpHost = (options) => {
+ if (options.servername === undefined &&
+ options.host &&
+ !net.isIP(options.host)) {
+ return {
+ ...options,
+ servername: options.host,
+ };
+ }
+ return options;
+};
+/**
+ * The `HttpsProxyAgent` implements an HTTP Agent subclass that connects to
+ * the specified "HTTP(s) proxy server" in order to proxy HTTPS requests.
+ *
+ * Outgoing HTTP requests are first tunneled through the proxy server using the
+ * `CONNECT` HTTP request method to establish a connection to the proxy server,
+ * and then the proxy server connects to the destination target and issues the
+ * HTTP request from the proxy server.
+ *
+ * `https:` requests have their socket connection upgraded to TLS once
+ * the connection to the proxy server has been established.
+ */
+class HttpsProxyAgent extends agent_base_1.Agent {
+ constructor(proxy, opts) {
+ super(opts);
+ this.options = { path: undefined };
+ this.proxy = typeof proxy === 'string' ? new url_1.URL(proxy) : proxy;
+ this.proxyHeaders = opts?.headers ?? {};
+ debug('Creating new HttpsProxyAgent instance: %o', this.proxy.href);
+ // Trim off the brackets from IPv6 addresses
+ const host = (this.proxy.hostname || this.proxy.host).replace(/^\[|\]$/g, '');
+ const port = this.proxy.port
+ ? parseInt(this.proxy.port, 10)
+ : this.proxy.protocol === 'https:'
+ ? 443
+ : 80;
+ this.connectOpts = {
+ // Attempt to negotiate http/1.1 for proxy servers that support http/2
+ ALPNProtocols: ['http/1.1'],
+ ...(opts ? omit(opts, 'headers') : null),
+ host,
+ port,
+ };
+ }
+ /**
+ * Called when the node-core HTTP client library is creating a
+ * new HTTP request.
+ */
+ async connect(req, opts) {
+ const { proxy } = this;
+ if (!opts.host) {
+ throw new TypeError('No "host" provided');
+ }
+ // Create a socket connection to the proxy server.
+ let socket;
+ if (proxy.protocol === 'https:') {
+ debug('Creating `tls.Socket`: %o', this.connectOpts);
+ socket = tls.connect(setServernameFromNonIpHost(this.connectOpts));
+ }
+ else {
+ debug('Creating `net.Socket`: %o', this.connectOpts);
+ socket = net.connect(this.connectOpts);
+ }
+ const headers = typeof this.proxyHeaders === 'function'
+ ? this.proxyHeaders()
+ : { ...this.proxyHeaders };
+ const host = net.isIPv6(opts.host) ? `[${opts.host}]` : opts.host;
+ let payload = `CONNECT ${host}:${opts.port} HTTP/1.1\r\n`;
+ // Inject the `Proxy-Authorization` header if necessary.
+ if (proxy.username || proxy.password) {
+ const auth = `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`;
+ headers['Proxy-Authorization'] = `Basic ${Buffer.from(auth).toString('base64')}`;
+ }
+ headers.Host = `${host}:${opts.port}`;
+ if (!headers['Proxy-Connection']) {
+ headers['Proxy-Connection'] = this.keepAlive
+ ? 'Keep-Alive'
+ : 'close';
+ }
+ for (const name of Object.keys(headers)) {
+ payload += `${name}: ${headers[name]}\r\n`;
+ }
+ const proxyResponsePromise = (0, parse_proxy_response_1.parseProxyResponse)(socket);
+ socket.write(`${payload}\r\n`);
+ const { connect, buffered } = await proxyResponsePromise;
+ req.emit('proxyConnect', connect);
+ this.emit('proxyConnect', connect, req);
+ if (connect.statusCode === 200) {
+ req.once('socket', resume);
+ if (opts.secureEndpoint) {
+ // The proxy is connecting to a TLS server, so upgrade
+ // this socket connection to a TLS connection.
+ debug('Upgrading socket connection to TLS');
+ return tls.connect({
+ ...omit(setServernameFromNonIpHost(opts), 'host', 'path', 'port'),
+ socket,
+ });
+ }
+ return socket;
+ }
+ // Some other status code that's not 200... need to re-play the HTTP
+ // header "data" events onto the socket once the HTTP machinery is
+ // attached so that the node core `http` can parse and handle the
+ // error status code.
+ // Close the original socket, and a new "fake" socket is returned
+ // instead, so that the proxy doesn't get the HTTP request
+ // written to it (which may contain `Authorization` headers or other
+ // sensitive data).
+ //
+ // See: https://hackerone.com/reports/541502
+ socket.destroy();
+ const fakeSocket = new net.Socket({ writable: false });
+ fakeSocket.readable = true;
+ // Need to wait for the "socket" event to re-play the "data" events.
+ req.once('socket', (s) => {
+ debug('Replaying proxy buffer for failed request');
+ (0, assert_1.default)(s.listenerCount('data') > 0);
+ // Replay the "buffered" Buffer onto the fake `socket`, since at
+ // this point the HTTP module machinery has been hooked up for
+ // the user.
+ s.push(buffered);
+ s.push(null);
+ });
+ return fakeSocket;
+ }
+}
+HttpsProxyAgent.protocols = ['http', 'https'];
+exports.HttpsProxyAgent = HttpsProxyAgent;
+function resume(socket) {
+ socket.resume();
+}
+function omit(obj, ...keys) {
+ const ret = {};
+ let key;
+ for (key in obj) {
+ if (!keys.includes(key)) {
+ ret[key] = obj[key];
+ }
+ }
+ return ret;
+}
+//# sourceMappingURL=index.js.map
+
+/***/ }),
+
+/***/ 7943:
+/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.parseProxyResponse = void 0;
+const debug_1 = __importDefault(__webpack_require__(2830));
+const debug = (0, debug_1.default)('https-proxy-agent:parse-proxy-response');
+function parseProxyResponse(socket) {
+ return new Promise((resolve, reject) => {
+ // we need to buffer any HTTP traffic that happens with the proxy before we get
+ // the CONNECT response, so that if the response is anything other than an "200"
+ // response code, then we can re-play the "data" events on the socket once the
+ // HTTP parser is hooked up...
+ let buffersLength = 0;
+ const buffers = [];
+ function read() {
+ const b = socket.read();
+ if (b)
+ ondata(b);
+ else
+ socket.once('readable', read);
+ }
+ function cleanup() {
+ socket.removeListener('end', onend);
+ socket.removeListener('error', onerror);
+ socket.removeListener('readable', read);
+ }
+ function onend() {
+ cleanup();
+ debug('onend');
+ reject(new Error('Proxy connection ended before receiving CONNECT response'));
+ }
+ function onerror(err) {
+ cleanup();
+ debug('onerror %o', err);
+ reject(err);
+ }
+ function ondata(b) {
+ buffers.push(b);
+ buffersLength += b.length;
+ const buffered = Buffer.concat(buffers, buffersLength);
+ const endOfHeaders = buffered.indexOf('\r\n\r\n');
+ if (endOfHeaders === -1) {
+ // keep buffering
+ debug('have not received end of HTTP headers yet...');
+ read();
+ return;
+ }
+ const headerParts = buffered
+ .slice(0, endOfHeaders)
+ .toString('ascii')
+ .split('\r\n');
+ const firstLine = headerParts.shift();
+ if (!firstLine) {
+ socket.destroy();
+ return reject(new Error('No header received from proxy CONNECT response'));
+ }
+ const firstLineParts = firstLine.split(' ');
+ const statusCode = +firstLineParts[1];
+ const statusText = firstLineParts.slice(2).join(' ');
+ const headers = {};
+ for (const header of headerParts) {
+ if (!header)
+ continue;
+ const firstColon = header.indexOf(':');
+ if (firstColon === -1) {
+ socket.destroy();
+ return reject(new Error(`Invalid header from proxy CONNECT response: "${header}"`));
+ }
+ const key = header.slice(0, firstColon).toLowerCase();
+ const value = header.slice(firstColon + 1).trimStart();
+ const current = headers[key];
+ if (typeof current === 'string') {
+ headers[key] = [current, value];
+ }
+ else if (Array.isArray(current)) {
+ current.push(value);
+ }
+ else {
+ headers[key] = value;
+ }
+ }
+ debug('got proxy server response: %o %o', firstLine, headers);
+ cleanup();
+ resolve({
+ connect: {
+ statusCode,
+ statusText,
+ headers,
+ },
+ buffered,
+ });
+ }
+ socket.on('error', onerror);
+ socket.on('end', onend);
+ read();
+ });
+}
+exports.parseProxyResponse = parseProxyResponse;
+//# sourceMappingURL=parse-proxy-response.js.map
+
+/***/ }),
+
+/***/ 744:
+/***/ ((module) => {
+
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+var w = d * 7;
+var y = d * 365.25;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ * - `long` verbose formatting [false]
+ *
+ * @param {String|Number} val
+ * @param {Object} [options]
+ * @throws {Error} throw an error if val is not a non-empty string or a number
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function (val, options) {
+ options = options || {};
+ var type = typeof val;
+ if (type === 'string' && val.length > 0) {
+ return parse(val);
+ } else if (type === 'number' && isFinite(val)) {
+ return options.long ? fmtLong(val) : fmtShort(val);
+ }
+ throw new Error(
+ 'val is not a non-empty string or a valid number. val=' +
+ JSON.stringify(val)
+ );
+};
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+ str = String(str);
+ if (str.length > 100) {
+ return;
+ }
+ var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
+ str
+ );
+ if (!match) {
+ return;
+ }
+ var n = parseFloat(match[1]);
+ var type = (match[2] || 'ms').toLowerCase();
+ switch (type) {
+ case 'years':
+ case 'year':
+ case 'yrs':
+ case 'yr':
+ case 'y':
+ return n * y;
+ case 'weeks':
+ case 'week':
+ case 'w':
+ return n * w;
+ case 'days':
+ case 'day':
+ case 'd':
+ return n * d;
+ case 'hours':
+ case 'hour':
+ case 'hrs':
+ case 'hr':
+ case 'h':
+ return n * h;
+ case 'minutes':
+ case 'minute':
+ case 'mins':
+ case 'min':
+ case 'm':
+ return n * m;
+ case 'seconds':
+ case 'second':
+ case 'secs':
+ case 'sec':
+ case 's':
+ return n * s;
+ case 'milliseconds':
+ case 'millisecond':
+ case 'msecs':
+ case 'msec':
+ case 'ms':
+ return n;
+ default:
+ return undefined;
+ }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtShort(ms) {
+ var msAbs = Math.abs(ms);
+ if (msAbs >= d) {
+ return Math.round(ms / d) + 'd';
+ }
+ if (msAbs >= h) {
+ return Math.round(ms / h) + 'h';
+ }
+ if (msAbs >= m) {
+ return Math.round(ms / m) + 'm';
+ }
+ if (msAbs >= s) {
+ return Math.round(ms / s) + 's';
+ }
+ return ms + 'ms';
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtLong(ms) {
+ var msAbs = Math.abs(ms);
+ if (msAbs >= d) {
+ return plural(ms, msAbs, d, 'day');
+ }
+ if (msAbs >= h) {
+ return plural(ms, msAbs, h, 'hour');
+ }
+ if (msAbs >= m) {
+ return plural(ms, msAbs, m, 'minute');
+ }
+ if (msAbs >= s) {
+ return plural(ms, msAbs, s, 'second');
+ }
+ return ms + ' ms';
+}
+
+/**
+ * Pluralization helper.
+ */
+
+function plural(ms, msAbs, n, name) {
+ var isPlural = msAbs >= n * 1.5;
+ return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
+}
+
+
+/***/ }),
+
+/***/ 1450:
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+
+const os = __webpack_require__(857);
+const tty = __webpack_require__(2018);
+const hasFlag = __webpack_require__(3813);
+
+const {env} = process;
+
+let forceColor;
+if (hasFlag('no-color') ||
+ hasFlag('no-colors') ||
+ hasFlag('color=false') ||
+ hasFlag('color=never')) {
+ forceColor = 0;
+} else if (hasFlag('color') ||
+ hasFlag('colors') ||
+ hasFlag('color=true') ||
+ hasFlag('color=always')) {
+ forceColor = 1;
+}
+
+if ('FORCE_COLOR' in env) {
+ if (env.FORCE_COLOR === 'true') {
+ forceColor = 1;
+ } else if (env.FORCE_COLOR === 'false') {
+ forceColor = 0;
+ } else {
+ forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);
+ }
+}
+
+function translateLevel(level) {
+ if (level === 0) {
+ return false;
+ }
+
+ return {
+ level,
+ hasBasic: true,
+ has256: level >= 2,
+ has16m: level >= 3
+ };
+}
+
+function supportsColor(haveStream, streamIsTTY) {
+ if (forceColor === 0) {
+ return 0;
+ }
+
+ if (hasFlag('color=16m') ||
+ hasFlag('color=full') ||
+ hasFlag('color=truecolor')) {
+ return 3;
+ }
+
+ if (hasFlag('color=256')) {
+ return 2;
+ }
+
+ if (haveStream && !streamIsTTY && forceColor === undefined) {
+ return 0;
+ }
+
+ const min = forceColor || 0;
+
+ if (env.TERM === 'dumb') {
+ return min;
+ }
+
+ if (process.platform === 'win32') {
+ // Windows 10 build 10586 is the first Windows release that supports 256 colors.
+ // Windows 10 build 14931 is the first release that supports 16m/TrueColor.
+ const osRelease = os.release().split('.');
+ if (
+ Number(osRelease[0]) >= 10 &&
+ Number(osRelease[2]) >= 10586
+ ) {
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
+ }
+
+ return 1;
+ }
+
+ if ('CI' in env) {
+ if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'GITHUB_ACTIONS', 'BUILDKITE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
+ return 1;
+ }
+
+ return min;
+ }
+
+ if ('TEAMCITY_VERSION' in env) {
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
+ }
+
+ if (env.COLORTERM === 'truecolor') {
+ return 3;
+ }
+
+ if ('TERM_PROGRAM' in env) {
+ const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
+
+ switch (env.TERM_PROGRAM) {
+ case 'iTerm.app':
+ return version >= 3 ? 3 : 2;
+ case 'Apple_Terminal':
+ return 2;
+ // No default
+ }
+ }
+
+ if (/-256(color)?$/i.test(env.TERM)) {
+ return 2;
+ }
+
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
+ return 1;
+ }
+
+ if ('COLORTERM' in env) {
+ return 1;
+ }
+
+ return min;
+}
+
+function getSupportLevel(stream) {
+ const level = supportsColor(stream, stream && stream.isTTY);
+ return translateLevel(level);
+}
+
+module.exports = {
+ supportsColor: getSupportLevel,
+ stdout: translateLevel(supportsColor(true, tty.isatty(1))),
+ stderr: translateLevel(supportsColor(true, tty.isatty(2)))
+};
+
+
+/***/ }),
+
+/***/ 30:
+/***/ ((__unused_webpack_module, exports) => {
+
+var __webpack_unused_export__;
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+__webpack_unused_export__ = ({ value: true });
+exports.w = void 0;
+/**
+ * Holds the singleton operationRequestMap, to be shared across CJS and ESM imports.
+ */
+exports.w = {
+ operationRequestMap: new WeakMap(),
+};
+//# sourceMappingURL=state-cjs.js.map
+
+/***/ }),
+
+/***/ 9437:
+/***/ ((__unused_webpack_module, exports) => {
+
+var __webpack_unused_export__;
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+__webpack_unused_export__ = ({ value: true });
+exports.w = void 0;
+/**
+ * @internal
+ *
+ * Holds the singleton instrumenter, to be shared across CJS and ESM imports.
+ */
+exports.w = {
+ instrumenterImplementation: undefined,
+};
+//# sourceMappingURL=state-cjs.js.map
+
+/***/ }),
+
+/***/ 8658:
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+// This file exists as a CommonJS module to read the version from package.json.
+// In an ESM package, using `require()` directly in .ts files requires disabling
+// ESLint rules and doesn't work reliably across all Node.js versions.
+// By keeping this as a .cjs file, we can use require() naturally and export
+// the version for the ESM modules to import.
+const packageJson = __webpack_require__(4012)
+module.exports = { version: packageJson.version }
+
+
+/***/ }),
+
+/***/ 5767:
+/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
+
+
+// EXPORTS
+__webpack_require__.d(__webpack_exports__, {
+ Zh: () => (/* binding */ ReserveCacheError),
+ yI: () => (/* binding */ ValidationError),
+ Io: () => (/* binding */ cache_saveCache)
+});
+
+// UNUSED EXPORTS: CACHE_READ_DENIED_PREFIX, CACHE_WRITE_DENIED_PREFIX, CacheReadDeniedError, CacheWriteDeniedError, FinalizeCacheError, isFeatureAvailable, restoreCache
+
+// NAMESPACE OBJECT: ./node_modules/@azure/storage-blob/dist/esm/generated/src/models/mappers.js
+var mappers_namespaceObject = {};
+__webpack_require__.r(mappers_namespaceObject);
+__webpack_require__.d(mappers_namespaceObject, {
+ AccessPolicy: () => (AccessPolicy),
+ AppendBlobAppendBlockExceptionHeaders: () => (AppendBlobAppendBlockExceptionHeaders),
+ AppendBlobAppendBlockFromUrlExceptionHeaders: () => (AppendBlobAppendBlockFromUrlExceptionHeaders),
+ AppendBlobAppendBlockFromUrlHeaders: () => (AppendBlobAppendBlockFromUrlHeaders),
+ AppendBlobAppendBlockHeaders: () => (AppendBlobAppendBlockHeaders),
+ AppendBlobCreateExceptionHeaders: () => (AppendBlobCreateExceptionHeaders),
+ AppendBlobCreateHeaders: () => (AppendBlobCreateHeaders),
+ AppendBlobSealExceptionHeaders: () => (AppendBlobSealExceptionHeaders),
+ AppendBlobSealHeaders: () => (AppendBlobSealHeaders),
+ ArrowConfiguration: () => (ArrowConfiguration),
+ ArrowField: () => (ArrowField),
+ BlobAbortCopyFromURLExceptionHeaders: () => (BlobAbortCopyFromURLExceptionHeaders),
+ BlobAbortCopyFromURLHeaders: () => (BlobAbortCopyFromURLHeaders),
+ BlobAcquireLeaseExceptionHeaders: () => (BlobAcquireLeaseExceptionHeaders),
+ BlobAcquireLeaseHeaders: () => (BlobAcquireLeaseHeaders),
+ BlobBreakLeaseExceptionHeaders: () => (BlobBreakLeaseExceptionHeaders),
+ BlobBreakLeaseHeaders: () => (BlobBreakLeaseHeaders),
+ BlobChangeLeaseExceptionHeaders: () => (BlobChangeLeaseExceptionHeaders),
+ BlobChangeLeaseHeaders: () => (BlobChangeLeaseHeaders),
+ BlobCopyFromURLExceptionHeaders: () => (BlobCopyFromURLExceptionHeaders),
+ BlobCopyFromURLHeaders: () => (BlobCopyFromURLHeaders),
+ BlobCreateSnapshotExceptionHeaders: () => (BlobCreateSnapshotExceptionHeaders),
+ BlobCreateSnapshotHeaders: () => (BlobCreateSnapshotHeaders),
+ BlobDeleteExceptionHeaders: () => (BlobDeleteExceptionHeaders),
+ BlobDeleteHeaders: () => (BlobDeleteHeaders),
+ BlobDeleteImmutabilityPolicyExceptionHeaders: () => (BlobDeleteImmutabilityPolicyExceptionHeaders),
+ BlobDeleteImmutabilityPolicyHeaders: () => (BlobDeleteImmutabilityPolicyHeaders),
+ BlobDownloadExceptionHeaders: () => (BlobDownloadExceptionHeaders),
+ BlobDownloadHeaders: () => (BlobDownloadHeaders),
+ BlobFlatListSegment: () => (BlobFlatListSegment),
+ BlobGetAccountInfoExceptionHeaders: () => (BlobGetAccountInfoExceptionHeaders),
+ BlobGetAccountInfoHeaders: () => (BlobGetAccountInfoHeaders),
+ BlobGetPropertiesExceptionHeaders: () => (BlobGetPropertiesExceptionHeaders),
+ BlobGetPropertiesHeaders: () => (BlobGetPropertiesHeaders),
+ BlobGetTagsExceptionHeaders: () => (BlobGetTagsExceptionHeaders),
+ BlobGetTagsHeaders: () => (BlobGetTagsHeaders),
+ BlobHierarchyListSegment: () => (BlobHierarchyListSegment),
+ BlobItemInternal: () => (BlobItemInternal),
+ BlobName: () => (BlobName),
+ BlobPrefix: () => (BlobPrefix),
+ BlobPropertiesInternal: () => (BlobPropertiesInternal),
+ BlobQueryExceptionHeaders: () => (BlobQueryExceptionHeaders),
+ BlobQueryHeaders: () => (BlobQueryHeaders),
+ BlobReleaseLeaseExceptionHeaders: () => (BlobReleaseLeaseExceptionHeaders),
+ BlobReleaseLeaseHeaders: () => (BlobReleaseLeaseHeaders),
+ BlobRenewLeaseExceptionHeaders: () => (BlobRenewLeaseExceptionHeaders),
+ BlobRenewLeaseHeaders: () => (BlobRenewLeaseHeaders),
+ BlobServiceProperties: () => (BlobServiceProperties),
+ BlobServiceStatistics: () => (BlobServiceStatistics),
+ BlobSetExpiryExceptionHeaders: () => (BlobSetExpiryExceptionHeaders),
+ BlobSetExpiryHeaders: () => (BlobSetExpiryHeaders),
+ BlobSetHttpHeadersExceptionHeaders: () => (BlobSetHttpHeadersExceptionHeaders),
+ BlobSetHttpHeadersHeaders: () => (BlobSetHttpHeadersHeaders),
+ BlobSetImmutabilityPolicyExceptionHeaders: () => (BlobSetImmutabilityPolicyExceptionHeaders),
+ BlobSetImmutabilityPolicyHeaders: () => (BlobSetImmutabilityPolicyHeaders),
+ BlobSetLegalHoldExceptionHeaders: () => (BlobSetLegalHoldExceptionHeaders),
+ BlobSetLegalHoldHeaders: () => (BlobSetLegalHoldHeaders),
+ BlobSetMetadataExceptionHeaders: () => (BlobSetMetadataExceptionHeaders),
+ BlobSetMetadataHeaders: () => (BlobSetMetadataHeaders),
+ BlobSetTagsExceptionHeaders: () => (BlobSetTagsExceptionHeaders),
+ BlobSetTagsHeaders: () => (BlobSetTagsHeaders),
+ BlobSetTierExceptionHeaders: () => (BlobSetTierExceptionHeaders),
+ BlobSetTierHeaders: () => (BlobSetTierHeaders),
+ BlobStartCopyFromURLExceptionHeaders: () => (BlobStartCopyFromURLExceptionHeaders),
+ BlobStartCopyFromURLHeaders: () => (BlobStartCopyFromURLHeaders),
+ BlobTag: () => (BlobTag),
+ BlobTags: () => (BlobTags),
+ BlobUndeleteExceptionHeaders: () => (BlobUndeleteExceptionHeaders),
+ BlobUndeleteHeaders: () => (BlobUndeleteHeaders),
+ Block: () => (Block),
+ BlockBlobCommitBlockListExceptionHeaders: () => (BlockBlobCommitBlockListExceptionHeaders),
+ BlockBlobCommitBlockListHeaders: () => (BlockBlobCommitBlockListHeaders),
+ BlockBlobGetBlockListExceptionHeaders: () => (BlockBlobGetBlockListExceptionHeaders),
+ BlockBlobGetBlockListHeaders: () => (BlockBlobGetBlockListHeaders),
+ BlockBlobPutBlobFromUrlExceptionHeaders: () => (BlockBlobPutBlobFromUrlExceptionHeaders),
+ BlockBlobPutBlobFromUrlHeaders: () => (BlockBlobPutBlobFromUrlHeaders),
+ BlockBlobStageBlockExceptionHeaders: () => (BlockBlobStageBlockExceptionHeaders),
+ BlockBlobStageBlockFromURLExceptionHeaders: () => (BlockBlobStageBlockFromURLExceptionHeaders),
+ BlockBlobStageBlockFromURLHeaders: () => (BlockBlobStageBlockFromURLHeaders),
+ BlockBlobStageBlockHeaders: () => (BlockBlobStageBlockHeaders),
+ BlockBlobUploadExceptionHeaders: () => (BlockBlobUploadExceptionHeaders),
+ BlockBlobUploadHeaders: () => (BlockBlobUploadHeaders),
+ BlockList: () => (BlockList),
+ BlockLookupList: () => (BlockLookupList),
+ ClearRange: () => (ClearRange),
+ ContainerAcquireLeaseExceptionHeaders: () => (ContainerAcquireLeaseExceptionHeaders),
+ ContainerAcquireLeaseHeaders: () => (ContainerAcquireLeaseHeaders),
+ ContainerBreakLeaseExceptionHeaders: () => (ContainerBreakLeaseExceptionHeaders),
+ ContainerBreakLeaseHeaders: () => (ContainerBreakLeaseHeaders),
+ ContainerChangeLeaseExceptionHeaders: () => (ContainerChangeLeaseExceptionHeaders),
+ ContainerChangeLeaseHeaders: () => (ContainerChangeLeaseHeaders),
+ ContainerCreateExceptionHeaders: () => (ContainerCreateExceptionHeaders),
+ ContainerCreateHeaders: () => (ContainerCreateHeaders),
+ ContainerDeleteExceptionHeaders: () => (ContainerDeleteExceptionHeaders),
+ ContainerDeleteHeaders: () => (ContainerDeleteHeaders),
+ ContainerFilterBlobsExceptionHeaders: () => (ContainerFilterBlobsExceptionHeaders),
+ ContainerFilterBlobsHeaders: () => (ContainerFilterBlobsHeaders),
+ ContainerGetAccessPolicyExceptionHeaders: () => (ContainerGetAccessPolicyExceptionHeaders),
+ ContainerGetAccessPolicyHeaders: () => (ContainerGetAccessPolicyHeaders),
+ ContainerGetAccountInfoExceptionHeaders: () => (ContainerGetAccountInfoExceptionHeaders),
+ ContainerGetAccountInfoHeaders: () => (ContainerGetAccountInfoHeaders),
+ ContainerGetPropertiesExceptionHeaders: () => (ContainerGetPropertiesExceptionHeaders),
+ ContainerGetPropertiesHeaders: () => (ContainerGetPropertiesHeaders),
+ ContainerItem: () => (ContainerItem),
+ ContainerListBlobFlatSegmentExceptionHeaders: () => (ContainerListBlobFlatSegmentExceptionHeaders),
+ ContainerListBlobFlatSegmentHeaders: () => (ContainerListBlobFlatSegmentHeaders),
+ ContainerListBlobHierarchySegmentExceptionHeaders: () => (ContainerListBlobHierarchySegmentExceptionHeaders),
+ ContainerListBlobHierarchySegmentHeaders: () => (ContainerListBlobHierarchySegmentHeaders),
+ ContainerProperties: () => (ContainerProperties),
+ ContainerReleaseLeaseExceptionHeaders: () => (ContainerReleaseLeaseExceptionHeaders),
+ ContainerReleaseLeaseHeaders: () => (ContainerReleaseLeaseHeaders),
+ ContainerRenameExceptionHeaders: () => (ContainerRenameExceptionHeaders),
+ ContainerRenameHeaders: () => (ContainerRenameHeaders),
+ ContainerRenewLeaseExceptionHeaders: () => (ContainerRenewLeaseExceptionHeaders),
+ ContainerRenewLeaseHeaders: () => (ContainerRenewLeaseHeaders),
+ ContainerRestoreExceptionHeaders: () => (ContainerRestoreExceptionHeaders),
+ ContainerRestoreHeaders: () => (ContainerRestoreHeaders),
+ ContainerSetAccessPolicyExceptionHeaders: () => (ContainerSetAccessPolicyExceptionHeaders),
+ ContainerSetAccessPolicyHeaders: () => (ContainerSetAccessPolicyHeaders),
+ ContainerSetMetadataExceptionHeaders: () => (ContainerSetMetadataExceptionHeaders),
+ ContainerSetMetadataHeaders: () => (ContainerSetMetadataHeaders),
+ ContainerSubmitBatchExceptionHeaders: () => (ContainerSubmitBatchExceptionHeaders),
+ ContainerSubmitBatchHeaders: () => (ContainerSubmitBatchHeaders),
+ CorsRule: () => (CorsRule),
+ DelimitedTextConfiguration: () => (DelimitedTextConfiguration),
+ FilterBlobItem: () => (FilterBlobItem),
+ FilterBlobSegment: () => (FilterBlobSegment),
+ GeoReplication: () => (GeoReplication),
+ JsonTextConfiguration: () => (JsonTextConfiguration),
+ KeyInfo: () => (KeyInfo),
+ ListBlobsFlatSegmentResponse: () => (ListBlobsFlatSegmentResponse),
+ ListBlobsHierarchySegmentResponse: () => (ListBlobsHierarchySegmentResponse),
+ ListContainersSegmentResponse: () => (ListContainersSegmentResponse),
+ Logging: () => (Logging),
+ Metrics: () => (Metrics),
+ PageBlobClearPagesExceptionHeaders: () => (PageBlobClearPagesExceptionHeaders),
+ PageBlobClearPagesHeaders: () => (PageBlobClearPagesHeaders),
+ PageBlobCopyIncrementalExceptionHeaders: () => (PageBlobCopyIncrementalExceptionHeaders),
+ PageBlobCopyIncrementalHeaders: () => (PageBlobCopyIncrementalHeaders),
+ PageBlobCreateExceptionHeaders: () => (PageBlobCreateExceptionHeaders),
+ PageBlobCreateHeaders: () => (PageBlobCreateHeaders),
+ PageBlobGetPageRangesDiffExceptionHeaders: () => (PageBlobGetPageRangesDiffExceptionHeaders),
+ PageBlobGetPageRangesDiffHeaders: () => (PageBlobGetPageRangesDiffHeaders),
+ PageBlobGetPageRangesExceptionHeaders: () => (PageBlobGetPageRangesExceptionHeaders),
+ PageBlobGetPageRangesHeaders: () => (PageBlobGetPageRangesHeaders),
+ PageBlobResizeExceptionHeaders: () => (PageBlobResizeExceptionHeaders),
+ PageBlobResizeHeaders: () => (PageBlobResizeHeaders),
+ PageBlobUpdateSequenceNumberExceptionHeaders: () => (PageBlobUpdateSequenceNumberExceptionHeaders),
+ PageBlobUpdateSequenceNumberHeaders: () => (PageBlobUpdateSequenceNumberHeaders),
+ PageBlobUploadPagesExceptionHeaders: () => (PageBlobUploadPagesExceptionHeaders),
+ PageBlobUploadPagesFromURLExceptionHeaders: () => (PageBlobUploadPagesFromURLExceptionHeaders),
+ PageBlobUploadPagesFromURLHeaders: () => (PageBlobUploadPagesFromURLHeaders),
+ PageBlobUploadPagesHeaders: () => (PageBlobUploadPagesHeaders),
+ PageList: () => (PageList),
+ PageRange: () => (PageRange),
+ QueryFormat: () => (QueryFormat),
+ QueryRequest: () => (QueryRequest),
+ QuerySerialization: () => (QuerySerialization),
+ RetentionPolicy: () => (RetentionPolicy),
+ ServiceFilterBlobsExceptionHeaders: () => (ServiceFilterBlobsExceptionHeaders),
+ ServiceFilterBlobsHeaders: () => (ServiceFilterBlobsHeaders),
+ ServiceGetAccountInfoExceptionHeaders: () => (ServiceGetAccountInfoExceptionHeaders),
+ ServiceGetAccountInfoHeaders: () => (ServiceGetAccountInfoHeaders),
+ ServiceGetPropertiesExceptionHeaders: () => (ServiceGetPropertiesExceptionHeaders),
+ ServiceGetPropertiesHeaders: () => (ServiceGetPropertiesHeaders),
+ ServiceGetStatisticsExceptionHeaders: () => (ServiceGetStatisticsExceptionHeaders),
+ ServiceGetStatisticsHeaders: () => (ServiceGetStatisticsHeaders),
+ ServiceGetUserDelegationKeyExceptionHeaders: () => (ServiceGetUserDelegationKeyExceptionHeaders),
+ ServiceGetUserDelegationKeyHeaders: () => (ServiceGetUserDelegationKeyHeaders),
+ ServiceListContainersSegmentExceptionHeaders: () => (ServiceListContainersSegmentExceptionHeaders),
+ ServiceListContainersSegmentHeaders: () => (ServiceListContainersSegmentHeaders),
+ ServiceSetPropertiesExceptionHeaders: () => (ServiceSetPropertiesExceptionHeaders),
+ ServiceSetPropertiesHeaders: () => (ServiceSetPropertiesHeaders),
+ ServiceSubmitBatchExceptionHeaders: () => (ServiceSubmitBatchExceptionHeaders),
+ ServiceSubmitBatchHeaders: () => (ServiceSubmitBatchHeaders),
+ SignedIdentifier: () => (SignedIdentifier),
+ StaticWebsite: () => (StaticWebsite),
+ StorageError: () => (StorageError),
+ UserDelegationKey: () => (UserDelegationKey)
+});
+
+// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js + 7 modules
+var lib_core = __webpack_require__(3838);
+// EXTERNAL MODULE: external "path"
+var external_path_ = __webpack_require__(6928);
+// EXTERNAL MODULE: ./node_modules/@actions/exec/lib/exec.js + 2 modules
+var exec = __webpack_require__(5260);
+// EXTERNAL MODULE: ./node_modules/@actions/glob/lib/glob.js + 17 modules
+var glob = __webpack_require__(2377);
+// EXTERNAL MODULE: ./node_modules/@actions/io/lib/io.js
+var lib_io = __webpack_require__(8701);
+// EXTERNAL MODULE: external "crypto"
+var external_crypto_ = __webpack_require__(6982);
+// EXTERNAL MODULE: external "fs"
+var external_fs_ = __webpack_require__(9896);
+// EXTERNAL MODULE: ./node_modules/semver/index.js
+var semver = __webpack_require__(2088);
+// EXTERNAL MODULE: external "util"
+var external_util_ = __webpack_require__(9023);
+;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/constants.js
+var CacheFilename;
+(function (CacheFilename) {
+ CacheFilename["Gzip"] = "cache.tgz";
+ CacheFilename["Zstd"] = "cache.tzst";
+})(CacheFilename || (CacheFilename = {}));
+var CompressionMethod;
+(function (CompressionMethod) {
+ CompressionMethod["Gzip"] = "gzip";
+ // Long range mode was added to zstd in v1.3.2.
+ // This enum is for earlier version of zstd that does not have --long support
+ CompressionMethod["ZstdWithoutLong"] = "zstd-without-long";
+ CompressionMethod["Zstd"] = "zstd";
+})(CompressionMethod || (CompressionMethod = {}));
+var ArchiveToolType;
+(function (ArchiveToolType) {
+ ArchiveToolType["GNU"] = "gnu";
+ ArchiveToolType["BSD"] = "bsd";
+})(ArchiveToolType || (ArchiveToolType = {}));
+// The default number of retry attempts.
+const DefaultRetryAttempts = 2;
+// The default delay in milliseconds between retry attempts.
+const DefaultRetryDelay = 5000;
+// Socket timeout in milliseconds during download. If no traffic is received
+// over the socket during this period, the socket is destroyed and the download
+// is aborted.
+const constants_SocketTimeout = 5000;
+// The default path of GNUtar on hosted Windows runners
+const GnuTarPathOnWindows = `${process.env['PROGRAMFILES']}\\Git\\usr\\bin\\tar.exe`;
+// The default path of BSDtar on hosted Windows runners
+const SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32\\tar.exe`;
+const TarFilename = 'cache.tar';
+const ManifestFilename = 'manifest.txt';
+const CacheFileSizeLimit = 10 * Math.pow(1024, 3); // 10GiB per repository
+// Prefix the cache backend embeds in a read-denial message (v2 twirp
+// GetCacheEntryDownloadURL error or the GHES v1 `_apis/artifactcache` 403 body).
+// Shared so cache.ts and cacheHttpClient.ts match the same contract value.
+const constants_CacheReadDeniedMessagePrefix = 'cache read denied:';
+//# sourceMappingURL=constants.js.map
+;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js
+var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+var __asyncValues = (undefined && undefined.__asyncValues) || function (o) {
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
+ var m = o[Symbol.asyncIterator], i;
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
+};
+
+
+
+
+
+
+
+
+
+
+const versionSalt = '1.0';
+// From https://github.com/actions/toolkit/blob/main/packages/tool-cache/src/tool-cache.ts#L23
+function createTempDirectory() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const IS_WINDOWS = process.platform === 'win32';
+ let tempDirectory = process.env['RUNNER_TEMP'] || '';
+ if (!tempDirectory) {
+ let baseLocation;
+ if (IS_WINDOWS) {
+ // On Windows use the USERPROFILE env variable
+ baseLocation = process.env['USERPROFILE'] || 'C:\\';
+ }
+ else {
+ if (process.platform === 'darwin') {
+ baseLocation = '/Users';
+ }
+ else {
+ baseLocation = '/home';
+ }
+ }
+ tempDirectory = external_path_.join(baseLocation, 'actions', 'temp');
+ }
+ const dest = external_path_.join(tempDirectory, external_crypto_.randomUUID());
+ yield lib_io/* mkdirP */.U$(dest);
+ return dest;
+ });
+}
+function getArchiveFileSizeInBytes(filePath) {
+ return external_fs_.statSync(filePath).size;
+}
+function resolvePaths(patterns) {
+ return __awaiter(this, void 0, void 0, function* () {
+ var _a, e_1, _b, _c;
+ var _d;
+ const paths = [];
+ const workspace = (_d = process.env['GITHUB_WORKSPACE']) !== null && _d !== void 0 ? _d : process.cwd();
+ const globber = yield glob/* create */.v(patterns.join('\n'), {
+ implicitDescendants: false
+ });
+ try {
+ for (var _e = true, _f = __asyncValues(globber.globGenerator()), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) {
+ _c = _g.value;
+ _e = false;
+ const file = _c;
+ const relativeFile = external_path_.relative(workspace, file)
+ .replace(new RegExp(`\\${external_path_.sep}`, 'g'), '/');
+ lib_core/* debug */.Yz(`Matched: ${relativeFile}`);
+ // Paths are made relative so the tar entries are all relative to the root of the workspace.
+ if (relativeFile === '') {
+ // path.relative returns empty string if workspace and file are equal
+ paths.push('.');
+ }
+ else {
+ paths.push(`${relativeFile}`);
+ }
+ }
+ }
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
+ finally {
+ try {
+ if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
+ }
+ finally { if (e_1) throw e_1.error; }
+ }
+ return paths;
+ });
+}
+function unlinkFile(filePath) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return external_util_.promisify(external_fs_.unlink)(filePath);
+ });
+}
+function getVersion(app_1) {
+ return __awaiter(this, arguments, void 0, function* (app, additionalArgs = []) {
+ let versionOutput = '';
+ additionalArgs.push('--version');
+ lib_core/* debug */.Yz(`Checking ${app} ${additionalArgs.join(' ')}`);
+ try {
+ yield exec/* exec */.m(`${app}`, additionalArgs, {
+ ignoreReturnCode: true,
+ silent: true,
+ listeners: {
+ stdout: (data) => (versionOutput += data.toString()),
+ stderr: (data) => (versionOutput += data.toString())
+ }
+ });
+ }
+ catch (err) {
+ lib_core/* debug */.Yz(err.message);
+ }
+ versionOutput = versionOutput.trim();
+ lib_core/* debug */.Yz(versionOutput);
+ return versionOutput;
+ });
+}
+// Use zstandard if possible to maximize cache performance
+function getCompressionMethod() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const versionOutput = yield getVersion('zstd', ['--quiet']);
+ const version = semver.clean(versionOutput);
+ lib_core/* debug */.Yz(`zstd version: ${version}`);
+ if (versionOutput === '') {
+ return CompressionMethod.Gzip;
+ }
+ else {
+ return CompressionMethod.ZstdWithoutLong;
+ }
+ });
+}
+function getCacheFileName(compressionMethod) {
+ return compressionMethod === CompressionMethod.Gzip
+ ? CacheFilename.Gzip
+ : CacheFilename.Zstd;
+}
+function getGnuTarPathOnWindows() {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (external_fs_.existsSync(GnuTarPathOnWindows)) {
+ return GnuTarPathOnWindows;
+ }
+ const versionOutput = yield getVersion('tar');
+ return versionOutput.toLowerCase().includes('gnu tar') ? lib_io/* which */.K7('tar') : '';
+ });
+}
+function assertDefined(name, value) {
+ if (value === undefined) {
+ throw Error(`Expected ${name} but value was undefiend`);
+ }
+ return value;
+}
+function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) {
+ // don't pass changes upstream
+ const components = paths.slice();
+ // Add compression method to cache version to restore
+ // compressed cache as per compression method
+ if (compressionMethod) {
+ components.push(compressionMethod);
+ }
+ // Only check for windows platforms if enableCrossOsArchive is false
+ if (process.platform === 'win32' && !enableCrossOsArchive) {
+ components.push('windows-only');
+ }
+ // Add salt to cache version to support breaking changes in cache entry
+ components.push(versionSalt);
+ return external_crypto_.createHash('sha256').update(components.join('|')).digest('hex');
+}
+function getRuntimeToken() {
+ const token = process.env['ACTIONS_RUNTIME_TOKEN'];
+ if (!token) {
+ throw new Error('Unable to get the ACTIONS_RUNTIME_TOKEN env variable');
+ }
+ return token;
+}
+//# sourceMappingURL=cacheUtils.js.map
+// EXTERNAL MODULE: ./node_modules/@actions/http-client/lib/index.js + 1 modules
+var lib = __webpack_require__(4942);
+// EXTERNAL MODULE: ./node_modules/@actions/http-client/lib/auth.js
+var auth = __webpack_require__(2145);
+// EXTERNAL MODULE: external "url"
+var external_url_ = __webpack_require__(7016);
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/abort-controller/AbortError.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * This error is thrown when an asynchronous operation has been aborted.
+ * Check for this error by testing the `name` that the name property of the
+ * error matches `"AbortError"`.
+ *
+ * @example
+ * ```ts snippet:ReadmeSampleAbortError
+ * import { AbortError } from "@typespec/ts-http-runtime";
+ *
+ * async function doAsyncWork(options: { abortSignal: AbortSignal }): Promise {
+ * if (options.abortSignal.aborted) {
+ * throw new AbortError();
+ * }
+ *
+ * // do async work
+ * }
+ *
+ * const controller = new AbortController();
+ * controller.abort();
+ *
+ * try {
+ * doAsyncWork({ abortSignal: controller.signal });
+ * } catch (e) {
+ * if (e instanceof Error && e.name === "AbortError") {
+ * // handle abort error here.
+ * }
+ * }
+ * ```
+ */
+class AbortError extends Error {
+ constructor(message) {
+ super(message);
+ this.name = "AbortError";
+ }
+}
+//# sourceMappingURL=AbortError.js.map
+// EXTERNAL MODULE: external "node:os"
+var external_node_os_ = __webpack_require__(8161);
+// EXTERNAL MODULE: external "node:util"
+var external_node_util_ = __webpack_require__(7975);
+// EXTERNAL MODULE: external "node:process"
+var external_node_process_ = __webpack_require__(1708);
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/logger/log.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+function log(message, ...args) {
+ external_node_process_.stderr.write(`${external_node_util_.format(message, ...args)}${external_node_os_.EOL}`);
+}
+//# sourceMappingURL=log.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/env.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Returns the value of the specified environment variable.
+ *
+ * @internal
+ */
+function getEnvironmentVariable(name) {
+ return external_node_process_.env[name];
+}
+/**
+ * Emits a Node.js process warning.
+ *
+ * @internal
+ */
+function env_emitNodeWarning(warning) {
+ process.emitWarning(warning);
+}
+/**
+ * A constant that indicates whether the environment the code is running is a Web Browser.
+ */
+const isBrowser = false;
+/**
+ * A constant that indicates whether the environment the code is running is a Web Worker.
+ */
+const isWebWorker = false;
+/**
+ * A constant that indicates whether the environment the code is running is Deno.
+ */
+const isDeno = typeof external_node_process_.versions.deno === "string" && external_node_process_.versions.deno.length > 0;
+/**
+ * A constant that indicates whether the environment the code is running is Bun.sh.
+ */
+const isBun = typeof external_node_process_.versions.bun === "string" && external_node_process_.versions.bun.length > 0;
+/**
+ * A constant that indicates whether the environment the code is running is a Node.js compatible environment.
+ */
+const env_isNodeLike = true;
+/**
+ * A constant that indicates whether the environment the code is running is Node.JS.
+ */
+const isNodeRuntime = !isBun && !isDeno;
+/**
+ * A constant that indicates whether the environment the code is running is in React-Native.
+ */
+const isReactNative = false;
+//# sourceMappingURL=env.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/logger/debug.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+const debugEnvVariable = getEnvironmentVariable("DEBUG");
+let enabledString;
+let enabledNamespaces = [];
+let skippedNamespaces = [];
+const debuggers = [];
+if (debugEnvVariable) {
+ enable(debugEnvVariable);
+}
+const debugObj = Object.assign((namespace) => {
+ return createDebugger(namespace);
+}, {
+ enable,
+ enabled,
+ disable,
+ log: log,
+});
+function enable(namespaces) {
+ enabledString = namespaces;
+ enabledNamespaces = [];
+ skippedNamespaces = [];
+ const namespaceList = namespaces.split(",").map((ns) => ns.trim());
+ for (const ns of namespaceList) {
+ if (ns.startsWith("-")) {
+ skippedNamespaces.push(ns.substring(1));
+ }
+ else {
+ enabledNamespaces.push(ns);
+ }
+ }
+ for (const instance of debuggers) {
+ instance.enabled = enabled(instance.namespace);
+ }
+}
+function enabled(namespace) {
+ if (namespace.endsWith("*")) {
+ return true;
+ }
+ for (const skipped of skippedNamespaces) {
+ if (namespaceMatches(namespace, skipped)) {
+ return false;
+ }
+ }
+ for (const enabledNamespace of enabledNamespaces) {
+ if (namespaceMatches(namespace, enabledNamespace)) {
+ return true;
+ }
+ }
+ return false;
+}
+/**
+ * Given a namespace, check if it matches a pattern.
+ * Patterns only have a single wildcard character which is *.
+ * The behavior of * is that it matches zero or more other characters.
+ */
+function namespaceMatches(namespace, patternToMatch) {
+ // simple case, no pattern matching required
+ if (patternToMatch.indexOf("*") === -1) {
+ return namespace === patternToMatch;
+ }
+ let pattern = patternToMatch;
+ // normalize successive * if needed
+ if (patternToMatch.indexOf("**") !== -1) {
+ const patternParts = [];
+ let lastCharacter = "";
+ for (const character of patternToMatch) {
+ if (character === "*" && lastCharacter === "*") {
+ continue;
+ }
+ else {
+ lastCharacter = character;
+ patternParts.push(character);
+ }
+ }
+ pattern = patternParts.join("");
+ }
+ let namespaceIndex = 0;
+ let patternIndex = 0;
+ const patternLength = pattern.length;
+ const namespaceLength = namespace.length;
+ let lastWildcard = -1;
+ let lastWildcardNamespace = -1;
+ while (namespaceIndex < namespaceLength && patternIndex < patternLength) {
+ if (pattern[patternIndex] === "*") {
+ lastWildcard = patternIndex;
+ patternIndex++;
+ if (patternIndex === patternLength) {
+ // if wildcard is the last character, it will match the remaining namespace string
+ return true;
+ }
+ // now we let the wildcard eat characters until we match the next literal in the pattern
+ while (namespace[namespaceIndex] !== pattern[patternIndex]) {
+ namespaceIndex++;
+ // reached the end of the namespace without a match
+ if (namespaceIndex === namespaceLength) {
+ return false;
+ }
+ }
+ // now that we have a match, let's try to continue on
+ // however, it's possible we could find a later match
+ // so keep a reference in case we have to backtrack
+ lastWildcardNamespace = namespaceIndex;
+ namespaceIndex++;
+ patternIndex++;
+ continue;
+ }
+ else if (pattern[patternIndex] === namespace[namespaceIndex]) {
+ // simple case: literal pattern matches so keep going
+ patternIndex++;
+ namespaceIndex++;
+ }
+ else if (lastWildcard >= 0) {
+ // special case: we don't have a literal match, but there is a previous wildcard
+ // which we can backtrack to and try having the wildcard eat the match instead
+ patternIndex = lastWildcard + 1;
+ namespaceIndex = lastWildcardNamespace + 1;
+ // we've reached the end of the namespace without a match
+ if (namespaceIndex === namespaceLength) {
+ return false;
+ }
+ // similar to the previous logic, let's keep going until we find the next literal match
+ while (namespace[namespaceIndex] !== pattern[patternIndex]) {
+ namespaceIndex++;
+ if (namespaceIndex === namespaceLength) {
+ return false;
+ }
+ }
+ lastWildcardNamespace = namespaceIndex;
+ namespaceIndex++;
+ patternIndex++;
+ continue;
+ }
+ else {
+ return false;
+ }
+ }
+ const namespaceDone = namespaceIndex === namespace.length;
+ const patternDone = patternIndex === pattern.length;
+ // this is to detect the case of an unneeded final wildcard
+ // e.g. the pattern `ab*` should match the string `ab`
+ const trailingWildCard = patternIndex === pattern.length - 1 && pattern[patternIndex] === "*";
+ return namespaceDone && (patternDone || trailingWildCard);
+}
+function disable() {
+ const result = enabledString || "";
+ enable("");
+ return result;
+}
+function createDebugger(namespace) {
+ const newDebugger = Object.assign(debug, {
+ enabled: enabled(namespace),
+ destroy,
+ log: debugObj.log,
+ namespace,
+ extend,
+ });
+ function debug(...args) {
+ if (!newDebugger.enabled) {
+ return;
+ }
+ if (args.length > 0) {
+ args[0] = `${namespace} ${args[0]}`;
+ }
+ newDebugger.log(...args);
+ }
+ debuggers.push(newDebugger);
+ return newDebugger;
+}
+function destroy() {
+ const index = debuggers.indexOf(this);
+ if (index >= 0) {
+ debuggers.splice(index, 1);
+ return true;
+ }
+ return false;
+}
+function extend(namespace) {
+ const newDebugger = createDebugger(`${this.namespace}:${namespace}`);
+ newDebugger.log = this.log;
+ return newDebugger;
+}
+/* harmony default export */ const debug = (debugObj);
+//# sourceMappingURL=debug.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/logger/logger.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+const TYPESPEC_RUNTIME_LOG_LEVELS = ["verbose", "info", "warning", "error"];
+const levelMap = {
+ verbose: 400,
+ info: 300,
+ warning: 200,
+ error: 100,
+};
+function patchLogMethod(parent, child) {
+ child.log = (...args) => {
+ parent.log(...args);
+ };
+}
+function isTypeSpecRuntimeLogLevel(level) {
+ return TYPESPEC_RUNTIME_LOG_LEVELS.includes(level);
+}
+/**
+ * Creates a logger context base on the provided options.
+ * @param options - The options for creating a logger context.
+ * @returns The logger context.
+ */
+function createLoggerContext(options) {
+ const registeredLoggers = new Set();
+ const logLevelFromEnv = getEnvironmentVariable(options.logLevelEnvVarName);
+ let logLevel;
+ const clientLogger = debug(options.namespace);
+ clientLogger.log = (...args) => {
+ debug.log(...args);
+ };
+ function contextSetLogLevel(level) {
+ if (level && !isTypeSpecRuntimeLogLevel(level)) {
+ throw new Error(`Unknown log level '${level}'. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join(",")}`);
+ }
+ logLevel = level;
+ const enabledNamespaces = [];
+ for (const logger of registeredLoggers) {
+ if (shouldEnable(logger)) {
+ enabledNamespaces.push(logger.namespace);
+ }
+ }
+ debug.enable(enabledNamespaces.join(","));
+ }
+ if (logLevelFromEnv) {
+ // avoid calling setLogLevel because we don't want a mis-set environment variable to crash
+ if (isTypeSpecRuntimeLogLevel(logLevelFromEnv)) {
+ contextSetLogLevel(logLevelFromEnv);
+ }
+ else {
+ console.error(`${options.logLevelEnvVarName} set to unknown log level '${logLevelFromEnv}'; logging is not enabled. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join(", ")}.`);
+ }
+ }
+ function shouldEnable(logger) {
+ return Boolean(logLevel && levelMap[logger.level] <= levelMap[logLevel]);
+ }
+ function createLogger(parent, level) {
+ const logger = Object.assign(parent.extend(level), {
+ level,
+ });
+ patchLogMethod(parent, logger);
+ if (shouldEnable(logger)) {
+ const enabledNamespaces = debug.disable();
+ debug.enable(enabledNamespaces + "," + logger.namespace);
+ }
+ registeredLoggers.add(logger);
+ return logger;
+ }
+ function contextGetLogLevel() {
+ return logLevel;
+ }
+ function contextCreateClientLogger(namespace) {
+ const clientRootLogger = clientLogger.extend(namespace);
+ patchLogMethod(clientLogger, clientRootLogger);
+ return {
+ error: createLogger(clientRootLogger, "error"),
+ warning: createLogger(clientRootLogger, "warning"),
+ info: createLogger(clientRootLogger, "info"),
+ verbose: createLogger(clientRootLogger, "verbose"),
+ };
+ }
+ return {
+ setLogLevel: contextSetLogLevel,
+ getLogLevel: contextGetLogLevel,
+ createClientLogger: contextCreateClientLogger,
+ logger: clientLogger,
+ };
+}
+const context = createLoggerContext({
+ logLevelEnvVarName: "TYPESPEC_RUNTIME_LOG_LEVEL",
+ namespace: "typeSpecRuntime",
+});
+/**
+ * Immediately enables logging at the specified log level. If no level is specified, logging is disabled.
+ * @param level - The log level to enable for logging.
+ * Options from most verbose to least verbose are:
+ * - verbose
+ * - info
+ * - warning
+ * - error
+ */
+// eslint-disable-next-line @typescript-eslint/no-redeclare
+const TypeSpecRuntimeLogger = context.logger;
+/**
+ * Retrieves the currently specified log level.
+ */
+function setLogLevel(logLevel) {
+ context.setLogLevel(logLevel);
+}
+/**
+ * Retrieves the currently specified log level.
+ */
+function getLogLevel() {
+ return context.getLogLevel();
+}
+/**
+ * Creates a logger for use by the SDKs that inherits from `TypeSpecRuntimeLogger`.
+ * @param namespace - The name of the SDK package.
+ * @hidden
+ */
+function createClientLogger(namespace) {
+ return context.createClientLogger(namespace);
+}
+//# sourceMappingURL=logger.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/httpHeaders.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+function normalizeName(name) {
+ return name.toLowerCase();
+}
+/**
+ * Removes CR and LF characters from a header value to prevent obs-fold
+ * (line folding) sequences, as forbidden by RFC 7230 §3.2.4.
+ * @param value - The header value to sanitize.
+ */
+function normalizeValue(value) {
+ return String(value)
+ .trim()
+ .replace(/[\r\n]/g, "");
+}
+function* headerIterator(map) {
+ for (const entry of map.values()) {
+ yield [entry.name, entry.value];
+ }
+}
+class HttpHeadersImpl {
+ _headersMap;
+ constructor(rawHeaders) {
+ this._headersMap = new Map();
+ if (rawHeaders) {
+ for (const headerName of Object.keys(rawHeaders)) {
+ this.set(headerName, rawHeaders[headerName]);
+ }
+ }
+ }
+ /**
+ * Set a header in this collection with the provided name and value. The name is
+ * case-insensitive.
+ * @param name - The name of the header to set. This value is case-insensitive.
+ * @param value - The value of the header to set.
+ */
+ set(name, value) {
+ this._headersMap.set(normalizeName(name), { name, value: normalizeValue(value) });
+ }
+ /**
+ * Get the header value for the provided header name, or undefined if no header exists in this
+ * collection with the provided name.
+ * @param name - The name of the header. This value is case-insensitive.
+ */
+ get(name) {
+ return this._headersMap.get(normalizeName(name))?.value;
+ }
+ /**
+ * Get whether or not this header collection contains a header entry for the provided header name.
+ * @param name - The name of the header to set. This value is case-insensitive.
+ */
+ has(name) {
+ return this._headersMap.has(normalizeName(name));
+ }
+ /**
+ * Remove the header with the provided headerName.
+ * @param name - The name of the header to remove.
+ */
+ delete(name) {
+ this._headersMap.delete(normalizeName(name));
+ }
+ /**
+ * Get the JSON object representation of this HTTP header collection.
+ */
+ toJSON(options = {}) {
+ const result = {};
+ if (options.preserveCase) {
+ for (const entry of this._headersMap.values()) {
+ result[entry.name] = entry.value;
+ }
+ }
+ else {
+ for (const [normalizedName, entry] of this._headersMap) {
+ result[normalizedName] = entry.value;
+ }
+ }
+ return result;
+ }
+ /**
+ * Get the string representation of this HTTP header collection.
+ */
+ toString() {
+ return JSON.stringify(this.toJSON({ preserveCase: true }));
+ }
+ /**
+ * Iterate over tuples of header [name, value] pairs.
+ */
+ [Symbol.iterator]() {
+ return headerIterator(this._headersMap);
+ }
+}
+/**
+ * Creates an object that satisfies the `HttpHeaders` interface.
+ * @param rawHeaders - A simple object representing initial headers
+ */
+function httpHeaders_createHttpHeaders(rawHeaders) {
+ return new HttpHeadersImpl(rawHeaders);
+}
+//# sourceMappingURL=httpHeaders.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/uuidUtils.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Generated Universally Unique Identifier
+ *
+ * @returns RFC4122 v4 UUID.
+ */
+function randomUUID() {
+ return globalThis.crypto.randomUUID();
+}
+//# sourceMappingURL=uuidUtils.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/pipelineRequest.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+class PipelineRequestImpl {
+ url;
+ method;
+ headers;
+ timeout;
+ withCredentials;
+ body;
+ multipartBody;
+ formData;
+ streamResponseStatusCodes;
+ enableBrowserStreams;
+ proxySettings;
+ disableKeepAlive;
+ abortSignal;
+ requestId;
+ allowInsecureConnection;
+ onUploadProgress;
+ onDownloadProgress;
+ requestOverrides;
+ authSchemes;
+ constructor(options) {
+ this.url = options.url;
+ this.body = options.body;
+ this.headers = options.headers ?? httpHeaders_createHttpHeaders();
+ this.method = options.method ?? "GET";
+ this.timeout = options.timeout ?? 0;
+ this.multipartBody = options.multipartBody;
+ this.formData = options.formData;
+ this.disableKeepAlive = options.disableKeepAlive ?? false;
+ this.proxySettings = options.proxySettings;
+ this.streamResponseStatusCodes = options.streamResponseStatusCodes;
+ this.withCredentials = options.withCredentials ?? false;
+ this.abortSignal = options.abortSignal;
+ this.onUploadProgress = options.onUploadProgress;
+ this.onDownloadProgress = options.onDownloadProgress;
+ this.requestId = options.requestId || randomUUID();
+ this.allowInsecureConnection = options.allowInsecureConnection ?? false;
+ this.enableBrowserStreams = options.enableBrowserStreams ?? false;
+ this.requestOverrides = options.requestOverrides;
+ this.authSchemes = options.authSchemes;
+ }
+}
+/**
+ * Creates a new pipeline request with the given options.
+ * This method is to allow for the easy setting of default values and not required.
+ * @param options - The options to create the request with.
+ */
+function pipelineRequest_createPipelineRequest(options) {
+ return new PipelineRequestImpl(options);
+}
+//# sourceMappingURL=pipelineRequest.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/pipeline.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+const ValidPhaseNames = new Set(["Deserialize", "Serialize", "Retry", "Sign"]);
+/**
+ * A private implementation of Pipeline.
+ * Do not export this class from the package.
+ * @internal
+ */
+class HttpPipeline {
+ _policies = [];
+ _orderedPolicies;
+ constructor(policies) {
+ this._policies = policies?.slice(0) ?? [];
+ this._orderedPolicies = undefined;
+ }
+ addPolicy(policy, options = {}) {
+ if (options.phase && options.afterPhase) {
+ throw new Error("Policies inside a phase cannot specify afterPhase.");
+ }
+ if (options.phase && !ValidPhaseNames.has(options.phase)) {
+ throw new Error(`Invalid phase name: ${options.phase}`);
+ }
+ if (options.afterPhase && !ValidPhaseNames.has(options.afterPhase)) {
+ throw new Error(`Invalid afterPhase name: ${options.afterPhase}`);
+ }
+ this._policies.push({
+ policy,
+ options,
+ });
+ this._orderedPolicies = undefined;
+ }
+ removePolicy(options) {
+ const removedPolicies = [];
+ this._policies = this._policies.filter((policyDescriptor) => {
+ if ((options.name && policyDescriptor.policy.name === options.name) ||
+ (options.phase && policyDescriptor.options.phase === options.phase)) {
+ removedPolicies.push(policyDescriptor.policy);
+ return false;
+ }
+ else {
+ return true;
+ }
+ });
+ this._orderedPolicies = undefined;
+ return removedPolicies;
+ }
+ sendRequest(httpClient, request) {
+ const policies = this.getOrderedPolicies();
+ const pipeline = policies.reduceRight((next, policy) => {
+ return (req) => {
+ return policy.sendRequest(req, next);
+ };
+ }, (req) => httpClient.sendRequest(req));
+ return pipeline(request);
+ }
+ getOrderedPolicies() {
+ if (!this._orderedPolicies) {
+ this._orderedPolicies = this.orderPolicies();
+ }
+ return this._orderedPolicies;
+ }
+ clone() {
+ return new HttpPipeline(this._policies);
+ }
+ static create() {
+ return new HttpPipeline();
+ }
+ orderPolicies() {
+ /**
+ * The goal of this method is to reliably order pipeline policies
+ * based on their declared requirements when they were added.
+ *
+ * Order is first determined by phase:
+ *
+ * 1. Serialize Phase
+ * 2. Policies not in a phase
+ * 3. Deserialize Phase
+ * 4. Retry Phase
+ * 5. Sign Phase
+ *
+ * Within each phase, policies are executed in the order
+ * they were added unless they were specified to execute
+ * before/after other policies or after a particular phase.
+ *
+ * To determine the final order, we will walk the policy list
+ * in phase order multiple times until all dependencies are
+ * satisfied.
+ *
+ * `afterPolicies` are the set of policies that must be
+ * executed before a given policy. This requirement is
+ * considered satisfied when each of the listed policies
+ * have been scheduled.
+ *
+ * `beforePolicies` are the set of policies that must be
+ * executed after a given policy. Since this dependency
+ * can be expressed by converting it into a equivalent
+ * `afterPolicies` declarations, they are normalized
+ * into that form for simplicity.
+ *
+ * An `afterPhase` dependency is considered satisfied when all
+ * policies in that phase have scheduled.
+ *
+ */
+ const result = [];
+ // Track all policies we know about.
+ const policyMap = new Map();
+ function createPhase(name) {
+ return {
+ name,
+ policies: new Set(),
+ hasRun: false,
+ hasAfterPolicies: false,
+ };
+ }
+ // Track policies for each phase.
+ const serializePhase = createPhase("Serialize");
+ const noPhase = createPhase("None");
+ const deserializePhase = createPhase("Deserialize");
+ const retryPhase = createPhase("Retry");
+ const signPhase = createPhase("Sign");
+ // a list of phases in order
+ const orderedPhases = [serializePhase, noPhase, deserializePhase, retryPhase, signPhase];
+ // Small helper function to map phase name to each Phase
+ function getPhase(phase) {
+ if (phase === "Retry") {
+ return retryPhase;
+ }
+ else if (phase === "Serialize") {
+ return serializePhase;
+ }
+ else if (phase === "Deserialize") {
+ return deserializePhase;
+ }
+ else if (phase === "Sign") {
+ return signPhase;
+ }
+ else {
+ return noPhase;
+ }
+ }
+ // First walk each policy and create a node to track metadata.
+ for (const descriptor of this._policies) {
+ const policy = descriptor.policy;
+ const options = descriptor.options;
+ const policyName = policy.name;
+ if (policyMap.has(policyName)) {
+ throw new Error("Duplicate policy names not allowed in pipeline");
+ }
+ const node = {
+ policy,
+ dependsOn: new Set(),
+ dependants: new Set(),
+ };
+ if (options.afterPhase) {
+ node.afterPhase = getPhase(options.afterPhase);
+ node.afterPhase.hasAfterPolicies = true;
+ }
+ policyMap.set(policyName, node);
+ const phase = getPhase(options.phase);
+ phase.policies.add(node);
+ }
+ // Now that each policy has a node, connect dependency references.
+ for (const descriptor of this._policies) {
+ const { policy, options } = descriptor;
+ const policyName = policy.name;
+ const node = policyMap.get(policyName);
+ if (!node) {
+ throw new Error(`Missing node for policy ${policyName}`);
+ }
+ if (options.afterPolicies) {
+ for (const afterPolicyName of options.afterPolicies) {
+ const afterNode = policyMap.get(afterPolicyName);
+ if (afterNode) {
+ // Linking in both directions helps later
+ // when we want to notify dependants.
+ node.dependsOn.add(afterNode);
+ afterNode.dependants.add(node);
+ }
+ }
+ }
+ if (options.beforePolicies) {
+ for (const beforePolicyName of options.beforePolicies) {
+ const beforeNode = policyMap.get(beforePolicyName);
+ if (beforeNode) {
+ // To execute before another node, make it
+ // depend on the current node.
+ beforeNode.dependsOn.add(node);
+ node.dependants.add(beforeNode);
+ }
+ }
+ }
+ }
+ function walkPhase(phase) {
+ phase.hasRun = true;
+ // Sets iterate in insertion order
+ for (const node of phase.policies) {
+ if (node.afterPhase && (!node.afterPhase.hasRun || node.afterPhase.policies.size)) {
+ // If this node is waiting on a phase to complete,
+ // we need to skip it for now.
+ // Even if the phase is empty, we should wait for it
+ // to be walked to avoid re-ordering policies.
+ continue;
+ }
+ if (node.dependsOn.size === 0) {
+ // If there's nothing else we're waiting for, we can
+ // add this policy to the result list.
+ result.push(node.policy);
+ // Notify anything that depends on this policy that
+ // the policy has been scheduled.
+ for (const dependant of node.dependants) {
+ dependant.dependsOn.delete(node);
+ }
+ policyMap.delete(node.policy.name);
+ phase.policies.delete(node);
+ }
+ }
+ }
+ function walkPhases() {
+ for (const phase of orderedPhases) {
+ walkPhase(phase);
+ // if the phase isn't complete
+ if (phase.policies.size > 0 && phase !== noPhase) {
+ if (!noPhase.hasRun) {
+ // Try running noPhase to see if that unblocks this phase next tick.
+ // This can happen if a phase that happens before noPhase
+ // is waiting on a noPhase policy to complete.
+ walkPhase(noPhase);
+ }
+ // Don't proceed to the next phase until this phase finishes.
+ return;
+ }
+ if (phase.hasAfterPolicies) {
+ // Run any policies unblocked by this phase
+ walkPhase(noPhase);
+ }
+ }
+ }
+ // Iterate until we've put every node in the result list.
+ let iteration = 0;
+ while (policyMap.size > 0) {
+ iteration++;
+ const initialResultLength = result.length;
+ // Keep walking each phase in order until we can order every node.
+ walkPhases();
+ // The result list *should* get at least one larger each time
+ // after the first full pass.
+ // Otherwise, we're going to loop forever.
+ if (result.length <= initialResultLength && iteration > 1) {
+ throw new Error("Cannot satisfy policy dependencies due to requirements cycle.");
+ }
+ }
+ return result;
+ }
+}
+/**
+ * Creates a totally empty pipeline.
+ * Useful for testing or creating a custom one.
+ */
+function pipeline_createEmptyPipeline() {
+ return HttpPipeline.create();
+}
+//# sourceMappingURL=pipeline.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/object.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Helper to determine when an input is a generic JS object.
+ * @returns true when input is an object type that is not null, Array, RegExp, or Date.
+ */
+function isObject(input) {
+ return (typeof input === "object" &&
+ input !== null &&
+ !Array.isArray(input) &&
+ !(input instanceof RegExp) &&
+ !(input instanceof Date));
+}
+//# sourceMappingURL=object.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/error.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Typeguard for an error object shape (has name and message)
+ * @param e - Something caught by a catch clause.
+ */
+function isError(e) {
+ if (isObject(e)) {
+ const hasName = typeof e.name === "string";
+ const hasMessage = typeof e.message === "string";
+ return hasName && hasMessage;
+ }
+ return false;
+}
+//# sourceMappingURL=error.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/inspect.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const custom = external_node_util_.inspect.custom;
+//# sourceMappingURL=inspect.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/sanitizer.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const RedactedString = "REDACTED";
+// Make sure this list is up-to-date with the one under core/logger/Readme#Keyconcepts
+const defaultAllowedHeaderNames = [
+ "x-ms-client-request-id",
+ "x-ms-return-client-request-id",
+ "x-ms-useragent",
+ "x-ms-correlation-request-id",
+ "x-ms-request-id",
+ "client-request-id",
+ "ms-cv",
+ "return-client-request-id",
+ "traceparent",
+ "Access-Control-Allow-Credentials",
+ "Access-Control-Allow-Headers",
+ "Access-Control-Allow-Methods",
+ "Access-Control-Allow-Origin",
+ "Access-Control-Expose-Headers",
+ "Access-Control-Max-Age",
+ "Access-Control-Request-Headers",
+ "Access-Control-Request-Method",
+ "Origin",
+ "Accept",
+ "Accept-Encoding",
+ "Cache-Control",
+ "Connection",
+ "Content-Length",
+ "Content-Type",
+ "Date",
+ "ETag",
+ "Expires",
+ "If-Match",
+ "If-Modified-Since",
+ "If-None-Match",
+ "If-Unmodified-Since",
+ "Last-Modified",
+ "Pragma",
+ "Request-Id",
+ "Retry-After",
+ "Server",
+ "Transfer-Encoding",
+ "User-Agent",
+ "WWW-Authenticate",
+];
+const defaultAllowedQueryParameters = ["api-version"];
+/**
+ * A utility class to sanitize objects for logging.
+ */
+class Sanitizer {
+ allowedHeaderNames;
+ allowedQueryParameters;
+ constructor({ additionalAllowedHeaderNames: allowedHeaderNames = [], additionalAllowedQueryParameters: allowedQueryParameters = [], } = {}) {
+ allowedHeaderNames = defaultAllowedHeaderNames.concat(allowedHeaderNames);
+ allowedQueryParameters = defaultAllowedQueryParameters.concat(allowedQueryParameters);
+ this.allowedHeaderNames = new Set(allowedHeaderNames.map((n) => n.toLowerCase()));
+ this.allowedQueryParameters = new Set(allowedQueryParameters.map((p) => p.toLowerCase()));
+ }
+ /**
+ * Sanitizes an object for logging.
+ * @param obj - The object to sanitize
+ * @returns - The sanitized object as a string
+ */
+ sanitize(obj) {
+ const seen = new Set();
+ return JSON.stringify(obj, (key, value) => {
+ // Ensure Errors include their interesting non-enumerable members
+ if (value instanceof Error) {
+ return {
+ ...value,
+ name: value.name,
+ message: value.message,
+ };
+ }
+ if (key === "headers" && isObject(value)) {
+ return this.sanitizeHeaders(value);
+ }
+ else if (key === "url" && typeof value === "string") {
+ return this.sanitizeUrl(value);
+ }
+ else if (key === "query" && isObject(value)) {
+ return this.sanitizeQuery(value);
+ }
+ else if (key === "body") {
+ // Don't log the request body
+ return undefined;
+ }
+ else if (key === "response") {
+ // Don't log response again
+ return undefined;
+ }
+ else if (key === "operationSpec") {
+ // When using sendOperationRequest, the request carries a massive
+ // field with the autorest spec. No need to log it.
+ return undefined;
+ }
+ else if (Array.isArray(value) || isObject(value)) {
+ if (seen.has(value)) {
+ return "[Circular]";
+ }
+ seen.add(value);
+ }
+ return value;
+ }, 2);
+ }
+ /**
+ * Sanitizes a URL for logging.
+ * @param value - The URL to sanitize
+ * @returns - The sanitized URL as a string
+ */
+ sanitizeUrl(value) {
+ if (typeof value !== "string" || value === null || value === "") {
+ return value;
+ }
+ const url = new URL(value);
+ if (!url.search) {
+ return value;
+ }
+ for (const [key] of url.searchParams) {
+ if (!this.allowedQueryParameters.has(key.toLowerCase())) {
+ url.searchParams.set(key, RedactedString);
+ }
+ }
+ return url.toString();
+ }
+ sanitizeHeaders(obj) {
+ const sanitized = {};
+ for (const key of Object.keys(obj)) {
+ if (this.allowedHeaderNames.has(key.toLowerCase())) {
+ sanitized[key] = obj[key];
+ }
+ else {
+ sanitized[key] = RedactedString;
+ }
+ }
+ return sanitized;
+ }
+ sanitizeQuery(value) {
+ if (typeof value !== "object" || value === null) {
+ return value;
+ }
+ const sanitized = {};
+ for (const k of Object.keys(value)) {
+ if (this.allowedQueryParameters.has(k.toLowerCase())) {
+ sanitized[k] = value[k];
+ }
+ else {
+ sanitized[k] = RedactedString;
+ }
+ }
+ return sanitized;
+ }
+}
+//# sourceMappingURL=sanitizer.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/restError.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+const errorSanitizer = new Sanitizer();
+/**
+ * A custom error type for failed pipeline requests.
+ */
+class restError_RestError extends Error {
+ /**
+ * Something went wrong when making the request.
+ * This means the actual request failed for some reason,
+ * such as a DNS issue or the connection being lost.
+ */
+ static REQUEST_SEND_ERROR = "REQUEST_SEND_ERROR";
+ /**
+ * This means that parsing the response from the server failed.
+ * It may have been malformed.
+ */
+ static PARSE_ERROR = "PARSE_ERROR";
+ /**
+ * The code of the error itself (use statics on RestError if possible.)
+ */
+ code;
+ /**
+ * The HTTP status code of the request (if applicable.)
+ */
+ statusCode;
+ /**
+ * The request that was made.
+ * This property is non-enumerable.
+ */
+ request;
+ /**
+ * The response received (if any.)
+ * This property is non-enumerable.
+ */
+ response;
+ /**
+ * Bonus property set by the throw site.
+ */
+ details;
+ constructor(message, options = {}) {
+ super(message);
+ this.name = "RestError";
+ this.code = options.code;
+ this.statusCode = options.statusCode;
+ // The request and response may contain sensitive information in the headers or body.
+ // To help prevent this sensitive information being accidentally logged, the request and response
+ // properties are marked as non-enumerable here. This prevents them showing up in the output of
+ // JSON.stringify and console.log.
+ Object.defineProperty(this, "request", { value: options.request, enumerable: false });
+ Object.defineProperty(this, "response", { value: options.response, enumerable: false });
+ // Only include useful agent information in the request for logging, as the full agent object
+ // may contain large binary data.
+ const agent = this.request?.agent
+ ? {
+ maxFreeSockets: this.request.agent.maxFreeSockets,
+ maxSockets: this.request.agent.maxSockets,
+ }
+ : undefined;
+ // Logging method for util.inspect in Node
+ Object.defineProperty(this, custom, {
+ value: () => {
+ // Extract non-enumerable properties and add them back. This is OK since in this output the request and
+ // response get sanitized.
+ return `RestError: ${this.message} \n ${errorSanitizer.sanitize({
+ ...this,
+ request: { ...this.request, agent },
+ response: this.response,
+ })}`;
+ },
+ enumerable: false,
+ });
+ Object.setPrototypeOf(this, restError_RestError.prototype);
+ }
+}
+/**
+ * Typeguard for RestError
+ * @param e - Something caught by a catch clause.
+ */
+function restError_isRestError(e) {
+ if (e instanceof restError_RestError) {
+ return true;
+ }
+ return isError(e) && e.name === "RestError";
+}
+//# sourceMappingURL=restError.js.map
+// EXTERNAL MODULE: external "node:http"
+var external_node_http_ = __webpack_require__(7067);
+// EXTERNAL MODULE: external "node:https"
+var external_node_https_ = __webpack_require__(4708);
+// EXTERNAL MODULE: external "node:zlib"
+var external_node_zlib_ = __webpack_require__(8522);
+// EXTERNAL MODULE: external "node:stream"
+var external_node_stream_ = __webpack_require__(7075);
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/log.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const log_logger = createClientLogger("ts-http-runtime");
+//# sourceMappingURL=log.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/nodeHttpClient.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+
+const DEFAULT_TLS_SETTINGS = {};
+function nodeHttpClient_isReadableStream(body) {
+ return body && typeof body.pipe === "function";
+}
+function isStreamComplete(stream) {
+ if (stream.readable === false) {
+ return Promise.resolve();
+ }
+ return new Promise((resolve) => {
+ const handler = () => {
+ resolve();
+ stream.removeListener("close", handler);
+ stream.removeListener("end", handler);
+ stream.removeListener("error", handler);
+ };
+ stream.on("close", handler);
+ stream.on("end", handler);
+ stream.on("error", handler);
+ });
+}
+function isArrayBuffer(body) {
+ return body && typeof body.byteLength === "number";
+}
+class ReportTransform extends external_node_stream_.Transform {
+ loadedBytes = 0;
+ progressCallback;
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
+ _transform(chunk, _encoding, callback) {
+ this.push(chunk);
+ this.loadedBytes += chunk.length;
+ try {
+ this.progressCallback({ loadedBytes: this.loadedBytes });
+ callback();
+ }
+ catch (e) {
+ callback(e);
+ }
+ }
+ constructor(progressCallback) {
+ super();
+ this.progressCallback = progressCallback;
+ }
+}
+/**
+ * A HttpClient implementation that uses Node's "https" module to send HTTPS requests.
+ * @internal
+ */
+class NodeHttpClient {
+ cachedHttpAgent;
+ cachedHttpsAgents = new WeakMap();
+ /**
+ * Makes a request over an underlying transport layer and returns the response.
+ * @param request - The request to be made.
+ */
+ async sendRequest(request) {
+ const abortController = new AbortController();
+ let abortListener;
+ if (request.abortSignal) {
+ if (request.abortSignal.aborted) {
+ throw new AbortError("The operation was aborted. Request has already been canceled.");
+ }
+ abortListener = (event) => {
+ if (event.type === "abort") {
+ abortController.abort();
+ }
+ };
+ request.abortSignal.addEventListener("abort", abortListener);
+ }
+ let timeoutId;
+ if (request.timeout > 0) {
+ timeoutId = setTimeout(() => {
+ const sanitizer = new Sanitizer();
+ log_logger.info(`request to '${sanitizer.sanitizeUrl(request.url)}' timed out. canceling...`);
+ abortController.abort();
+ }, request.timeout);
+ }
+ const acceptEncoding = request.headers.get("Accept-Encoding");
+ const shouldDecompress = acceptEncoding?.includes("gzip") || acceptEncoding?.includes("deflate");
+ let body = typeof request.body === "function" ? request.body() : request.body;
+ if (body && !request.headers.has("Content-Length")) {
+ const bodyLength = getBodyLength(body);
+ if (bodyLength !== null) {
+ request.headers.set("Content-Length", bodyLength);
+ }
+ }
+ let responseStream;
+ try {
+ if (body && request.onUploadProgress) {
+ const onUploadProgress = request.onUploadProgress;
+ const uploadReportStream = new ReportTransform(onUploadProgress);
+ uploadReportStream.on("error", (e) => {
+ log_logger.error("Error in upload progress", e);
+ });
+ if (nodeHttpClient_isReadableStream(body)) {
+ body.pipe(uploadReportStream);
+ }
+ else {
+ uploadReportStream.end(body);
+ }
+ body = uploadReportStream;
+ }
+ const res = await this.makeRequest(request, abortController, body);
+ if (timeoutId !== undefined) {
+ clearTimeout(timeoutId);
+ }
+ const headers = getResponseHeaders(res);
+ const status = res.statusCode ?? 0;
+ const response = {
+ status,
+ headers,
+ request,
+ };
+ // Responses to HEAD must not have a body.
+ // If they do return a body, that body must be ignored.
+ if (request.method === "HEAD") {
+ // call resume() and not destroy() to avoid closing the socket
+ // and losing keep alive
+ res.resume();
+ return response;
+ }
+ responseStream = shouldDecompress ? getDecodedResponseStream(res, headers) : res;
+ const onDownloadProgress = request.onDownloadProgress;
+ if (onDownloadProgress) {
+ const downloadReportStream = new ReportTransform(onDownloadProgress);
+ downloadReportStream.on("error", (e) => {
+ log_logger.error("Error in download progress", e);
+ });
+ responseStream.pipe(downloadReportStream);
+ responseStream = downloadReportStream;
+ }
+ if (
+ // Value of POSITIVE_INFINITY in streamResponseStatusCodes is considered as any status code
+ request.streamResponseStatusCodes?.has(Number.POSITIVE_INFINITY) ||
+ request.streamResponseStatusCodes?.has(response.status)) {
+ response.readableStreamBody = responseStream;
+ }
+ else {
+ response.bodyAsText = await streamToText(responseStream);
+ }
+ return response;
+ }
+ finally {
+ // clean up event listener
+ if (request.abortSignal && abortListener) {
+ let uploadStreamDone = Promise.resolve();
+ if (nodeHttpClient_isReadableStream(body)) {
+ uploadStreamDone = isStreamComplete(body);
+ }
+ let downloadStreamDone = Promise.resolve();
+ if (nodeHttpClient_isReadableStream(responseStream)) {
+ downloadStreamDone = isStreamComplete(responseStream);
+ }
+ Promise.all([uploadStreamDone, downloadStreamDone])
+ .then(() => {
+ // eslint-disable-next-line promise/always-return
+ if (abortListener) {
+ request.abortSignal?.removeEventListener("abort", abortListener);
+ }
+ })
+ .catch((e) => {
+ log_logger.warning("Error when cleaning up abortListener on httpRequest", e);
+ });
+ }
+ }
+ }
+ makeRequest(request, abortController, body) {
+ const url = new URL(request.url);
+ const isInsecure = url.protocol !== "https:";
+ if (isInsecure && !request.allowInsecureConnection) {
+ throw new Error(`Cannot connect to ${request.url} while allowInsecureConnection is false.`);
+ }
+ const agent = request.agent ?? this.getOrCreateAgent(request, isInsecure);
+ const options = {
+ agent,
+ hostname: url.hostname,
+ path: `${url.pathname}${url.search}`,
+ port: url.port,
+ method: request.method,
+ headers: request.headers.toJSON({ preserveCase: true }),
+ ...request.requestOverrides,
+ };
+ return new Promise((resolve, reject) => {
+ const req = isInsecure ? external_node_http_.request(options, resolve) : external_node_https_.request(options, resolve);
+ req.once("error", (err) => {
+ reject(new restError_RestError(err.message, { code: err.code ?? restError_RestError.REQUEST_SEND_ERROR, request }));
+ });
+ abortController.signal.addEventListener("abort", () => {
+ const abortError = new AbortError("The operation was aborted. Rejecting from abort signal callback while making request.");
+ req.destroy(abortError);
+ reject(abortError);
+ });
+ if (body && nodeHttpClient_isReadableStream(body)) {
+ body.pipe(req);
+ }
+ else if (body) {
+ if (typeof body === "string" || Buffer.isBuffer(body)) {
+ req.end(body);
+ }
+ else if (isArrayBuffer(body)) {
+ req.end(ArrayBuffer.isView(body)
+ ? Buffer.from(body.buffer, body.byteOffset, body.byteLength)
+ : Buffer.from(body));
+ }
+ else {
+ log_logger.error("Unrecognized body type", body);
+ reject(new restError_RestError("Unrecognized body type"));
+ }
+ }
+ else {
+ // streams don't like "undefined" being passed as data
+ req.end();
+ }
+ });
+ }
+ getOrCreateAgent(request, isInsecure) {
+ const disableKeepAlive = request.disableKeepAlive;
+ // Handle Insecure requests first
+ if (isInsecure) {
+ if (disableKeepAlive) {
+ // keepAlive:false is the default so we don't need a custom Agent
+ return external_node_http_.globalAgent;
+ }
+ if (!this.cachedHttpAgent) {
+ // If there is no cached agent create a new one and cache it.
+ this.cachedHttpAgent = new external_node_http_.Agent({ keepAlive: true });
+ }
+ return this.cachedHttpAgent;
+ }
+ else {
+ if (disableKeepAlive && !request.tlsSettings) {
+ // When there are no tlsSettings and keepAlive is false
+ // we don't need a custom agent
+ return external_node_https_.globalAgent;
+ }
+ // We use the tlsSettings to index cached clients
+ const tlsSettings = request.tlsSettings ?? DEFAULT_TLS_SETTINGS;
+ // Get the cached agent or create a new one with the
+ // provided values for keepAlive and tlsSettings
+ let agent = this.cachedHttpsAgents.get(tlsSettings);
+ if (agent && agent.options.keepAlive === !disableKeepAlive) {
+ return agent;
+ }
+ log_logger.info("No cached TLS Agent exist, creating a new Agent");
+ agent = new external_node_https_.Agent({
+ // keepAlive is true if disableKeepAlive is false.
+ keepAlive: !disableKeepAlive,
+ // Since we are spreading, if no tslSettings were provided, nothing is added to the agent options.
+ ...tlsSettings,
+ });
+ this.cachedHttpsAgents.set(tlsSettings, agent);
+ return agent;
+ }
+ }
+}
+function getResponseHeaders(res) {
+ const headers = httpHeaders_createHttpHeaders();
+ for (const header of Object.keys(res.headers)) {
+ const value = res.headers[header];
+ if (Array.isArray(value)) {
+ if (value.length > 0) {
+ headers.set(header, value[0]);
+ }
+ }
+ else if (value) {
+ headers.set(header, value);
+ }
+ }
+ return headers;
+}
+function getDecodedResponseStream(stream, headers) {
+ const contentEncoding = headers.get("Content-Encoding");
+ if (contentEncoding === "gzip") {
+ const unzip = external_node_zlib_.createGunzip();
+ stream.pipe(unzip);
+ return unzip;
+ }
+ else if (contentEncoding === "deflate") {
+ const inflate = external_node_zlib_.createInflate();
+ stream.pipe(inflate);
+ return inflate;
+ }
+ return stream;
+}
+function streamToText(stream) {
+ return new Promise((resolve, reject) => {
+ const buffer = [];
+ stream.on("data", (chunk) => {
+ if (Buffer.isBuffer(chunk)) {
+ buffer.push(chunk);
+ }
+ else {
+ buffer.push(Buffer.from(chunk));
+ }
+ });
+ stream.on("end", () => {
+ resolve(Buffer.concat(buffer).toString("utf8"));
+ });
+ stream.on("error", (e) => {
+ if (e && e?.name === "AbortError") {
+ reject(e);
+ }
+ else {
+ reject(new restError_RestError(`Error reading response as text: ${e.message}`, {
+ code: restError_RestError.PARSE_ERROR,
+ }));
+ }
+ });
+ });
+}
+/** @internal */
+function getBodyLength(body) {
+ if (!body) {
+ return 0;
+ }
+ else if (Buffer.isBuffer(body)) {
+ return body.length;
+ }
+ else if (nodeHttpClient_isReadableStream(body)) {
+ return null;
+ }
+ else if (isArrayBuffer(body)) {
+ return body.byteLength;
+ }
+ else if (typeof body === "string") {
+ return Buffer.from(body).length;
+ }
+ else {
+ return null;
+ }
+}
+/**
+ * Create a new HttpClient instance for the NodeJS environment.
+ * @internal
+ */
+function createNodeHttpClient() {
+ return new NodeHttpClient();
+}
+//# sourceMappingURL=nodeHttpClient.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/defaultHttpClient.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Create the correct HttpClient for the current environment.
+ */
+function defaultHttpClient_createDefaultHttpClient() {
+ return createNodeHttpClient();
+}
+//# sourceMappingURL=defaultHttpClient.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/logPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * The programmatic identifier of the logPolicy.
+ */
+const logPolicyName = "logPolicy";
+/**
+ * A policy that logs all requests and responses.
+ * @param options - Options to configure logPolicy.
+ */
+function logPolicy_logPolicy(options = {}) {
+ const logger = options.logger ?? log_logger.info;
+ const sanitizer = new Sanitizer({
+ additionalAllowedHeaderNames: options.additionalAllowedHeaderNames,
+ additionalAllowedQueryParameters: options.additionalAllowedQueryParameters,
+ });
+ return {
+ name: logPolicyName,
+ async sendRequest(request, next) {
+ if (!logger.enabled) {
+ return next(request);
+ }
+ logger(`Request: ${sanitizer.sanitize(request)}`);
+ const response = await next(request);
+ logger(`Response status code: ${response.status}`);
+ logger(`Headers: ${sanitizer.sanitize({ headers: response.headers })}`);
+ return response;
+ },
+ };
+}
+//# sourceMappingURL=logPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/userAgentPlatform.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * @internal
+ */
+function getHeaderName() {
+ return "User-Agent";
+}
+/**
+ * @internal
+ */
+async function userAgentPlatform_setPlatformSpecificData(map) {
+ if (process && process.versions) {
+ const osInfo = `${os.type()} ${os.release()}; ${os.arch()}`;
+ if (process.versions.bun) {
+ map.set("Bun", `${process.versions.bun} (${osInfo})`);
+ }
+ else if (process.versions.deno) {
+ map.set("Deno", `${process.versions.deno} (${osInfo})`);
+ }
+ else if (process.versions.node) {
+ map.set("Node", `${process.versions.node} (${osInfo})`);
+ }
+ }
+}
+//# sourceMappingURL=userAgentPlatform.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/userAgent.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+function getUserAgentString(telemetryInfo) {
+ const parts = [];
+ for (const [key, value] of telemetryInfo) {
+ const token = value ? `${key}/${value}` : key;
+ parts.push(token);
+ }
+ return parts.join(" ");
+}
+/**
+ * @internal
+ */
+function getUserAgentHeaderName() {
+ return getHeaderName();
+}
+/**
+ * @internal
+ */
+async function userAgent_getUserAgentValue(prefix) {
+ const runtimeInfo = new Map();
+ runtimeInfo.set("ts-http-runtime", SDK_VERSION);
+ await setPlatformSpecificData(runtimeInfo);
+ const defaultAgent = getUserAgentString(runtimeInfo);
+ const userAgentValue = prefix ? `${prefix} ${defaultAgent}` : defaultAgent;
+ return userAgentValue;
+}
+//# sourceMappingURL=userAgent.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/userAgentPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const UserAgentHeaderName = getUserAgentHeaderName();
+/**
+ * The programmatic identifier of the userAgentPolicy.
+ */
+const userAgentPolicyName = "userAgentPolicy";
+/**
+ * A policy that sets the User-Agent header (or equivalent) to reflect
+ * the library version.
+ * @param options - Options to customize the user agent value.
+ */
+function userAgentPolicy_userAgentPolicy(options = {}) {
+ const userAgentValue = getUserAgentValue(options.userAgentPrefix);
+ return {
+ name: userAgentPolicyName,
+ async sendRequest(request, next) {
+ if (!request.headers.has(UserAgentHeaderName)) {
+ request.headers.set(UserAgentHeaderName, await userAgentValue);
+ }
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=userAgentPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/random.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Returns a random integer value between a lower and upper bound,
+ * inclusive of both bounds.
+ * Note that this uses Math.random and isn't secure. If you need to use
+ * this for any kind of security purpose, find a better source of random.
+ * @param min - The smallest integer value allowed.
+ * @param max - The largest integer value allowed.
+ */
+function getRandomIntegerInclusive(min, max) {
+ // Make sure inputs are integers.
+ min = Math.ceil(min);
+ max = Math.floor(max);
+ // Pick a random offset from zero to the size of the range.
+ // Since Math.random() can never return 1, we have to make the range one larger
+ // in order to be inclusive of the maximum value after we take the floor.
+ const offset = Math.floor(Math.random() * (max - min + 1));
+ return offset + min;
+}
+//# sourceMappingURL=random.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/delay.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Calculates the delay interval for retry attempts using exponential delay with jitter.
+ * @param retryAttempt - The current retry attempt number.
+ * @param config - The exponential retry configuration.
+ * @returns An object containing the calculated retry delay.
+ */
+function calculateRetryDelay(retryAttempt, config) {
+ // Exponentially increase the delay each time
+ const exponentialDelay = config.retryDelayInMs * Math.pow(2, retryAttempt);
+ // Don't let the delay exceed the maximum
+ const clampedDelay = Math.min(config.maxRetryDelayInMs, exponentialDelay);
+ // Allow the final value to have some "jitter" (within 50% of the delay size) so
+ // that retries across multiple clients don't occur simultaneously.
+ const retryAfterInMs = clampedDelay / 2 + getRandomIntegerInclusive(0, clampedDelay / 2);
+ return { retryAfterInMs };
+}
+//# sourceMappingURL=delay.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/helpers.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const StandardAbortMessage = "The operation was aborted.";
+/**
+ * A wrapper for setTimeout that resolves a promise after delayInMs milliseconds.
+ * @param delayInMs - The number of milliseconds to be delayed.
+ * @param value - The value to be resolved with after a timeout of t milliseconds.
+ * @param options - The options for delay - currently abort options
+ * - abortSignal - The abortSignal associated with containing operation.
+ * - abortErrorMsg - The abort error message associated with containing operation.
+ * @returns Resolved promise
+ */
+function helpers_delay(delayInMs, value, options) {
+ return new Promise((resolve, reject) => {
+ let timer = undefined;
+ let onAborted = undefined;
+ const rejectOnAbort = () => {
+ return reject(new AbortError(options?.abortErrorMsg ? options?.abortErrorMsg : StandardAbortMessage));
+ };
+ const removeListeners = () => {
+ if (options?.abortSignal && onAborted) {
+ options.abortSignal.removeEventListener("abort", onAborted);
+ }
+ };
+ onAborted = () => {
+ if (timer) {
+ clearTimeout(timer);
+ }
+ removeListeners();
+ return rejectOnAbort();
+ };
+ if (options?.abortSignal && options.abortSignal.aborted) {
+ return rejectOnAbort();
+ }
+ timer = setTimeout(() => {
+ removeListeners();
+ resolve(value);
+ }, delayInMs);
+ if (options?.abortSignal) {
+ options.abortSignal.addEventListener("abort", onAborted);
+ }
+ });
+}
+/**
+ * @internal
+ * @returns the parsed value or undefined if the parsed value is invalid.
+ */
+function parseHeaderValueAsNumber(response, headerName) {
+ const value = response.headers.get(headerName);
+ if (!value)
+ return;
+ const valueAsNum = Number(value);
+ if (Number.isNaN(valueAsNum))
+ return;
+ return valueAsNum;
+}
+//# sourceMappingURL=helpers.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/retryStrategies/throttlingRetryStrategy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * The header that comes back from services representing
+ * the amount of time (minimum) to wait to retry (in seconds or timestamp after which we can retry).
+ */
+const RetryAfterHeader = "Retry-After";
+/**
+ * The headers that come back from services representing
+ * the amount of time (minimum) to wait to retry.
+ *
+ * "retry-after-ms", "x-ms-retry-after-ms" : milliseconds
+ * "Retry-After" : seconds or timestamp
+ */
+const AllRetryAfterHeaders = ["retry-after-ms", "x-ms-retry-after-ms", RetryAfterHeader];
+/**
+ * A response is a throttling retry response if it has a throttling status code (429 or 503),
+ * as long as one of the [ "Retry-After" or "retry-after-ms" or "x-ms-retry-after-ms" ] headers has a valid value.
+ *
+ * Returns the `retryAfterInMs` value if the response is a throttling retry response.
+ * If not throttling retry response, returns `undefined`.
+ *
+ * @internal
+ */
+function getRetryAfterInMs(response) {
+ if (!(response && [429, 503].includes(response.status)))
+ return undefined;
+ try {
+ // Headers: "retry-after-ms", "x-ms-retry-after-ms", "Retry-After"
+ for (const header of AllRetryAfterHeaders) {
+ const retryAfterValue = parseHeaderValueAsNumber(response, header);
+ if (retryAfterValue === 0 || retryAfterValue) {
+ // "Retry-After" header ==> seconds
+ // "retry-after-ms", "x-ms-retry-after-ms" headers ==> milli-seconds
+ const multiplyingFactor = header === RetryAfterHeader ? 1000 : 1;
+ return retryAfterValue * multiplyingFactor; // in milli-seconds
+ }
+ }
+ // RetryAfterHeader ("Retry-After") has a special case where it might be formatted as a date instead of a number of seconds
+ const retryAfterHeader = response.headers.get(RetryAfterHeader);
+ if (!retryAfterHeader)
+ return;
+ const date = Date.parse(retryAfterHeader);
+ const diff = date - Date.now();
+ // negative diff would mean a date in the past, so retry asap with 0 milliseconds
+ return Number.isFinite(diff) ? Math.max(0, diff) : undefined;
+ }
+ catch {
+ return undefined;
+ }
+}
+/**
+ * A response is a retry response if it has a throttling status code (429 or 503),
+ * as long as one of the [ "Retry-After" or "retry-after-ms" or "x-ms-retry-after-ms" ] headers has a valid value.
+ */
+function isThrottlingRetryResponse(response) {
+ return Number.isFinite(getRetryAfterInMs(response));
+}
+function throttlingRetryStrategy_throttlingRetryStrategy() {
+ return {
+ name: "throttlingRetryStrategy",
+ retry({ response }) {
+ const retryAfterInMs = getRetryAfterInMs(response);
+ if (!Number.isFinite(retryAfterInMs)) {
+ return { skipStrategy: true };
+ }
+ return {
+ retryAfterInMs,
+ };
+ },
+ };
+}
+//# sourceMappingURL=throttlingRetryStrategy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/retryStrategies/exponentialRetryStrategy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+// intervals are in milliseconds
+const DEFAULT_CLIENT_RETRY_INTERVAL = 1000;
+const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64;
+/**
+ * A retry strategy that retries with an exponentially increasing delay in these two cases:
+ * - When there are errors in the underlying transport layer (e.g. DNS lookup failures).
+ * - Or otherwise if the outgoing request fails (408, greater or equal than 500, except for 501 and 505).
+ */
+function exponentialRetryStrategy_exponentialRetryStrategy(options = {}) {
+ const retryInterval = options.retryDelayInMs ?? DEFAULT_CLIENT_RETRY_INTERVAL;
+ const maxRetryInterval = options.maxRetryDelayInMs ?? DEFAULT_CLIENT_MAX_RETRY_INTERVAL;
+ return {
+ name: "exponentialRetryStrategy",
+ retry({ retryCount, response, responseError }) {
+ const matchedSystemError = isSystemError(responseError);
+ const ignoreSystemErrors = matchedSystemError && options.ignoreSystemErrors;
+ const isExponential = isExponentialRetryResponse(response);
+ const ignoreExponentialResponse = isExponential && options.ignoreHttpStatusCodes;
+ const unknownResponse = response && (isThrottlingRetryResponse(response) || !isExponential);
+ if (unknownResponse || ignoreExponentialResponse || ignoreSystemErrors) {
+ return { skipStrategy: true };
+ }
+ if (responseError && !matchedSystemError && !isExponential) {
+ return { errorToThrow: responseError };
+ }
+ return calculateRetryDelay(retryCount, {
+ retryDelayInMs: retryInterval,
+ maxRetryDelayInMs: maxRetryInterval,
+ });
+ },
+ };
+}
+/**
+ * A response is a retry response if it has status codes:
+ * - 408, or
+ * - Greater or equal than 500, except for 501 and 505.
+ */
+function isExponentialRetryResponse(response) {
+ return Boolean(response &&
+ response.status !== undefined &&
+ (response.status >= 500 || response.status === 408) &&
+ response.status !== 501 &&
+ response.status !== 505);
+}
+/**
+ * Determines whether an error from a pipeline response was triggered in the network layer.
+ */
+function isSystemError(err) {
+ if (!err) {
+ return false;
+ }
+ return (err.code === "ETIMEDOUT" ||
+ err.code === "ESOCKETTIMEDOUT" ||
+ err.code === "ECONNREFUSED" ||
+ err.code === "ECONNRESET" ||
+ err.code === "ENOENT" ||
+ err.code === "ENOTFOUND");
+}
+//# sourceMappingURL=exponentialRetryStrategy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/constants.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+const constants_SDK_VERSION = "0.3.7";
+const constants_DEFAULT_RETRY_POLICY_COUNT = 3;
+//# sourceMappingURL=constants.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/retryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+const retryPolicyLogger = createClientLogger("ts-http-runtime retryPolicy");
+/**
+ * The programmatic identifier of the retryPolicy.
+ */
+const retryPolicyName = "retryPolicy";
+/**
+ * retryPolicy is a generic policy to enable retrying requests when certain conditions are met
+ */
+function retryPolicy_retryPolicy(strategies, options = { maxRetries: constants_DEFAULT_RETRY_POLICY_COUNT }) {
+ const logger = options.logger || retryPolicyLogger;
+ return {
+ name: retryPolicyName,
+ async sendRequest(request, next) {
+ let response;
+ let responseError;
+ let retryCount = -1;
+ retryRequest: while (true) {
+ retryCount += 1;
+ response = undefined;
+ responseError = undefined;
+ try {
+ logger.info(`Retry ${retryCount}: Attempting to send request`, request.requestId);
+ response = await next(request);
+ logger.info(`Retry ${retryCount}: Received a response from request`, request.requestId);
+ }
+ catch (e) {
+ logger.error(`Retry ${retryCount}: Received an error from request`, request.requestId);
+ // RestErrors are valid targets for the retry strategies.
+ // If none of the retry strategies can work with them, they will be thrown later in this policy.
+ // If the received error is not a RestError, it is immediately thrown.
+ if (!restError_isRestError(e)) {
+ throw e;
+ }
+ responseError = e;
+ response = e.response;
+ }
+ if (request.abortSignal?.aborted) {
+ logger.error(`Retry ${retryCount}: Request aborted.`);
+ const abortError = new AbortError();
+ throw abortError;
+ }
+ if (retryCount >= (options.maxRetries ?? constants_DEFAULT_RETRY_POLICY_COUNT)) {
+ logger.info(`Retry ${retryCount}: Maximum retries reached. Returning the last received response, or throwing the last received error.`);
+ if (responseError) {
+ throw responseError;
+ }
+ else if (response) {
+ return response;
+ }
+ else {
+ throw new Error("Maximum retries reached with no response or error to throw");
+ }
+ }
+ logger.info(`Retry ${retryCount}: Processing ${strategies.length} retry strategies.`);
+ strategiesLoop: for (const strategy of strategies) {
+ const strategyLogger = strategy.logger || logger;
+ strategyLogger.info(`Retry ${retryCount}: Processing retry strategy ${strategy.name}.`);
+ const modifiers = strategy.retry({
+ retryCount,
+ response,
+ responseError,
+ });
+ if (modifiers.skipStrategy) {
+ strategyLogger.info(`Retry ${retryCount}: Skipped.`);
+ continue strategiesLoop;
+ }
+ const { errorToThrow, retryAfterInMs, redirectTo } = modifiers;
+ if (errorToThrow) {
+ strategyLogger.error(`Retry ${retryCount}: Retry strategy ${strategy.name} throws error:`, errorToThrow);
+ throw errorToThrow;
+ }
+ if (retryAfterInMs || retryAfterInMs === 0) {
+ strategyLogger.info(`Retry ${retryCount}: Retry strategy ${strategy.name} retries after ${retryAfterInMs}`);
+ await helpers_delay(retryAfterInMs, undefined, { abortSignal: request.abortSignal });
+ continue retryRequest;
+ }
+ if (redirectTo) {
+ strategyLogger.info(`Retry ${retryCount}: Retry strategy ${strategy.name} redirects to ${redirectTo}`);
+ request.url = redirectTo;
+ continue retryRequest;
+ }
+ }
+ if (responseError) {
+ logger.info(`None of the retry strategies could work with the received error. Throwing it.`);
+ throw responseError;
+ }
+ if (response) {
+ logger.info(`None of the retry strategies could work with the received response. Returning it.`);
+ return response;
+ }
+ // If all the retries skip and there's no response,
+ // we're still in the retry loop, so a new request will be sent
+ // until `maxRetries` is reached.
+ }
+ },
+ };
+}
+//# sourceMappingURL=retryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/defaultRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+/**
+ * Name of the {@link defaultRetryPolicy}
+ */
+const defaultRetryPolicyName = "defaultRetryPolicy";
+/**
+ * A policy that retries according to three strategies:
+ * - When the server sends a 429 response with a Retry-After header.
+ * - When there are errors in the underlying transport layer (e.g. DNS lookup failures).
+ * - Or otherwise if the outgoing request fails, it will retry with an exponentially increasing delay.
+ */
+function defaultRetryPolicy_defaultRetryPolicy(options = {}) {
+ return {
+ name: defaultRetryPolicyName,
+ sendRequest: retryPolicy_retryPolicy([throttlingRetryStrategy_throttlingRetryStrategy(), exponentialRetryStrategy_exponentialRetryStrategy(options)], {
+ maxRetries: options.maxRetries ?? constants_DEFAULT_RETRY_POLICY_COUNT,
+ }).sendRequest,
+ };
+}
+//# sourceMappingURL=defaultRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/bytesEncoding.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * The helper that transforms bytes with specific character encoding into string
+ * @param bytes - the uint8array bytes
+ * @param format - the format we use to encode the byte
+ * @returns a string of the encoded string
+ */
+function bytesEncoding_uint8ArrayToString(bytes, format) {
+ return Buffer.from(bytes).toString(format);
+}
+/**
+ * The helper that transforms string to specific character encoded bytes array.
+ * @param value - the string to be converted
+ * @param format - the format we use to decode the value
+ * @returns a uint8array
+ */
+function bytesEncoding_stringToUint8Array(value, format) {
+ return Buffer.from(value, format);
+}
+//# sourceMappingURL=bytesEncoding.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/formData.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * If the request body is a native FormData, convert it to our FormDataMap
+ * representation and clear the body. Node.js's HTTP stack doesn't handle
+ * FormData natively, so the pipeline must serialize it later.
+ *
+ * @internal
+ */
+function convertBodyToFormDataMap(body) {
+ if (typeof FormData !== "undefined" && body instanceof FormData) {
+ const formDataMap = {};
+ for (const [key, value] of body.entries()) {
+ const existing = formDataMap[key];
+ if (Array.isArray(existing)) {
+ existing.push(value);
+ }
+ else {
+ formDataMap[key] = existing !== undefined ? [existing, value] : [value];
+ }
+ }
+ return formDataMap;
+ }
+ return undefined;
+}
+//# sourceMappingURL=formData.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/formDataPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+/**
+ * The programmatic identifier of the formDataPolicy.
+ */
+const formDataPolicyName = "formDataPolicy";
+/**
+ * A policy that encodes FormData on the request into the body.
+ */
+function formDataPolicy_formDataPolicy() {
+ return {
+ name: formDataPolicyName,
+ async sendRequest(request, next) {
+ const converted = convertBodyToFormDataMap(request.body);
+ if (converted) {
+ request.formData = converted;
+ request.body = undefined;
+ }
+ if (request.formData) {
+ const contentType = request.headers.get("Content-Type");
+ if (contentType && contentType.indexOf("application/x-www-form-urlencoded") !== -1) {
+ request.body = wwwFormUrlEncode(request.formData);
+ }
+ else {
+ await prepareFormData(request.formData, request);
+ }
+ request.formData = undefined;
+ }
+ return next(request);
+ },
+ };
+}
+function wwwFormUrlEncode(formData) {
+ const urlSearchParams = new URLSearchParams();
+ for (const [key, value] of Object.entries(formData)) {
+ if (Array.isArray(value)) {
+ for (const subValue of value) {
+ urlSearchParams.append(key, subValue.toString());
+ }
+ }
+ else {
+ urlSearchParams.append(key, value.toString());
+ }
+ }
+ return urlSearchParams.toString();
+}
+async function prepareFormData(formData, request) {
+ // validate content type (multipart/form-data)
+ const contentType = request.headers.get("Content-Type");
+ if (contentType && !contentType.startsWith("multipart/form-data")) {
+ // content type is specified and is not multipart/form-data. Exit.
+ return;
+ }
+ request.headers.set("Content-Type", contentType ?? "multipart/form-data");
+ // set body to MultipartRequestBody using content from FormDataMap
+ const parts = [];
+ for (const [fieldName, values] of Object.entries(formData)) {
+ for (const value of Array.isArray(values) ? values : [values]) {
+ if (typeof value === "string") {
+ parts.push({
+ headers: httpHeaders_createHttpHeaders({
+ "Content-Disposition": `form-data; name="${fieldName}"`,
+ }),
+ body: bytesEncoding_stringToUint8Array(value, "utf-8"),
+ });
+ }
+ else if (value === undefined || value === null || typeof value !== "object") {
+ throw new Error(`Unexpected value for key ${fieldName}: ${value}. Value should be serialized to string first.`);
+ }
+ else {
+ // using || instead of ?? here since if value.name is empty we should create a file name
+ const fileName = value.name || "blob";
+ const headers = httpHeaders_createHttpHeaders();
+ headers.set("Content-Disposition", `form-data; name="${fieldName}"; filename="${fileName}"`);
+ // again, || is used since an empty value.type means the content type is unset
+ headers.set("Content-Type", value.type || "application/octet-stream");
+ parts.push({
+ headers,
+ body: value,
+ });
+ }
+ }
+ }
+ request.multipartBody = { parts };
+}
+//# sourceMappingURL=formDataPolicy.js.map
+// EXTERNAL MODULE: ./node_modules/https-proxy-agent/dist/index.js
+var dist = __webpack_require__(3669);
+// EXTERNAL MODULE: ./node_modules/http-proxy-agent/dist/index.js
+var http_proxy_agent_dist = __webpack_require__(1970);
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/proxyPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+const HTTPS_PROXY = "HTTPS_PROXY";
+const HTTP_PROXY = "HTTP_PROXY";
+const ALL_PROXY = "ALL_PROXY";
+const NO_PROXY = "NO_PROXY";
+/**
+ * The programmatic identifier of the proxyPolicy.
+ */
+const proxyPolicyName = "proxyPolicy";
+/**
+ * Stores the patterns specified in NO_PROXY environment variable.
+ * @internal
+ */
+const globalNoProxyList = [];
+let noProxyListLoaded = false;
+/** A cache of whether a host should bypass the proxy. */
+const globalBypassedMap = new Map();
+function getEnvironmentValue(name) {
+ if (process.env[name]) {
+ return process.env[name];
+ }
+ else if (process.env[name.toLowerCase()]) {
+ return process.env[name.toLowerCase()];
+ }
+ return undefined;
+}
+function loadEnvironmentProxyValue() {
+ if (!process) {
+ return undefined;
+ }
+ const httpsProxy = getEnvironmentValue(HTTPS_PROXY);
+ const allProxy = getEnvironmentValue(ALL_PROXY);
+ const httpProxy = getEnvironmentValue(HTTP_PROXY);
+ return httpsProxy || allProxy || httpProxy;
+}
+/**
+ * Check whether the host of a given `uri` matches any pattern in the no proxy list.
+ * If there's a match, any request sent to the same host shouldn't have the proxy settings set.
+ * This implementation is a port of https://github.com/Azure/azure-sdk-for-net/blob/8cca811371159e527159c7eb65602477898683e2/sdk/core/Azure.Core/src/Pipeline/Internal/HttpEnvironmentProxy.cs#L210
+ */
+function isBypassed(uri, noProxyList, bypassedMap) {
+ if (noProxyList.length === 0) {
+ return false;
+ }
+ const host = new URL(uri).hostname;
+ if (bypassedMap?.has(host)) {
+ return bypassedMap.get(host);
+ }
+ let isBypassedFlag = false;
+ for (const pattern of noProxyList) {
+ if (pattern[0] === ".") {
+ // This should match either domain it self or any subdomain or host
+ // .foo.com will match foo.com it self or *.foo.com
+ if (host.endsWith(pattern)) {
+ isBypassedFlag = true;
+ }
+ else {
+ if (host.length === pattern.length - 1 && host === pattern.slice(1)) {
+ isBypassedFlag = true;
+ }
+ }
+ }
+ else {
+ if (host === pattern) {
+ isBypassedFlag = true;
+ }
+ }
+ }
+ bypassedMap?.set(host, isBypassedFlag);
+ return isBypassedFlag;
+}
+function loadNoProxy() {
+ const noProxy = getEnvironmentValue(NO_PROXY);
+ noProxyListLoaded = true;
+ if (noProxy) {
+ return noProxy
+ .split(",")
+ .map((item) => item.trim())
+ .filter((item) => item.length);
+ }
+ return [];
+}
+/**
+ * This method converts a proxy url into `ProxySettings` for use with ProxyPolicy.
+ * If no argument is given, it attempts to parse a proxy URL from the environment
+ * variables `HTTPS_PROXY` or `HTTP_PROXY`.
+ * @param proxyUrl - The url of the proxy to use. May contain authentication information.
+ * @deprecated - Internally this method is no longer necessary when setting proxy information.
+ */
+function getDefaultProxySettings(proxyUrl) {
+ if (!proxyUrl) {
+ proxyUrl = loadEnvironmentProxyValue();
+ if (!proxyUrl) {
+ return undefined;
+ }
+ }
+ const parsedUrl = new URL(proxyUrl);
+ const schema = parsedUrl.protocol ? parsedUrl.protocol + "//" : "";
+ return {
+ host: schema + parsedUrl.hostname,
+ port: Number.parseInt(parsedUrl.port || "80"),
+ username: parsedUrl.username,
+ password: parsedUrl.password,
+ };
+}
+/**
+ * This method attempts to parse a proxy URL from the environment
+ * variables `HTTPS_PROXY` or `HTTP_PROXY`.
+ */
+function getDefaultProxySettingsInternal() {
+ const envProxy = loadEnvironmentProxyValue();
+ return envProxy ? new URL(envProxy) : undefined;
+}
+function getUrlFromProxySettings(settings) {
+ let parsedProxyUrl;
+ try {
+ parsedProxyUrl = new URL(settings.host);
+ }
+ catch {
+ throw new Error(`Expecting a valid host string in proxy settings, but found "${settings.host}".`);
+ }
+ parsedProxyUrl.port = String(settings.port);
+ if (settings.username) {
+ parsedProxyUrl.username = settings.username;
+ }
+ if (settings.password) {
+ parsedProxyUrl.password = settings.password;
+ }
+ return parsedProxyUrl;
+}
+function setProxyAgentOnRequest(request, cachedAgents, proxyUrl) {
+ // Custom Agent should take precedence so if one is present
+ // we should skip to avoid overwriting it.
+ if (request.agent) {
+ return;
+ }
+ const url = new URL(request.url);
+ const isInsecure = url.protocol !== "https:";
+ if (request.tlsSettings) {
+ log_logger.warning("TLS settings are not supported in combination with custom Proxy, certificates provided to the client will be ignored.");
+ }
+ if (isInsecure) {
+ if (!cachedAgents.httpProxyAgent) {
+ cachedAgents.httpProxyAgent = new http_proxy_agent_dist.HttpProxyAgent(proxyUrl);
+ }
+ request.agent = cachedAgents.httpProxyAgent;
+ }
+ else {
+ if (!cachedAgents.httpsProxyAgent) {
+ cachedAgents.httpsProxyAgent = new dist.HttpsProxyAgent(proxyUrl);
+ }
+ request.agent = cachedAgents.httpsProxyAgent;
+ }
+}
+/**
+ * A policy that allows one to apply proxy settings to all requests.
+ * If not passed static settings, they will be retrieved from the HTTPS_PROXY
+ * or HTTP_PROXY environment variables.
+ * @param proxySettings - ProxySettings to use on each request.
+ * @param options - additional settings, for example, custom NO_PROXY patterns
+ */
+function proxyPolicy_proxyPolicy(proxySettings, options) {
+ if (!noProxyListLoaded) {
+ globalNoProxyList.push(...loadNoProxy());
+ }
+ const defaultProxy = proxySettings
+ ? getUrlFromProxySettings(proxySettings)
+ : getDefaultProxySettingsInternal();
+ const cachedAgents = {};
+ return {
+ name: proxyPolicyName,
+ async sendRequest(request, next) {
+ if (!request.proxySettings &&
+ defaultProxy &&
+ !isBypassed(request.url, options?.customNoProxyList ?? globalNoProxyList, options?.customNoProxyList ? undefined : globalBypassedMap)) {
+ setProxyAgentOnRequest(request, cachedAgents, defaultProxy);
+ }
+ else if (request.proxySettings) {
+ setProxyAgentOnRequest(request, cachedAgents, getUrlFromProxySettings(request.proxySettings));
+ }
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=proxyPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/redirectPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * The programmatic identifier of the redirectPolicy.
+ */
+const redirectPolicyName = "redirectPolicy";
+/**
+ * Methods that are allowed to follow redirects 301 and 302
+ */
+const allowedRedirect = ["GET", "HEAD"];
+/**
+ * A policy to follow Location headers from the server in order
+ * to support server-side redirection.
+ * In the browser, this policy is not used.
+ * @param options - Options to control policy behavior.
+ */
+function redirectPolicy_redirectPolicy(options = {}) {
+ const { maxRetries = 20, allowCrossOriginRedirects = false } = options;
+ return {
+ name: redirectPolicyName,
+ async sendRequest(request, next) {
+ const response = await next(request);
+ return handleRedirect(next, response, maxRetries, allowCrossOriginRedirects);
+ },
+ };
+}
+async function handleRedirect(next, response, maxRetries, allowCrossOriginRedirects, currentRetries = 0) {
+ const { request, status, headers } = response;
+ const locationHeader = headers.get("location");
+ if (locationHeader &&
+ (status === 300 ||
+ (status === 301 && allowedRedirect.includes(request.method)) ||
+ (status === 302 && allowedRedirect.includes(request.method)) ||
+ (status === 303 && request.method === "POST") ||
+ status === 307) &&
+ currentRetries < maxRetries) {
+ const url = new URL(locationHeader, request.url);
+ // Only follow redirects to the same origin by default.
+ if (!allowCrossOriginRedirects) {
+ const originalUrl = new URL(request.url);
+ if (url.origin !== originalUrl.origin) {
+ log_logger.verbose(`Skipping cross-origin redirect from ${originalUrl.origin} to ${url.origin}.`);
+ return response;
+ }
+ }
+ request.url = url.toString();
+ // POST request with Status code 303 should be converted into a
+ // redirected GET request if the redirect url is present in the location header
+ if (status === 303) {
+ request.method = "GET";
+ request.headers.delete("Content-Length");
+ delete request.body;
+ }
+ request.headers.delete("Authorization");
+ const res = await next(request);
+ return handleRedirect(next, res, maxRetries, allowCrossOriginRedirects, currentRetries + 1);
+ }
+ return response;
+}
+//# sourceMappingURL=redirectPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/platformPolicies.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+/**
+ * Add platform-specific policies to the pipeline.
+ *
+ * On Node.js, this adds agent, TLS, proxy, decompression, and redirect
+ * policies. On browser and React Native these concerns are handled
+ * natively by the runtime, so this is a no-op.
+ *
+ * @internal
+ */
+function platformPolicies_addPlatformPolicies(pipeline, options) {
+ if (options.agent) {
+ pipeline.addPolicy(agentPolicy(options.agent));
+ }
+ if (options.tlsOptions) {
+ pipeline.addPolicy(tlsPolicy(options.tlsOptions));
+ }
+ pipeline.addPolicy(proxyPolicy(options.proxyOptions));
+ pipeline.addPolicy(decompressResponsePolicy());
+ // Both XHR and Fetch expect to handle redirects automatically,
+ // so this only takes effect on Node.
+ pipeline.addPolicy(redirectPolicy(options.redirectOptions), { afterPhase: "Retry" });
+}
+//# sourceMappingURL=platformPolicies.js.map
+// EXTERNAL MODULE: external "stream"
+var external_stream_ = __webpack_require__(2203);
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/typeGuards-node.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Checks if the given value is a Node.js readable stream.
+ *
+ * @internal
+ */
+function typeGuards_node_isNodeReadableStream(x) {
+ return x instanceof Readable;
+}
+/**
+ * Checks if the given value is a web ReadableStream.
+ *
+ * @internal
+ */
+function typeGuards_node_isWebReadableStream(x) {
+ return x instanceof ReadableStream;
+}
+//# sourceMappingURL=typeGuards-node.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/typeGuards.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+function typeGuards_isBinaryBody(body) {
+ return (body !== undefined &&
+ (body instanceof Uint8Array ||
+ typeGuards_isReadableStream(body) ||
+ typeof body === "function" ||
+ body instanceof Blob));
+}
+function typeGuards_isReadableStream(x) {
+ return isNodeReadableStream(x) || isWebReadableStream(x);
+}
+function typeGuards_isBlob(x) {
+ return x instanceof Blob;
+}
+//# sourceMappingURL=typeGuards.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/concat.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+async function* streamAsyncIterator() {
+ const reader = this.getReader();
+ try {
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) {
+ return;
+ }
+ yield value;
+ }
+ }
+ finally {
+ reader.releaseLock();
+ }
+}
+function makeAsyncIterable(webStream) {
+ if (!webStream[Symbol.asyncIterator]) {
+ webStream[Symbol.asyncIterator] = streamAsyncIterator.bind(webStream);
+ }
+ if (!webStream.values) {
+ webStream.values = streamAsyncIterator.bind(webStream);
+ }
+}
+function ensureNodeStream(stream) {
+ if (stream instanceof ReadableStream) {
+ makeAsyncIterable(stream);
+ return external_stream_.Readable.fromWeb(stream);
+ }
+ else {
+ return stream;
+ }
+}
+function toStream(source) {
+ if (source instanceof Uint8Array) {
+ return external_stream_.Readable.from(Buffer.from(source));
+ }
+ else if (typeGuards_isBlob(source)) {
+ return ensureNodeStream(source.stream());
+ }
+ else {
+ return ensureNodeStream(source);
+ }
+}
+/**
+ * Utility function that concatenates a set of binary inputs into one combined output.
+ *
+ * @param sources - array of sources for the concatenation
+ * @returns - in Node, a (() =\> NodeJS.ReadableStream) which, when read, produces a concatenation of all the inputs.
+ * In browser, returns a `Blob` representing all the concatenated inputs.
+ *
+ * @internal
+ */
+async function concat(sources) {
+ return function () {
+ const streams = sources.map((x) => (typeof x === "function" ? x() : x)).map(toStream);
+ return external_stream_.Readable.from((async function* () {
+ for (const stream of streams) {
+ for await (const chunk of stream) {
+ yield chunk;
+ }
+ }
+ })());
+ };
+}
+//# sourceMappingURL=concat.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/multipartPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+function generateBoundary() {
+ return `----AzSDKFormBoundary${randomUUID()}`;
+}
+function encodeHeaders(headers) {
+ let result = "";
+ for (const [key, value] of headers) {
+ result += `${key}: ${value}\r\n`;
+ }
+ return result;
+}
+function getLength(source) {
+ if (source instanceof Uint8Array) {
+ return source.byteLength;
+ }
+ else if (typeGuards_isBlob(source)) {
+ // if was created using createFile then -1 means we have an unknown size
+ return source.size === -1 ? undefined : source.size;
+ }
+ else {
+ return undefined;
+ }
+}
+function getTotalLength(sources) {
+ let total = 0;
+ for (const source of sources) {
+ const partLength = getLength(source);
+ if (partLength === undefined) {
+ return undefined;
+ }
+ else {
+ total += partLength;
+ }
+ }
+ return total;
+}
+async function buildRequestBody(request, parts, boundary) {
+ const sources = [
+ bytesEncoding_stringToUint8Array(`--${boundary}`, "utf-8"),
+ ...parts.flatMap((part) => [
+ bytesEncoding_stringToUint8Array("\r\n", "utf-8"),
+ bytesEncoding_stringToUint8Array(encodeHeaders(part.headers), "utf-8"),
+ bytesEncoding_stringToUint8Array("\r\n", "utf-8"),
+ part.body,
+ bytesEncoding_stringToUint8Array(`\r\n--${boundary}`, "utf-8"),
+ ]),
+ bytesEncoding_stringToUint8Array("--\r\n\r\n", "utf-8"),
+ ];
+ const contentLength = getTotalLength(sources);
+ if (contentLength) {
+ request.headers.set("Content-Length", contentLength);
+ }
+ // The public BodyPart.body type uses Uint8Array (= Uint8Array) for
+ // backward compatibility. Internally, concat requires Uint8Array to ensure
+ // SharedArrayBuffer-backed arrays don't flow into Blob construction. In practice, HTTP
+ // request bodies are always ArrayBuffer-backed, so this narrowing is safe.
+ request.body = await concat(sources);
+}
+/**
+ * Name of multipart policy
+ */
+const multipartPolicy_multipartPolicyName = "multipartPolicy";
+const maxBoundaryLength = 70;
+const validBoundaryCharacters = new Set(`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'()+,-./:=?`);
+function assertValidBoundary(boundary) {
+ if (boundary.length > maxBoundaryLength) {
+ throw new Error(`Multipart boundary "${boundary}" exceeds maximum length of 70 characters`);
+ }
+ if (Array.from(boundary).some((x) => !validBoundaryCharacters.has(x))) {
+ throw new Error(`Multipart boundary "${boundary}" contains invalid characters`);
+ }
+}
+/**
+ * Pipeline policy for multipart requests
+ */
+function multipartPolicy_multipartPolicy() {
+ return {
+ name: multipartPolicy_multipartPolicyName,
+ async sendRequest(request, next) {
+ if (!request.multipartBody) {
+ return next(request);
+ }
+ if (request.body) {
+ throw new Error("multipartBody and regular body cannot be set at the same time");
+ }
+ let boundary = request.multipartBody.boundary;
+ const contentTypeHeader = request.headers.get("Content-Type") ?? "multipart/mixed";
+ const parsedHeader = contentTypeHeader.match(/^(multipart\/[^ ;]+)(?:; *boundary=(.+))?$/);
+ if (!parsedHeader) {
+ throw new Error(`Got multipart request body, but content-type header was not multipart: ${contentTypeHeader}`);
+ }
+ const [, contentType, parsedBoundary] = parsedHeader;
+ if (parsedBoundary && boundary && parsedBoundary !== boundary) {
+ throw new Error(`Multipart boundary was specified as ${parsedBoundary} in the header, but got ${boundary} in the request body`);
+ }
+ boundary ??= parsedBoundary;
+ if (boundary) {
+ assertValidBoundary(boundary);
+ }
+ else {
+ boundary = generateBoundary();
+ }
+ request.headers.set("Content-Type", `${contentType}; boundary=${boundary}`);
+ await buildRequestBody(request, request.multipartBody.parts, boundary);
+ request.multipartBody = undefined;
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=multipartPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/createPipelineFromOptions.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+/**
+ * Create a new pipeline with a default set of customizable policies.
+ * @param options - Options to configure a custom pipeline.
+ */
+function createPipelineFromOptions_createPipelineFromOptions(options) {
+ const pipeline = createEmptyPipeline();
+ addPlatformPolicies(pipeline, options);
+ pipeline.addPolicy(formDataPolicy(), { beforePolicies: [multipartPolicyName] });
+ pipeline.addPolicy(userAgentPolicy(options.userAgentOptions));
+ // The multipart policy is added after policies with no phase, so that
+ // policies can be added between it and formDataPolicy to modify
+ // properties (e.g., making the boundary constant in recorded tests).
+ pipeline.addPolicy(multipartPolicy(), { afterPhase: "Deserialize" });
+ pipeline.addPolicy(defaultRetryPolicy(options.retryOptions), { phase: "Retry" });
+ pipeline.addPolicy(logPolicy(options.loggingOptions), { afterPhase: "Sign" });
+ return pipeline;
+}
+//# sourceMappingURL=createPipelineFromOptions.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/auth/checkInsecureConnection.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+// Ensure the warining is only emitted once
+let insecureConnectionWarningEmmitted = false;
+/**
+ * Checks if the request is allowed to be sent over an insecure connection.
+ *
+ * A request is allowed to be sent over an insecure connection when:
+ * - The `allowInsecureConnection` option is set to `true`.
+ * - The request has the `allowInsecureConnection` property set to `true`.
+ * - The request is being sent to `localhost` or `127.0.0.1`
+ */
+function allowInsecureConnection(request, options) {
+ if (options.allowInsecureConnection && request.allowInsecureConnection) {
+ const url = new URL(request.url);
+ if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
+ return true;
+ }
+ }
+ return false;
+}
+/**
+ * Logs a warning about sending a token over an insecure connection.
+ *
+ * This function will emit a node warning once, but log the warning every time.
+ */
+function emitInsecureConnectionWarning() {
+ const warning = "Sending token over insecure transport. Assume any token issued is compromised.";
+ logger.warning(warning);
+ if (!insecureConnectionWarningEmmitted) {
+ insecureConnectionWarningEmmitted = true;
+ emitNodeWarning(warning);
+ }
+}
+/**
+ * Ensures that authentication is only allowed over HTTPS unless explicitly allowed.
+ * Throws an error if the connection is not secure and not explicitly allowed.
+ */
+function checkInsecureConnection_ensureSecureConnection(request, options) {
+ if (!request.url.toLowerCase().startsWith("https://")) {
+ if (allowInsecureConnection(request, options)) {
+ emitInsecureConnectionWarning();
+ }
+ else {
+ throw new Error("Authentication is not permitted for non-TLS protected (non-https) URLs when allowInsecureConnection is false.");
+ }
+ }
+}
+//# sourceMappingURL=checkInsecureConnection.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/auth/apiKeyAuthenticationPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the API Key Authentication Policy
+ */
+const apiKeyAuthenticationPolicyName = "apiKeyAuthenticationPolicy";
+/**
+ * Gets a pipeline policy that adds API key authentication to requests
+ */
+function apiKeyAuthenticationPolicy_apiKeyAuthenticationPolicy(options) {
+ return {
+ name: apiKeyAuthenticationPolicyName,
+ async sendRequest(request, next) {
+ // Ensure allowInsecureConnection is explicitly set when sending request to non-https URLs
+ ensureSecureConnection(request, options);
+ const scheme = (request.authSchemes ?? options.authSchemes)?.find((x) => x.kind === "apiKey");
+ // Skip adding authentication header if no API key authentication scheme is found
+ if (!scheme) {
+ return next(request);
+ }
+ if (scheme.apiKeyLocation !== "header") {
+ throw new Error(`Unsupported API key location: ${scheme.apiKeyLocation}`);
+ }
+ request.headers.set(scheme.name, options.credential.key);
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=apiKeyAuthenticationPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/auth/basicAuthenticationPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * Name of the Basic Authentication Policy
+ */
+const basicAuthenticationPolicyName = "bearerAuthenticationPolicy";
+/**
+ * Gets a pipeline policy that adds basic authentication to requests
+ */
+function basicAuthenticationPolicy_basicAuthenticationPolicy(options) {
+ return {
+ name: basicAuthenticationPolicyName,
+ async sendRequest(request, next) {
+ // Ensure allowInsecureConnection is explicitly set when sending request to non-https URLs
+ ensureSecureConnection(request, options);
+ const scheme = (request.authSchemes ?? options.authSchemes)?.find((x) => x.kind === "http" && x.scheme === "basic");
+ // Skip adding authentication header if no basic authentication scheme is found
+ if (!scheme) {
+ return next(request);
+ }
+ const { username, password } = options.credential;
+ const headerValue = uint8ArrayToString(stringToUint8Array(`${username}:${password}`, "utf-8"), "base64");
+ request.headers.set("Authorization", `Basic ${headerValue}`);
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=basicAuthenticationPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/auth/bearerAuthenticationPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the Bearer Authentication Policy
+ */
+const bearerAuthenticationPolicyName = "bearerAuthenticationPolicy";
+/**
+ * Gets a pipeline policy that adds bearer token authentication to requests
+ */
+function bearerAuthenticationPolicy_bearerAuthenticationPolicy(options) {
+ return {
+ name: bearerAuthenticationPolicyName,
+ async sendRequest(request, next) {
+ // Ensure allowInsecureConnection is explicitly set when sending request to non-https URLs
+ ensureSecureConnection(request, options);
+ const scheme = (request.authSchemes ?? options.authSchemes)?.find((x) => x.kind === "http" && x.scheme === "bearer");
+ // Skip adding authentication header if no bearer authentication scheme is found
+ if (!scheme) {
+ return next(request);
+ }
+ const token = await options.credential.getBearerToken({
+ abortSignal: request.abortSignal,
+ });
+ request.headers.set("Authorization", `Bearer ${token}`);
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=bearerAuthenticationPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/auth/oauth2AuthenticationPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the OAuth2 Authentication Policy
+ */
+const oauth2AuthenticationPolicyName = "oauth2AuthenticationPolicy";
+/**
+ * Gets a pipeline policy that adds authorization header from OAuth2 schemes
+ */
+function oauth2AuthenticationPolicy_oauth2AuthenticationPolicy(options) {
+ return {
+ name: oauth2AuthenticationPolicyName,
+ async sendRequest(request, next) {
+ // Ensure allowInsecureConnection is explicitly set when sending request to non-https URLs
+ ensureSecureConnection(request, options);
+ const scheme = (request.authSchemes ?? options.authSchemes)?.find((x) => x.kind === "oauth2");
+ // Skip adding authentication header if no OAuth2 authentication scheme is found
+ if (!scheme) {
+ return next(request);
+ }
+ const token = await options.credential.getOAuth2Token(scheme.flows, {
+ abortSignal: request.abortSignal,
+ });
+ request.headers.set("Authorization", `Bearer ${token}`);
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=oauth2AuthenticationPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/client/clientHelpers.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+let cachedHttpClient;
+/**
+ * Creates a default rest pipeline to re-use accross Rest Level Clients
+ */
+function clientHelpers_createDefaultPipeline(options = {}) {
+ const pipeline = createPipelineFromOptions(options);
+ pipeline.addPolicy(apiVersionPolicy(options));
+ const { credential, authSchemes, allowInsecureConnection } = options;
+ if (credential) {
+ if (isApiKeyCredential(credential)) {
+ pipeline.addPolicy(apiKeyAuthenticationPolicy({ authSchemes, credential, allowInsecureConnection }));
+ }
+ else if (isBasicCredential(credential)) {
+ pipeline.addPolicy(basicAuthenticationPolicy({ authSchemes, credential, allowInsecureConnection }));
+ }
+ else if (isBearerTokenCredential(credential)) {
+ pipeline.addPolicy(bearerAuthenticationPolicy({ authSchemes, credential, allowInsecureConnection }));
+ }
+ else if (isOAuth2TokenCredential(credential)) {
+ pipeline.addPolicy(oauth2AuthenticationPolicy({ authSchemes, credential, allowInsecureConnection }));
+ }
+ }
+ return pipeline;
+}
+function clientHelpers_getCachedDefaultHttpsClient() {
+ if (!cachedHttpClient) {
+ cachedHttpClient = createDefaultHttpClient();
+ }
+ return cachedHttpClient;
+}
+//# sourceMappingURL=clientHelpers.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/client/multipart.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+/**
+ * Get value of a header in the part descriptor ignoring case
+ */
+function getHeaderValue(descriptor, headerName) {
+ if (descriptor.headers) {
+ const actualHeaderName = Object.keys(descriptor.headers).find((x) => x.toLowerCase() === headerName.toLowerCase());
+ if (actualHeaderName) {
+ return descriptor.headers[actualHeaderName];
+ }
+ }
+ return undefined;
+}
+function getPartContentType(descriptor) {
+ const contentTypeHeader = getHeaderValue(descriptor, "content-type");
+ if (contentTypeHeader) {
+ return contentTypeHeader;
+ }
+ // Special value of null means content type is to be omitted
+ if (descriptor.contentType === null) {
+ return undefined;
+ }
+ if (descriptor.contentType) {
+ return descriptor.contentType;
+ }
+ const { body } = descriptor;
+ if (body === null || body === undefined) {
+ return undefined;
+ }
+ if (typeof body === "string" || typeof body === "number" || typeof body === "boolean") {
+ return "text/plain; charset=UTF-8";
+ }
+ if (body instanceof Blob) {
+ return body.type || "application/octet-stream";
+ }
+ if (isBinaryBody(body)) {
+ return "application/octet-stream";
+ }
+ // arbitrary non-text object -> generic JSON content type by default. We will try to JSON.stringify the body.
+ return "application/json";
+}
+/**
+ * Enclose value in quotes and escape special characters, for use in the Content-Disposition header
+ */
+function escapeDispositionField(value) {
+ return JSON.stringify(value);
+}
+function getContentDisposition(descriptor) {
+ const contentDispositionHeader = getHeaderValue(descriptor, "content-disposition");
+ if (contentDispositionHeader) {
+ return contentDispositionHeader;
+ }
+ if (descriptor.dispositionType === undefined &&
+ descriptor.name === undefined &&
+ descriptor.filename === undefined) {
+ return undefined;
+ }
+ const dispositionType = descriptor.dispositionType ?? "form-data";
+ let disposition = dispositionType;
+ if (descriptor.name) {
+ disposition += `; name=${escapeDispositionField(descriptor.name)}`;
+ }
+ let filename = undefined;
+ if (descriptor.filename) {
+ filename = descriptor.filename;
+ }
+ else if (typeof File !== "undefined" && descriptor.body instanceof File) {
+ const filenameFromFile = descriptor.body.name;
+ if (filenameFromFile !== "") {
+ filename = filenameFromFile;
+ }
+ }
+ if (filename) {
+ disposition += `; filename=${escapeDispositionField(filename)}`;
+ }
+ return disposition;
+}
+function normalizeBody(body, contentType) {
+ if (body === undefined) {
+ // zero-length body
+ return new Uint8Array([]);
+ }
+ // binary and primitives should go straight on the wire regardless of content type
+ if (isBinaryBody(body)) {
+ return body;
+ }
+ if (typeof body === "string" || typeof body === "number" || typeof body === "boolean") {
+ return stringToUint8Array(String(body), "utf-8");
+ }
+ // stringify objects for JSON-ish content types e.g. application/json, application/merge-patch+json, application/vnd.oci.manifest.v1+json, application.json; charset=UTF-8
+ if (contentType && /application\/(.+\+)?json(;.+)?/i.test(String(contentType))) {
+ return stringToUint8Array(JSON.stringify(body), "utf-8");
+ }
+ throw new RestError(`Unsupported body/content-type combination: ${body}, ${contentType}`);
+}
+function buildBodyPart(descriptor) {
+ const contentType = getPartContentType(descriptor);
+ const contentDisposition = getContentDisposition(descriptor);
+ const headers = createHttpHeaders(descriptor.headers ?? {});
+ if (contentType) {
+ headers.set("content-type", contentType);
+ }
+ if (contentDisposition) {
+ headers.set("content-disposition", contentDisposition);
+ }
+ const body = normalizeBody(descriptor.body, contentType);
+ return {
+ headers,
+ body,
+ };
+}
+function multipart_buildMultipartBody(parts) {
+ return { parts: parts.map(buildBodyPart) };
+}
+//# sourceMappingURL=multipart.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/client/sendRequest.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+/**
+ * Helper function to send request used by the client
+ * @param method - method to use to send the request
+ * @param url - url to send the request to
+ * @param pipeline - pipeline with the policies to run when sending the request
+ * @param options - request options
+ * @param customHttpClient - a custom HttpClient to use when making the request
+ * @returns returns and HttpResponse
+ */
+async function sendRequest_sendRequest(method, url, pipeline, options = {}, customHttpClient) {
+ const httpClient = customHttpClient ?? getCachedDefaultHttpsClient();
+ const request = buildPipelineRequest(method, url, options);
+ try {
+ const response = await pipeline.sendRequest(httpClient, request);
+ const headers = response.headers.toJSON();
+ const stream = response.readableStreamBody ?? response.browserStreamBody;
+ const parsedBody = options.responseAsStream || stream !== undefined ? undefined : getResponseBody(response);
+ const body = stream ?? parsedBody;
+ if (options?.onResponse) {
+ options.onResponse({ ...response, request, rawHeaders: headers, parsedBody });
+ }
+ return {
+ request,
+ headers,
+ status: `${response.status}`,
+ body,
+ };
+ }
+ catch (e) {
+ if (isRestError(e) && e.response && options.onResponse) {
+ const { response } = e;
+ const rawHeaders = response.headers.toJSON();
+ // UNBRANDED DIFFERENCE: onResponse callback does not have a second __legacyError property
+ options?.onResponse({ ...response, request, rawHeaders }, e);
+ }
+ throw e;
+ }
+}
+/**
+ * Function to determine the request content type
+ * @param options - request options InternalRequestParameters
+ * @returns returns the content-type
+ */
+function getRequestContentType(options = {}) {
+ if (options.contentType) {
+ return options.contentType;
+ }
+ const headerContentType = options.headers?.["content-type"];
+ if (typeof headerContentType === "string") {
+ return headerContentType;
+ }
+ return getContentType(options.body);
+}
+/**
+ * Function to determine the content-type of a body
+ * this is used if an explicit content-type is not provided
+ * @param body - body in the request
+ * @returns returns the content-type
+ */
+function getContentType(body) {
+ if (body === undefined) {
+ return undefined;
+ }
+ if (ArrayBuffer.isView(body)) {
+ return "application/octet-stream";
+ }
+ if (isBlob(body) && body.type) {
+ return body.type;
+ }
+ if (typeof body === "string") {
+ try {
+ JSON.parse(body);
+ return "application/json";
+ }
+ catch (error) {
+ // If we fail to parse the body, it is not json
+ return undefined;
+ }
+ }
+ // By default return json
+ return "application/json";
+}
+function buildPipelineRequest(method, url, options = {}) {
+ const requestContentType = getRequestContentType(options);
+ const { body, multipartBody } = getRequestBody(options.body, requestContentType);
+ const headers = createHttpHeaders({
+ ...(options.headers ? options.headers : {}),
+ accept: options.accept ?? options.headers?.accept ?? "application/json",
+ ...(requestContentType && {
+ "content-type": requestContentType,
+ }),
+ });
+ const { allowInsecureConnection, abortSignal, onUploadProgress, onDownloadProgress, timeout, responseAsStream, url: _url, method: _method, body: _body, multipartBody: _multiBody, headers: _headers, ...rest } = options;
+ const request = createPipelineRequest({
+ url,
+ method,
+ body,
+ multipartBody,
+ headers,
+ allowInsecureConnection,
+ abortSignal,
+ onUploadProgress,
+ onDownloadProgress,
+ timeout,
+ enableBrowserStreams: true,
+ streamResponseStatusCodes: responseAsStream ? new Set([Number.POSITIVE_INFINITY]) : undefined,
+ });
+ Object.assign(request, rest);
+ return request;
+}
+/**
+ * Prepares the body before sending the request
+ */
+function getRequestBody(body, contentType = "") {
+ if (body === undefined) {
+ return { body: undefined };
+ }
+ if (typeof FormData !== "undefined" && body instanceof FormData) {
+ return { body };
+ }
+ if (isBlob(body)) {
+ return { body };
+ }
+ if (isReadableStream(body)) {
+ return { body };
+ }
+ if (typeof body === "function") {
+ return { body: body };
+ }
+ if (ArrayBuffer.isView(body)) {
+ return {
+ body: body instanceof Uint8Array ? body : JSON.stringify(body),
+ };
+ }
+ const firstType = contentType.split(";")[0];
+ switch (firstType) {
+ case "application/json":
+ return { body: JSON.stringify(body) };
+ case "multipart/form-data":
+ if (Array.isArray(body)) {
+ return { multipartBody: buildMultipartBody(body) };
+ }
+ return { body: JSON.stringify(body) };
+ case "text/plain":
+ return { body: String(body) };
+ default:
+ if (typeof body === "string") {
+ return { body };
+ }
+ return { body: JSON.stringify(body) };
+ }
+}
+/**
+ * Prepares the response body
+ */
+function getResponseBody(response) {
+ // Set the default response type
+ const contentType = response.headers.get("content-type") ?? "";
+ const firstType = contentType.split(";")[0];
+ const bodyToParse = response.bodyAsText ?? "";
+ if (firstType === "text/plain") {
+ return String(bodyToParse);
+ }
+ // Default to "application/json" and fallback to string;
+ try {
+ return bodyToParse ? JSON.parse(bodyToParse) : undefined;
+ }
+ catch (error) {
+ // If we were supposed to get a JSON object and failed to
+ // parse, throw a parse error
+ if (firstType === "application/json") {
+ throw createParseError(response, error);
+ }
+ // We are not sure how to handle the response so we return it as
+ // plain text.
+ return String(bodyToParse);
+ }
+}
+function createParseError(response, err) {
+ const msg = `Error "${err}" occurred while parsing the response body - ${response.bodyAsText}.`;
+ const errCode = err.code ?? RestError.PARSE_ERROR;
+ return new RestError(msg, {
+ code: errCode,
+ statusCode: response.status,
+ request: response.request,
+ response: response,
+ });
+}
+//# sourceMappingURL=sendRequest.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/client/getClient.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+/**
+ * Creates a client with a default pipeline
+ * @param endpoint - Base endpoint for the client
+ * @param credentials - Credentials to authenticate the requests
+ * @param options - Client options
+ */
+function getClient(endpoint, clientOptions = {}) {
+ const pipeline = clientOptions.pipeline ?? createDefaultPipeline(clientOptions);
+ if (clientOptions.additionalPolicies?.length) {
+ for (const { policy, position } of clientOptions.additionalPolicies) {
+ // Sign happens after Retry and is commonly needed to occur
+ // before policies that intercept post-retry.
+ const afterPhase = position === "perRetry" ? "Sign" : undefined;
+ pipeline.addPolicy(policy, {
+ afterPhase,
+ });
+ }
+ }
+ const { allowInsecureConnection, httpClient } = clientOptions;
+ const endpointUrl = clientOptions.endpoint ?? endpoint;
+ const client = (path, ...args) => {
+ const getUrl = (requestOptions) => buildRequestUrl(endpointUrl, path, args, { allowInsecureConnection, ...requestOptions });
+ return {
+ get: (requestOptions = {}) => {
+ return buildOperation("GET", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ post: (requestOptions = {}) => {
+ return buildOperation("POST", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ put: (requestOptions = {}) => {
+ return buildOperation("PUT", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ patch: (requestOptions = {}) => {
+ return buildOperation("PATCH", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ delete: (requestOptions = {}) => {
+ return buildOperation("DELETE", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ head: (requestOptions = {}) => {
+ return buildOperation("HEAD", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ options: (requestOptions = {}) => {
+ return buildOperation("OPTIONS", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ trace: (requestOptions = {}) => {
+ return buildOperation("TRACE", getUrl(requestOptions), pipeline, requestOptions, allowInsecureConnection, httpClient);
+ },
+ };
+ };
+ return {
+ path: client,
+ pathUnchecked: client,
+ pipeline,
+ };
+}
+function buildOperation(method, url, pipeline, options, allowInsecureConnection, httpClient) {
+ allowInsecureConnection = options.allowInsecureConnection ?? allowInsecureConnection;
+ return {
+ then: function (onFulfilled, onrejected) {
+ return sendRequest(method, url, pipeline, { ...options, allowInsecureConnection }, httpClient).then(onFulfilled, onrejected);
+ },
+ async asBrowserStream() {
+ if (isNodeLike) {
+ throw new Error("`asBrowserStream` is supported only in the browser environment. Use `asNodeStream` instead to obtain the response body stream. If you require a Web stream of the response in Node, consider using `Readable.toWeb` on the result of `asNodeStream`.");
+ }
+ else {
+ return sendRequest(method, url, pipeline, { ...options, allowInsecureConnection, responseAsStream: true }, httpClient);
+ }
+ },
+ async asNodeStream() {
+ if (isNodeLike) {
+ return sendRequest(method, url, pipeline, { ...options, allowInsecureConnection, responseAsStream: true }, httpClient);
+ }
+ else {
+ throw new Error("`isNodeStream` is not supported in the browser environment. Use `asBrowserStream` to obtain the response body stream.");
+ }
+ },
+ };
+}
+//# sourceMappingURL=getClient.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/client/restError.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+function createRestError(messageOrResponse, response) {
+ const resp = typeof messageOrResponse === "string" ? response : messageOrResponse;
+ const internalError = resp.body?.error ?? resp.body;
+ const message = typeof messageOrResponse === "string"
+ ? messageOrResponse
+ : (internalError?.message ?? `Unexpected status code: ${resp.status}`);
+ return new RestError(message, {
+ statusCode: statusCodeToNumber(resp.status),
+ code: internalError?.code,
+ request: resp.request,
+ response: toPipelineResponse(resp),
+ });
+}
+function toPipelineResponse(errorResponse) {
+ return {
+ headers: createHttpHeaders(errorResponse.headers),
+ request: errorResponse.request,
+ status: statusCodeToNumber(errorResponse.status) ?? -1,
+ ...(typeof errorResponse.body === "string" ? { bodyAsText: errorResponse.body } : {}),
+ };
+}
+function statusCodeToNumber(statusCode) {
+ const status = Number.parseInt(statusCode);
+ return Number.isNaN(status) ? undefined : status;
+}
+//# sourceMappingURL=restError.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+
+
+
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/pipeline.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Creates a totally empty pipeline.
+ * Useful for testing or creating a custom one.
+ */
+function esm_pipeline_createEmptyPipeline() {
+ return pipeline_createEmptyPipeline();
+}
+//# sourceMappingURL=pipeline.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/logger/internal.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+//# sourceMappingURL=internal.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/logger/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const esm_context = createLoggerContext({
+ logLevelEnvVarName: "AZURE_LOG_LEVEL",
+ namespace: "azure",
+});
+/**
+ * The AzureLogger provides a mechanism for overriding where logs are output to.
+ * By default, logs are sent to stderr.
+ * Override the `log` method to redirect logs to another location.
+ */
+const AzureLogger = esm_context.logger;
+/**
+ * Immediately enables logging at the specified log level. If no level is specified, logging is disabled.
+ * @param level - The log level to enable for logging.
+ * Options from most verbose to least verbose are:
+ * - verbose
+ * - info
+ * - warning
+ * - error
+ */
+function esm_setLogLevel(level) {
+ esm_context.setLogLevel(level);
+}
+/**
+ * Retrieves the currently specified log level.
+ */
+function esm_getLogLevel() {
+ return esm_context.getLogLevel();
+}
+/**
+ * Creates a logger for use by the Azure SDKs that inherits from `AzureLogger`.
+ * @param namespace - The name of the SDK package.
+ * @hidden
+ */
+function esm_createClientLogger(namespace) {
+ return esm_context.createClientLogger(namespace);
+}
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/log.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const esm_log_logger = esm_createClientLogger("core-rest-pipeline");
+//# sourceMappingURL=log.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/agentPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Name of the Agent Policy
+ */
+const agentPolicyName = "agentPolicy";
+/**
+ * Gets a pipeline policy that sets http.agent
+ */
+function agentPolicy_agentPolicy(agent) {
+ return {
+ name: agentPolicyName,
+ sendRequest: async (req, next) => {
+ // Users may define an agent on the request, honor it over the client level one
+ if (!req.agent) {
+ req.agent = agent;
+ }
+ return next(req);
+ },
+ };
+}
+//# sourceMappingURL=agentPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/decompressResponsePolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * The programmatic identifier of the decompressResponsePolicy.
+ */
+const decompressResponsePolicyName = "decompressResponsePolicy";
+/**
+ * A policy to enable response decompression according to Accept-Encoding header
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
+ */
+function decompressResponsePolicy_decompressResponsePolicy() {
+ return {
+ name: decompressResponsePolicyName,
+ async sendRequest(request, next) {
+ // HEAD requests have no body
+ if (request.method !== "HEAD") {
+ request.headers.set("Accept-Encoding", "gzip,deflate");
+ }
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=decompressResponsePolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/exponentialRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+/**
+ * The programmatic identifier of the exponentialRetryPolicy.
+ */
+const exponentialRetryPolicyName = "exponentialRetryPolicy";
+/**
+ * A policy that attempts to retry requests while introducing an exponentially increasing delay.
+ * @param options - Options that configure retry logic.
+ */
+function exponentialRetryPolicy(options = {}) {
+ return retryPolicy([
+ exponentialRetryStrategy({
+ ...options,
+ ignoreSystemErrors: true,
+ }),
+ ], {
+ maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY_COUNT,
+ });
+}
+//# sourceMappingURL=exponentialRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/systemErrorRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+/**
+ * Name of the {@link systemErrorRetryPolicy}
+ */
+const systemErrorRetryPolicyName = "systemErrorRetryPolicy";
+/**
+ * A retry policy that specifically seeks to handle errors in the
+ * underlying transport layer (e.g. DNS lookup failures) rather than
+ * retryable error codes from the server itself.
+ * @param options - Options that customize the policy.
+ */
+function systemErrorRetryPolicy(options = {}) {
+ return {
+ name: systemErrorRetryPolicyName,
+ sendRequest: retryPolicy([
+ exponentialRetryStrategy({
+ ...options,
+ ignoreHttpStatusCodes: true,
+ }),
+ ], {
+ maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY_COUNT,
+ }).sendRequest,
+ };
+}
+//# sourceMappingURL=systemErrorRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/throttlingRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+/**
+ * Name of the {@link throttlingRetryPolicy}
+ */
+const throttlingRetryPolicyName = "throttlingRetryPolicy";
+/**
+ * A policy that retries when the server sends a 429 response with a Retry-After header.
+ *
+ * To learn more, please refer to
+ * https://learn.microsoft.com/azure/azure-resource-manager/resource-manager-request-limits,
+ * https://learn.microsoft.com/azure/azure-subscription-service-limits and
+ * https://learn.microsoft.com/azure/virtual-machines/troubleshooting/troubleshooting-throttling-errors
+ *
+ * @param options - Options that configure retry logic.
+ */
+function throttlingRetryPolicy(options = {}) {
+ return {
+ name: throttlingRetryPolicyName,
+ sendRequest: retryPolicy([throttlingRetryStrategy()], {
+ maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY_COUNT,
+ }).sendRequest,
+ };
+}
+//# sourceMappingURL=throttlingRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/tlsPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Name of the TLS Policy
+ */
+const tlsPolicyName = "tlsPolicy";
+/**
+ * Gets a pipeline policy that adds the client certificate to the HttpClient agent for authentication.
+ */
+function tlsPolicy_tlsPolicy(tlsSettings) {
+ return {
+ name: tlsPolicyName,
+ sendRequest: async (req, next) => {
+ // Users may define a request tlsSettings, honor those over the client level one
+ if (!req.tlsSettings) {
+ req.tlsSettings = tlsSettings;
+ }
+ return next(req);
+ },
+ };
+}
+//# sourceMappingURL=tlsPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/internal.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//# sourceMappingURL=internal.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/logPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * The programmatic identifier of the logPolicy.
+ */
+const logPolicy_logPolicyName = (/* unused pure expression or super */ null && (tspLogPolicyName));
+/**
+ * A policy that logs all requests and responses.
+ * @param options - Options to configure logPolicy.
+ */
+function policies_logPolicy_logPolicy(options = {}) {
+ return logPolicy_logPolicy({
+ logger: esm_log_logger.info,
+ ...options,
+ });
+}
+//# sourceMappingURL=logPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/redirectPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * The programmatic identifier of the redirectPolicy.
+ */
+const redirectPolicy_redirectPolicyName = redirectPolicyName;
+/**
+ * A policy to follow Location headers from the server in order
+ * to support server-side redirection.
+ * In the browser, this policy is not used.
+ * @param options - Options to control policy behavior.
+ */
+function policies_redirectPolicy_redirectPolicy(options = {}) {
+ return redirectPolicy_redirectPolicy(options);
+}
+//# sourceMappingURL=redirectPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/util/userAgentPlatform.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * @internal
+ */
+function userAgentPlatform_getHeaderName() {
+ return "User-Agent";
+}
+/**
+ * @internal
+ */
+async function util_userAgentPlatform_setPlatformSpecificData(map) {
+ if (external_node_process_ && external_node_process_.versions) {
+ const osInfo = `${external_node_os_.type()} ${external_node_os_.release()}; ${external_node_os_.arch()}`;
+ if (external_node_process_.versions.bun) {
+ map.set("Bun", `${external_node_process_.versions.bun} (${osInfo})`);
+ }
+ else if (external_node_process_.versions.deno) {
+ map.set("Deno", `${external_node_process_.versions.deno} (${osInfo})`);
+ }
+ else if (external_node_process_.versions.node) {
+ map.set("Node", `${external_node_process_.versions.node} (${osInfo})`);
+ }
+ }
+}
+//# sourceMappingURL=userAgentPlatform.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/constants.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+const esm_constants_SDK_VERSION = "1.25.0";
+const esm_constants_DEFAULT_RETRY_POLICY_COUNT = 3;
+//# sourceMappingURL=constants.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/util/userAgent.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+function userAgent_getUserAgentString(telemetryInfo) {
+ const parts = [];
+ for (const [key, value] of telemetryInfo) {
+ const token = value ? `${key}/${value}` : key;
+ parts.push(token);
+ }
+ return parts.join(" ");
+}
+/**
+ * @internal
+ */
+function userAgent_getUserAgentHeaderName() {
+ return userAgentPlatform_getHeaderName();
+}
+/**
+ * @internal
+ */
+async function util_userAgent_getUserAgentValue(prefix) {
+ const runtimeInfo = new Map();
+ runtimeInfo.set("core-rest-pipeline", esm_constants_SDK_VERSION);
+ await util_userAgentPlatform_setPlatformSpecificData(runtimeInfo);
+ const defaultAgent = userAgent_getUserAgentString(runtimeInfo);
+ const userAgentValue = prefix ? `${prefix} ${defaultAgent}` : defaultAgent;
+ return userAgentValue;
+}
+//# sourceMappingURL=userAgent.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/userAgentPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const userAgentPolicy_UserAgentHeaderName = userAgent_getUserAgentHeaderName();
+/**
+ * The programmatic identifier of the userAgentPolicy.
+ */
+const userAgentPolicy_userAgentPolicyName = "userAgentPolicy";
+/**
+ * A policy that sets the User-Agent header (or equivalent) to reflect
+ * the library version.
+ * @param options - Options to customize the user agent value.
+ */
+function policies_userAgentPolicy_userAgentPolicy(options = {}) {
+ const userAgentValue = util_userAgent_getUserAgentValue(options.userAgentPrefix);
+ return {
+ name: userAgentPolicy_userAgentPolicyName,
+ async sendRequest(request, next) {
+ if (!request.headers.has(userAgentPolicy_UserAgentHeaderName)) {
+ request.headers.set(userAgentPolicy_UserAgentHeaderName, await userAgentValue);
+ }
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=userAgentPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/util/createFile.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Create an object that implements the File interface. This object is intended to be
+ * passed into RequestBodyType.formData, and is not guaranteed to work as expected in
+ * other situations.
+ *
+ * Use this function to create a File object for use in RequestBodyType.formData in environments
+ * where the global File object is unavailable.
+ *
+ * @param content - the content of the file as a Uint8Array in memory.
+ * @param name - the name of the file.
+ * @param options - optional metadata about the file, e.g. file name, file size, MIME type.
+ */
+function createFile(content, name, options = {}) {
+ return createRawFile(content, name, options);
+}
+//# sourceMappingURL=createFile.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/util/file.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+function file_isNodeReadableStream(x) {
+ return typeof x === "object" && x !== null && "pipe" in x && typeof x.pipe === "function";
+}
+const unimplementedMethods = {
+ arrayBuffer: () => {
+ throw new Error("Not implemented");
+ },
+ bytes: () => {
+ throw new Error("Not implemented");
+ },
+ slice: () => {
+ throw new Error("Not implemented");
+ },
+ text: () => {
+ throw new Error("Not implemented");
+ },
+};
+/**
+ * Private symbol used as key on objects created using createFile containing the
+ * original source of the file object.
+ *
+ * This is used in Node to access the original Node stream without using Blob#stream, which
+ * returns a web stream. This is done to avoid a couple of bugs to do with Blob#stream and
+ * Readable#to/fromWeb in Node versions we support:
+ * - https://github.com/nodejs/node/issues/42694 (fixed in Node 18.14)
+ * - https://github.com/nodejs/node/issues/48916 (fixed in Node 20.6)
+ *
+ * Once these versions are no longer supported, we may be able to stop doing this.
+ *
+ * @internal
+ */
+const rawContent = Symbol("rawContent");
+/**
+ * Type guard to check if a given object is a blob-like object with a raw content property.
+ */
+function hasRawContent(x) {
+ return typeof x[rawContent] === "function";
+}
+/**
+ * Extract the raw content from a given blob-like object. If the input was created using createFile
+ * or createFileFromStream, the exact content passed into createFile/createFileFromStream will be used.
+ * For true instances of Blob and File, returns the actual blob.
+ *
+ * @internal
+ */
+function getRawContent(blob) {
+ if (hasRawContent(blob)) {
+ return blob[rawContent]();
+ }
+ else {
+ return blob;
+ }
+}
+/**
+ * @internal
+ *
+ * Creates a File-like object tagged with rawContent for efficient streaming access.
+ * Used by the Node createFile to avoid Blob#stream() bugs.
+ */
+function file_createRawFile(content, name, options = {}) {
+ return {
+ ...unimplementedMethods,
+ type: options.type ?? "",
+ lastModified: options.lastModified ?? new Date().getTime(),
+ webkitRelativePath: options.webkitRelativePath ?? "",
+ size: content.byteLength,
+ name,
+ arrayBuffer: async () => toArrayBuffer(content).buffer,
+ stream: () => new Blob([toArrayBuffer(content)]).stream(),
+ [rawContent]: () => content,
+ };
+}
+/**
+ * Create an object that implements the File interface. This object is intended to be
+ * passed into RequestBodyType.formData, and is not guaranteed to work as expected in
+ * other situations.
+ *
+ * Use this function to:
+ * - Create a File object for use in RequestBodyType.formData in environments where the
+ * global File object is unavailable.
+ * - Create a File-like object from a readable stream without reading the stream into memory.
+ *
+ * @param stream - the content of the file as a callback returning a stream. When a File object made using createFile is
+ * passed in a request's form data map, the stream will not be read into memory
+ * and instead will be streamed when the request is made. In the event of a retry, the
+ * stream needs to be read again, so this callback SHOULD return a fresh stream if possible.
+ * @param name - the name of the file.
+ * @param options - optional metadata about the file, e.g. file name, file size, MIME type.
+ */
+function createFileFromStream(stream, name, options = {}) {
+ return {
+ ...unimplementedMethods,
+ type: options.type ?? "",
+ lastModified: options.lastModified ?? new Date().getTime(),
+ webkitRelativePath: options.webkitRelativePath ?? "",
+ size: options.size ?? -1,
+ name,
+ stream: () => {
+ const s = stream();
+ if (file_isNodeReadableStream(s)) {
+ throw new Error("Not supported: a Node stream was provided as input to createFileFromStream.");
+ }
+ return s;
+ },
+ [rawContent]: stream,
+ };
+}
+
+function hasArrayBuffer(source) {
+ return "resize" in source.buffer;
+}
+function toArrayBuffer(source) {
+ if (hasArrayBuffer(source)) {
+ // ArrayBuffer — return a copy if the view is a subarray of a larger buffer
+ if (source.byteOffset !== 0 || source.byteLength !== source.buffer.byteLength) {
+ return new Uint8Array(source);
+ }
+ return source;
+ }
+ // SharedArrayBuffer
+ return source.map((x) => x);
+}
+//# sourceMappingURL=file.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/multipartPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * Name of multipart policy
+ */
+const policies_multipartPolicy_multipartPolicyName = multipartPolicy_multipartPolicyName;
+/**
+ * Pipeline policy for multipart requests
+ */
+function policies_multipartPolicy_multipartPolicy() {
+ const tspPolicy = multipartPolicy_multipartPolicy();
+ return {
+ name: policies_multipartPolicy_multipartPolicyName,
+ sendRequest: async (request, next) => {
+ if (request.multipartBody) {
+ for (const part of request.multipartBody.parts) {
+ if (hasRawContent(part.body)) {
+ part.body = getRawContent(part.body);
+ }
+ }
+ }
+ return tspPolicy.sendRequest(request, next);
+ },
+ };
+}
+//# sourceMappingURL=multipartPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/decompressResponsePolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * The programmatic identifier of the decompressResponsePolicy.
+ */
+const decompressResponsePolicy_decompressResponsePolicyName = decompressResponsePolicyName;
+/**
+ * A policy to enable response decompression according to Accept-Encoding header
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
+ */
+function policies_decompressResponsePolicy_decompressResponsePolicy() {
+ return decompressResponsePolicy_decompressResponsePolicy();
+}
+//# sourceMappingURL=decompressResponsePolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/defaultRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the {@link defaultRetryPolicy}
+ */
+const defaultRetryPolicy_defaultRetryPolicyName = (/* unused pure expression or super */ null && (tspDefaultRetryPolicyName));
+/**
+ * A policy that retries according to three strategies:
+ * - When the server sends a 429 response with a Retry-After header.
+ * - When there are errors in the underlying transport layer (e.g. DNS lookup failures).
+ * - Or otherwise if the outgoing request fails, it will retry with an exponentially increasing delay.
+ */
+function policies_defaultRetryPolicy_defaultRetryPolicy(options = {}) {
+ return defaultRetryPolicy_defaultRetryPolicy(options);
+}
+//# sourceMappingURL=defaultRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/formDataPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * The programmatic identifier of the formDataPolicy.
+ */
+const formDataPolicy_formDataPolicyName = (/* unused pure expression or super */ null && (tspFormDataPolicyName));
+/**
+ * A policy that encodes FormData on the request into the body.
+ */
+function policies_formDataPolicy_formDataPolicy() {
+ return formDataPolicy_formDataPolicy();
+}
+//# sourceMappingURL=formDataPolicy.js.map
+// EXTERNAL MODULE: external "node:crypto"
+var external_node_crypto_ = __webpack_require__(7598);
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/sha256.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Generates a SHA-256 HMAC signature.
+ * @param key - The HMAC key represented as a base64 string, used to generate the cryptographic HMAC hash.
+ * @param stringToSign - The data to be signed.
+ * @param encoding - The textual encoding to use for the returned HMAC digest.
+ */
+async function computeSha256Hmac(key, stringToSign, encoding) {
+ const decodedKey = Buffer.from(key, "base64");
+ return createHmac("sha256", decodedKey).update(stringToSign).digest(encoding);
+}
+/**
+ * Generates a SHA-256 hash.
+ * @param content - The data to be included in the hash.
+ * @param encoding - The textual encoding to use for the returned hash.
+ */
+async function computeSha256Hash(content, encoding) {
+ return createHash("sha256").update(content).digest(encoding);
+}
+//# sourceMappingURL=sha256.js.map
+;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/internal.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+
+//# sourceMappingURL=internal.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/abort-controller/dist/esm/AbortError.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * This error is thrown when an asynchronous operation has been aborted.
+ * Check for this error by testing the `name` that the name property of the
+ * error matches `"AbortError"`.
+ *
+ * @example
+ * ```ts snippet:AbortErrorSample
+ * import { AbortError } from "@azure/abort-controller";
+ *
+ * async function doAsyncWork(options: { abortSignal: AbortSignal }): Promise {
+ * if (options.abortSignal.aborted) {
+ * throw new AbortError();
+ * }
+ *
+ * // do async work
+ * }
+ *
+ * const controller = new AbortController();
+ * controller.abort();
+ * try {
+ * doAsyncWork({ abortSignal: controller.signal });
+ * } catch (e) {
+ * if (e instanceof Error && e.name === "AbortError") {
+ * // handle abort error here.
+ * }
+ * }
+ * ```
+ */
+class AbortError_AbortError extends Error {
+ constructor(message) {
+ super(message);
+ this.name = "AbortError";
+ }
+}
+//# sourceMappingURL=AbortError.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/abort-controller/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-util/dist/esm/createAbortablePromise.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Creates an abortable promise.
+ * @param buildPromise - A function that takes the resolve and reject functions as parameters.
+ * @param options - The options for the abortable promise.
+ * @returns A promise that can be aborted.
+ */
+function createAbortablePromise(buildPromise, options) {
+ const { cleanupBeforeAbort, abortSignal, abortErrorMsg } = options ?? {};
+ return new Promise((resolve, reject) => {
+ function rejectOnAbort() {
+ reject(new AbortError_AbortError(abortErrorMsg ?? "The operation was aborted."));
+ }
+ function removeListeners() {
+ abortSignal?.removeEventListener("abort", onAbort);
+ }
+ function onAbort() {
+ cleanupBeforeAbort?.();
+ removeListeners();
+ rejectOnAbort();
+ }
+ if (abortSignal?.aborted) {
+ return rejectOnAbort();
+ }
+ try {
+ buildPromise((x) => {
+ removeListeners();
+ resolve(x);
+ }, (x) => {
+ removeListeners();
+ reject(x);
+ });
+ }
+ catch (err) {
+ reject(err);
+ }
+ abortSignal?.addEventListener("abort", onAbort);
+ });
+}
+//# sourceMappingURL=createAbortablePromise.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-util/dist/esm/delay.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const delay_StandardAbortMessage = "The delay was aborted.";
+/**
+ * A wrapper for setTimeout that resolves a promise after timeInMs milliseconds.
+ * @param timeInMs - The number of milliseconds to be delayed.
+ * @param options - The options for delay - currently abort options
+ * @returns Promise that is resolved after timeInMs
+ */
+function delay_delay(timeInMs, options) {
+ let token;
+ const { abortSignal, abortErrorMsg } = options ?? {};
+ return createAbortablePromise((resolve) => {
+ token = setTimeout(resolve, timeInMs);
+ }, {
+ cleanupBeforeAbort: () => clearTimeout(token),
+ abortSignal,
+ abortErrorMsg: abortErrorMsg ?? delay_StandardAbortMessage,
+ });
+}
+//# sourceMappingURL=delay.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-util/dist/esm/error.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Given what is thought to be an error object, return the message if possible.
+ * If the message is missing, returns a stringified version of the input.
+ * @param e - Something thrown from a try block
+ * @returns The error message or a string of the input
+ */
+function getErrorMessage(e) {
+ if (isError(e)) {
+ return e.message;
+ }
+ else {
+ let stringified;
+ try {
+ if (typeof e === "object" && e) {
+ stringified = JSON.stringify(e);
+ }
+ else {
+ stringified = String(e);
+ }
+ }
+ catch (err) {
+ stringified = "[unable to stringify input]";
+ }
+ return `Unknown error ${stringified}`;
+ }
+}
+//# sourceMappingURL=error.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-util/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+/**
+ * Calculates the delay interval for retry attempts using exponential delay with jitter.
+ *
+ * @param retryAttempt - The current retry attempt number.
+ *
+ * @param config - The exponential retry configuration.
+ *
+ * @returns An object containing the calculated retry delay.
+ */
+function esm_calculateRetryDelay(retryAttempt, config) {
+ return tspRuntime.calculateRetryDelay(retryAttempt, config);
+}
+/**
+ * Generates a SHA-256 hash.
+ *
+ * @param content - The data to be included in the hash.
+ *
+ * @param encoding - The textual encoding to use for the returned hash.
+ */
+function esm_computeSha256Hash(content, encoding) {
+ return tspRuntime.computeSha256Hash(content, encoding);
+}
+/**
+ * Generates a SHA-256 HMAC signature.
+ *
+ * @param key - The HMAC key represented as a base64 string, used to generate the cryptographic HMAC hash.
+ *
+ * @param stringToSign - The data to be signed.
+ *
+ * @param encoding - The textual encoding to use for the returned HMAC digest.
+ */
+function esm_computeSha256Hmac(key, stringToSign, encoding) {
+ return tspRuntime.computeSha256Hmac(key, stringToSign, encoding);
+}
+/**
+ * Returns a random integer value between a lower and upper bound, inclusive of both bounds. Note that this uses Math.random and isn't secure. If you need to use this for any kind of security purpose, find a better source of random.
+ *
+ * @param min - The smallest integer value allowed.
+ *
+ * @param max - The largest integer value allowed.
+ */
+function esm_getRandomIntegerInclusive(min, max) {
+ return tspRuntime.getRandomIntegerInclusive(min, max);
+}
+/**
+ * Typeguard for an error object shape (has name and message)
+ *
+ * @param e - Something caught by a catch clause.
+ */
+function esm_isError(e) {
+ return isError(e);
+}
+/**
+ * Helper to determine when an input is a generic JS object.
+ *
+ * @returns true when input is an object type that is not null, Array, RegExp, or Date.
+ */
+function esm_isObject(input) {
+ return tspRuntime.isObject(input);
+}
+/**
+ * Generated Universally Unique Identifier
+ *
+ * @returns RFC4122 v4 UUID.
+ */
+function esm_randomUUID() {
+ return randomUUID();
+}
+/**
+ * A constant that indicates whether the environment the code is running is a Web Browser.
+ */
+const esm_isBrowser = isBrowser;
+/**
+ * A constant that indicates whether the environment the code is running is Bun.sh.
+ */
+const esm_isBun = isBun;
+/**
+ * A constant that indicates whether the environment the code is running is Deno.
+ */
+const esm_isDeno = isDeno;
+/**
+ * A constant that indicates whether the environment the code is running is a Node.js compatible environment.
+ *
+ * @deprecated
+ *
+ * Use `isNodeLike` instead.
+ */
+const isNode = env_isNodeLike;
+/**
+ * A constant that indicates whether the environment the code is running is a Node.js compatible environment.
+ */
+const esm_isNodeLike = env_isNodeLike;
+/**
+ * A constant that indicates whether the environment the code is running is Node.JS.
+ */
+const esm_isNodeRuntime = isNodeRuntime;
+/**
+ * A constant that indicates whether the environment the code is running is in React-Native.
+ */
+const esm_isReactNative = isReactNative;
+/**
+ * A constant that indicates whether the environment the code is running is a Web Worker.
+ */
+const esm_isWebWorker = isWebWorker;
+/**
+ * The helper that transforms bytes with specific character encoding into string
+ * @param bytes - the uint8array bytes
+ * @param format - the format we use to encode the byte
+ * @returns a string of the encoded string
+ */
+function esm_uint8ArrayToString(bytes, format) {
+ return bytesEncoding_uint8ArrayToString(bytes, format);
+}
+/**
+ * The helper that transforms string to specific character encoded bytes array.
+ * @param value - the string to be converted
+ * @param format - the format we use to decode the value
+ * @returns a uint8array
+ */
+function esm_stringToUint8Array(value, format) {
+ return bytesEncoding_stringToUint8Array(value, format);
+}
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/proxyPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * The programmatic identifier of the proxyPolicy.
+ */
+const proxyPolicy_proxyPolicyName = (/* unused pure expression or super */ null && (tspProxyPolicyName));
+/**
+ * This method converts a proxy url into `ProxySettings` for use with ProxyPolicy.
+ * If no argument is given, it attempts to parse a proxy URL from the environment
+ * variables `HTTPS_PROXY` or `HTTP_PROXY`.
+ * @param proxyUrl - The url of the proxy to use. May contain authentication information.
+ * @deprecated - Internally this method is no longer necessary when setting proxy information.
+ */
+function proxyPolicy_getDefaultProxySettings(proxyUrl) {
+ return getDefaultProxySettings(proxyUrl);
+}
+/**
+ * A policy that allows one to apply proxy settings to all requests.
+ * If not passed static settings, they will be retrieved from the HTTPS_PROXY
+ * or HTTP_PROXY environment variables.
+ * @param proxySettings - ProxySettings to use on each request.
+ * @param options - additional settings, for example, custom NO_PROXY patterns
+ */
+function policies_proxyPolicy_proxyPolicy(proxySettings, options) {
+ return proxyPolicy_proxyPolicy(proxySettings, options);
+}
+//# sourceMappingURL=proxyPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/setClientRequestIdPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * The programmatic identifier of the setClientRequestIdPolicy.
+ */
+const setClientRequestIdPolicyName = "setClientRequestIdPolicy";
+/**
+ * Each PipelineRequest gets a unique id upon creation.
+ * This policy passes that unique id along via an HTTP header to enable better
+ * telemetry and tracing.
+ * @param requestIdHeaderName - The name of the header to pass the request ID to.
+ */
+function setClientRequestIdPolicy(requestIdHeaderName = "x-ms-client-request-id") {
+ return {
+ name: setClientRequestIdPolicyName,
+ async sendRequest(request, next) {
+ if (!request.headers.has(requestIdHeaderName)) {
+ request.headers.set(requestIdHeaderName, request.requestId);
+ }
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=setClientRequestIdPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/agentPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the Agent Policy
+ */
+const agentPolicy_agentPolicyName = (/* unused pure expression or super */ null && (tspAgentPolicyName));
+/**
+ * Gets a pipeline policy that sets http.agent
+ */
+function policies_agentPolicy_agentPolicy(agent) {
+ return agentPolicy_agentPolicy(agent);
+}
+//# sourceMappingURL=agentPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/tlsPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the TLS Policy
+ */
+const tlsPolicy_tlsPolicyName = (/* unused pure expression or super */ null && (tspTlsPolicyName));
+/**
+ * Gets a pipeline policy that adds the client certificate to the HttpClient agent for authentication.
+ */
+function policies_tlsPolicy_tlsPolicy(tlsSettings) {
+ return tlsPolicy_tlsPolicy(tlsSettings);
+}
+//# sourceMappingURL=tlsPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-tracing/dist/esm/tracingContext.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/** @internal */
+const knownContextKeys = {
+ span: Symbol.for("@azure/core-tracing span"),
+ namespace: Symbol.for("@azure/core-tracing namespace"),
+};
+/**
+ * Creates a new {@link TracingContext} with the given options.
+ * @param options - A set of known keys that may be set on the context.
+ * @returns A new {@link TracingContext} with the given options.
+ *
+ * @internal
+ */
+function createTracingContext(options = {}) {
+ let context = new TracingContextImpl(options.parentContext);
+ if (options.span) {
+ context = context.setValue(knownContextKeys.span, options.span);
+ }
+ if (options.namespace) {
+ context = context.setValue(knownContextKeys.namespace, options.namespace);
+ }
+ return context;
+}
+/** @internal */
+class TracingContextImpl {
+ _contextMap;
+ constructor(initialContext) {
+ this._contextMap =
+ initialContext instanceof TracingContextImpl
+ ? new Map(initialContext._contextMap)
+ : new Map();
+ }
+ setValue(key, value) {
+ const newContext = new TracingContextImpl(this);
+ newContext._contextMap.set(key, value);
+ return newContext;
+ }
+ getValue(key) {
+ return this._contextMap.get(key);
+ }
+ deleteValue(key) {
+ const newContext = new TracingContextImpl(this);
+ newContext._contextMap.delete(key);
+ return newContext;
+ }
+}
+//# sourceMappingURL=tracingContext.js.map
+// EXTERNAL MODULE: ./node_modules/@azure/core-tracing/dist/commonjs/state-cjs.js
+var state_cjs = __webpack_require__(9437);
+;// CONCATENATED MODULE: ./node_modules/@azure/core-tracing/dist/esm/state.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// @ts-expect-error The recommended approach to sharing module state between ESM and CJS.
+// See https://github.com/isaacs/tshy/blob/main/README.md#module-local-state for additional information.
+
+/**
+ * Defines the shared state between CJS and ESM by re-exporting the CJS state.
+ */
+const state_state = state_cjs/* state */.w;
+//# sourceMappingURL=state.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-tracing/dist/esm/instrumenter.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+function createDefaultTracingSpan() {
+ return {
+ end: () => {
+ // noop
+ },
+ isRecording: () => false,
+ recordException: () => {
+ // noop
+ },
+ setAttribute: () => {
+ // noop
+ },
+ setStatus: () => {
+ // noop
+ },
+ addEvent: () => {
+ // noop
+ },
+ };
+}
+function createDefaultInstrumenter() {
+ return {
+ createRequestHeaders: () => {
+ return {};
+ },
+ parseTraceparentHeader: () => {
+ return undefined;
+ },
+ startSpan: (_name, spanOptions) => {
+ return {
+ span: createDefaultTracingSpan(),
+ tracingContext: createTracingContext({ parentContext: spanOptions.tracingContext }),
+ };
+ },
+ withContext(_context, callback, ...callbackArgs) {
+ return callback(...callbackArgs);
+ },
+ };
+}
+/**
+ * Extends the Azure SDK with support for a given instrumenter implementation.
+ *
+ * @param instrumenter - The instrumenter implementation to use.
+ */
+function useInstrumenter(instrumenter) {
+ state.instrumenterImplementation = instrumenter;
+}
+/**
+ * Gets the currently set instrumenter, a No-Op instrumenter by default.
+ *
+ * @returns The currently set instrumenter
+ */
+function getInstrumenter() {
+ if (!state_state.instrumenterImplementation) {
+ state_state.instrumenterImplementation = createDefaultInstrumenter();
+ }
+ return state_state.instrumenterImplementation;
+}
+//# sourceMappingURL=instrumenter.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-tracing/dist/esm/tracingClient.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * Creates a new tracing client.
+ *
+ * @param options - Options used to configure the tracing client.
+ * @returns - An instance of {@link TracingClient}.
+ */
+function createTracingClient(options) {
+ const { namespace, packageName, packageVersion } = options;
+ function startSpan(name, operationOptions, spanOptions) {
+ const startSpanResult = getInstrumenter().startSpan(name, {
+ ...spanOptions,
+ packageName,
+ packageVersion,
+ tracingContext: operationOptions?.tracingOptions?.tracingContext,
+ });
+ let tracingContext = startSpanResult.tracingContext;
+ const span = startSpanResult.span;
+ if (!tracingContext.getValue(knownContextKeys.namespace)) {
+ tracingContext = tracingContext.setValue(knownContextKeys.namespace, namespace);
+ }
+ span.setAttribute("az.namespace", tracingContext.getValue(knownContextKeys.namespace));
+ const updatedOptions = Object.assign({}, operationOptions, {
+ tracingOptions: { ...operationOptions?.tracingOptions, tracingContext },
+ });
+ return {
+ span,
+ updatedOptions,
+ };
+ }
+ async function withSpan(name, operationOptions, callback, spanOptions) {
+ const { span, updatedOptions } = startSpan(name, operationOptions, spanOptions);
+ try {
+ const result = await withContext(updatedOptions.tracingOptions.tracingContext, () => callback(updatedOptions, span));
+ span.setStatus({ status: "success" });
+ return result;
+ }
+ catch (err) {
+ span.setStatus({ status: "error", error: err });
+ throw err;
+ }
+ finally {
+ span.end();
+ }
+ }
+ function withContext(context, callback, ...callbackArgs) {
+ return getInstrumenter().withContext(context, callback, ...callbackArgs);
+ }
+ /**
+ * Parses a traceparent header value into a span identifier.
+ *
+ * @param traceparentHeader - The traceparent header to parse.
+ * @returns An implementation-specific identifier for the span.
+ */
+ function parseTraceparentHeader(traceparentHeader) {
+ return getInstrumenter().parseTraceparentHeader(traceparentHeader);
+ }
+ /**
+ * Creates a set of request headers to propagate tracing information to a backend.
+ *
+ * @param tracingContext - The context containing the span to serialize.
+ * @returns The set of headers to add to a request.
+ */
+ function createRequestHeaders(tracingContext) {
+ return getInstrumenter().createRequestHeaders(tracingContext);
+ }
+ return {
+ startSpan,
+ withSpan,
+ withContext,
+ parseTraceparentHeader,
+ createRequestHeaders,
+ };
+}
+//# sourceMappingURL=tracingClient.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-tracing/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/restError.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * A custom error type for failed pipeline requests.
+ */
+// eslint-disable-next-line @typescript-eslint/no-redeclare
+const esm_restError_RestError = restError_RestError;
+/**
+ * Typeguard for RestError
+ * @param e - Something caught by a catch clause.
+ */
+function esm_restError_isRestError(e) {
+ return restError_isRestError(e);
+}
+//# sourceMappingURL=restError.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/tracingPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+/**
+ * The programmatic identifier of the tracingPolicy.
+ */
+const tracingPolicyName = "tracingPolicy";
+/**
+ * A simple policy to create OpenTelemetry Spans for each request made by the pipeline
+ * that has SpanOptions with a parent.
+ * Requests made without a parent Span will not be recorded.
+ * @param options - Options to configure the telemetry logged by the tracing policy.
+ */
+function tracingPolicy(options = {}) {
+ const userAgentPromise = util_userAgent_getUserAgentValue(options.userAgentPrefix);
+ const sanitizer = new Sanitizer({
+ additionalAllowedQueryParameters: options.additionalAllowedQueryParameters,
+ });
+ const tracingClient = tryCreateTracingClient();
+ return {
+ name: tracingPolicyName,
+ async sendRequest(request, next) {
+ if (!tracingClient) {
+ return next(request);
+ }
+ const userAgent = await userAgentPromise;
+ const spanAttributes = {
+ "http.url": sanitizer.sanitizeUrl(request.url),
+ "http.method": request.method,
+ "http.user_agent": userAgent,
+ requestId: request.requestId,
+ };
+ if (userAgent) {
+ spanAttributes["http.user_agent"] = userAgent;
+ }
+ const { span, tracingContext } = tryCreateSpan(tracingClient, request, spanAttributes) ?? {};
+ if (!span || !tracingContext) {
+ return next(request);
+ }
+ try {
+ const response = await tracingClient.withContext(tracingContext, next, request);
+ tryProcessResponse(span, response);
+ return response;
+ }
+ catch (err) {
+ tryProcessError(span, err);
+ throw err;
+ }
+ },
+ };
+}
+function tryCreateTracingClient() {
+ try {
+ return createTracingClient({
+ namespace: "",
+ packageName: "@azure/core-rest-pipeline",
+ packageVersion: esm_constants_SDK_VERSION,
+ });
+ }
+ catch (e) {
+ esm_log_logger.warning(`Error when creating the TracingClient: ${getErrorMessage(e)}`);
+ return undefined;
+ }
+}
+function tryCreateSpan(tracingClient, request, spanAttributes) {
+ try {
+ // As per spec, we do not need to differentiate between HTTP and HTTPS in span name.
+ const { span, updatedOptions } = tracingClient.startSpan(`HTTP ${request.method}`, { tracingOptions: request.tracingOptions }, {
+ spanKind: "client",
+ spanAttributes,
+ });
+ // If the span is not recording, don't do any more work.
+ if (!span.isRecording()) {
+ span.end();
+ return undefined;
+ }
+ // set headers
+ const headers = tracingClient.createRequestHeaders(updatedOptions.tracingOptions.tracingContext);
+ for (const [key, value] of Object.entries(headers)) {
+ request.headers.set(key, value);
+ }
+ return { span, tracingContext: updatedOptions.tracingOptions.tracingContext };
+ }
+ catch (e) {
+ esm_log_logger.warning(`Skipping creating a tracing span due to an error: ${getErrorMessage(e)}`);
+ return undefined;
+ }
+}
+function tryProcessError(span, error) {
+ try {
+ span.setStatus({
+ status: "error",
+ error: esm_isError(error) ? error : undefined,
+ });
+ if (esm_restError_isRestError(error) && error.statusCode) {
+ span.setAttribute("http.status_code", error.statusCode);
+ }
+ span.end();
+ }
+ catch (e) {
+ esm_log_logger.warning(`Skipping tracing span processing due to an error: ${getErrorMessage(e)}`);
+ }
+}
+function tryProcessResponse(span, response) {
+ try {
+ span.setAttribute("http.status_code", response.status);
+ const serviceRequestId = response.headers.get("x-ms-request-id");
+ if (serviceRequestId) {
+ span.setAttribute("serviceRequestId", serviceRequestId);
+ }
+ // Per semantic conventions, only set the status to error if the status code is 4xx or 5xx.
+ // Otherwise, the status MUST remain unset.
+ // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+ if (response.status >= 400) {
+ span.setStatus({
+ status: "error",
+ });
+ }
+ span.end();
+ }
+ catch (e) {
+ esm_log_logger.warning(`Skipping tracing span processing due to an error: ${getErrorMessage(e)}`);
+ }
+}
+//# sourceMappingURL=tracingPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/util/wrapAbortSignal.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Creates a native AbortSignal which reflects the state of the provided AbortSignalLike.
+ * If the AbortSignalLike is already a native AbortSignal, it is returned as is.
+ * @param abortSignalLike - The AbortSignalLike to wrap.
+ * @returns - An object containing the native AbortSignal and an optional cleanup function. The cleanup function should be called when the AbortSignal is no longer needed.
+ */
+function wrapAbortSignalLike(abortSignalLike) {
+ if (abortSignalLike instanceof AbortSignal) {
+ return { abortSignal: abortSignalLike };
+ }
+ if (abortSignalLike.aborted) {
+ return {
+ abortSignal: AbortSignal.abort("reason" in abortSignalLike ? abortSignalLike.reason : undefined),
+ };
+ }
+ const controller = new AbortController();
+ let needsCleanup = true;
+ function cleanup() {
+ if (needsCleanup) {
+ abortSignalLike.removeEventListener("abort", listener);
+ needsCleanup = false;
+ }
+ }
+ function listener() {
+ controller.abort("reason" in abortSignalLike ? abortSignalLike.reason : undefined);
+ cleanup();
+ }
+ abortSignalLike.addEventListener("abort", listener);
+ return { abortSignal: controller.signal, cleanup };
+}
+//# sourceMappingURL=wrapAbortSignal.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/wrapAbortSignalLikePolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const wrapAbortSignalLikePolicyName = "wrapAbortSignalLikePolicy";
+/**
+ * Policy that ensure that any AbortSignalLike is wrapped in a native AbortSignal for processing by the pipeline.
+ * Since the ts-http-runtime expects a native AbortSignal, this policy is used to ensure that any AbortSignalLike is wrapped in a native AbortSignal.
+ *
+ * @returns - created policy
+ */
+function wrapAbortSignalLikePolicy() {
+ return {
+ name: wrapAbortSignalLikePolicyName,
+ sendRequest: async (request, next) => {
+ if (!request.abortSignal) {
+ return next(request);
+ }
+ const { abortSignal, cleanup } = wrapAbortSignalLike(request.abortSignal);
+ request.abortSignal = abortSignal;
+ try {
+ return await next(request);
+ }
+ finally {
+ cleanup?.();
+ }
+ },
+ };
+}
+//# sourceMappingURL=wrapAbortSignalLikePolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/createPipelineFromOptions.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * Create a new pipeline with a default set of customizable policies.
+ * @param options - Options to configure a custom pipeline.
+ */
+function esm_createPipelineFromOptions_createPipelineFromOptions(options) {
+ const pipeline = esm_pipeline_createEmptyPipeline();
+ if (esm_isNodeLike) {
+ if (options.agent) {
+ pipeline.addPolicy(policies_agentPolicy_agentPolicy(options.agent));
+ }
+ if (options.tlsOptions) {
+ pipeline.addPolicy(policies_tlsPolicy_tlsPolicy(options.tlsOptions));
+ }
+ pipeline.addPolicy(policies_proxyPolicy_proxyPolicy(options.proxyOptions));
+ pipeline.addPolicy(policies_decompressResponsePolicy_decompressResponsePolicy());
+ }
+ pipeline.addPolicy(wrapAbortSignalLikePolicy());
+ pipeline.addPolicy(policies_formDataPolicy_formDataPolicy(), { beforePolicies: [policies_multipartPolicy_multipartPolicyName] });
+ pipeline.addPolicy(policies_userAgentPolicy_userAgentPolicy(options.userAgentOptions));
+ pipeline.addPolicy(setClientRequestIdPolicy(options.telemetryOptions?.clientRequestIdHeaderName));
+ // The multipart policy is added after policies with no phase, so that
+ // policies can be added between it and formDataPolicy to modify
+ // properties (e.g., making the boundary constant in recorded tests).
+ pipeline.addPolicy(policies_multipartPolicy_multipartPolicy(), { afterPhase: "Deserialize" });
+ pipeline.addPolicy(policies_defaultRetryPolicy_defaultRetryPolicy(options.retryOptions), { phase: "Retry" });
+ pipeline.addPolicy(tracingPolicy({ ...options.userAgentOptions, ...options.loggingOptions }), {
+ afterPhase: "Retry",
+ });
+ if (esm_isNodeLike) {
+ // Both XHR and Fetch expect to handle redirects automatically,
+ // so only include this policy when we're in Node.
+ pipeline.addPolicy(policies_redirectPolicy_redirectPolicy(options.redirectOptions), { afterPhase: "Retry" });
+ }
+ pipeline.addPolicy(policies_logPolicy_logPolicy(options.loggingOptions), { afterPhase: "Sign" });
+ return pipeline;
+}
+//# sourceMappingURL=createPipelineFromOptions.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/defaultHttpClient.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * Create the correct HttpClient for the current environment.
+ */
+function esm_defaultHttpClient_createDefaultHttpClient() {
+ const client = defaultHttpClient_createDefaultHttpClient();
+ return {
+ async sendRequest(request) {
+ // we wrap any AbortSignalLike here since the TypeSpec runtime expects a native AbortSignal.
+ // 99% of the time, this should be a no-op since a native AbortSignal is passed in.
+ const { abortSignal, cleanup } = request.abortSignal
+ ? wrapAbortSignalLike(request.abortSignal)
+ : {};
+ try {
+ request.abortSignal = abortSignal;
+ return await client.sendRequest(request);
+ }
+ finally {
+ cleanup?.();
+ }
+ },
+ };
+}
+//# sourceMappingURL=defaultHttpClient.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/httpHeaders.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Creates an object that satisfies the `HttpHeaders` interface.
+ * @param rawHeaders - A simple object representing initial headers
+ */
+function esm_httpHeaders_createHttpHeaders(rawHeaders) {
+ return httpHeaders_createHttpHeaders(rawHeaders);
+}
+//# sourceMappingURL=httpHeaders.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/pipelineRequest.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Creates a new pipeline request with the given options.
+ * This method is to allow for the easy setting of default values and not required.
+ * @param options - The options to create the request with.
+ */
+function esm_pipelineRequest_createPipelineRequest(options) {
+ // Cast required due to difference between ts-http-runtime requiring AbortSignal while core-rest-pipeline allows
+ // the more generic AbortSignalLike. The wrapAbortSignalLike pipeline policy will take care of ensuring that any AbortSignalLike in the request
+ // is converted into a true AbortSignal.
+ return pipelineRequest_createPipelineRequest(options);
+}
+//# sourceMappingURL=pipelineRequest.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/exponentialRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * The programmatic identifier of the exponentialRetryPolicy.
+ */
+const exponentialRetryPolicy_exponentialRetryPolicyName = (/* unused pure expression or super */ null && (tspExponentialRetryPolicyName));
+/**
+ * A policy that attempts to retry requests while introducing an exponentially increasing delay.
+ * @param options - Options that configure retry logic.
+ */
+function exponentialRetryPolicy_exponentialRetryPolicy(options = {}) {
+ return tspExponentialRetryPolicy(options);
+}
+//# sourceMappingURL=exponentialRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/systemErrorRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the {@link systemErrorRetryPolicy}
+ */
+const systemErrorRetryPolicy_systemErrorRetryPolicyName = (/* unused pure expression or super */ null && (tspSystemErrorRetryPolicyName));
+/**
+ * A retry policy that specifically seeks to handle errors in the
+ * underlying transport layer (e.g. DNS lookup failures) rather than
+ * retryable error codes from the server itself.
+ * @param options - Options that customize the policy.
+ */
+function systemErrorRetryPolicy_systemErrorRetryPolicy(options = {}) {
+ return tspSystemErrorRetryPolicy(options);
+}
+//# sourceMappingURL=systemErrorRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/throttlingRetryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Name of the {@link throttlingRetryPolicy}
+ */
+const throttlingRetryPolicy_throttlingRetryPolicyName = (/* unused pure expression or super */ null && (tspThrottlingRetryPolicyName));
+/**
+ * A policy that retries when the server sends a 429 response with a Retry-After header.
+ *
+ * To learn more, please refer to
+ * https://learn.microsoft.com/azure/azure-resource-manager/resource-manager-request-limits,
+ * https://learn.microsoft.com/azure/azure-subscription-service-limits and
+ * https://learn.microsoft.com/azure/virtual-machines/troubleshooting/troubleshooting-throttling-errors
+ *
+ * @param options - Options that configure retry logic.
+ */
+function throttlingRetryPolicy_throttlingRetryPolicy(options = {}) {
+ return tspThrottlingRetryPolicy(options);
+}
+//# sourceMappingURL=throttlingRetryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/retryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+const retryPolicy_retryPolicyLogger = esm_createClientLogger("core-rest-pipeline retryPolicy");
+/**
+ * retryPolicy is a generic policy to enable retrying requests when certain conditions are met
+ */
+function policies_retryPolicy_retryPolicy(strategies, options = { maxRetries: DEFAULT_RETRY_POLICY_COUNT }) {
+ // Cast is required since the TSP runtime retry strategy type is slightly different
+ // very deep down (using real AbortSignal vs. AbortSignalLike in RestError).
+ // In practice the difference doesn't actually matter.
+ return tspRetryPolicy(strategies, {
+ logger: retryPolicy_retryPolicyLogger,
+ ...options,
+ });
+}
+//# sourceMappingURL=retryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/util/tokenCycler.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// Default options for the cycler if none are provided
+const DEFAULT_CYCLER_OPTIONS = {
+ forcedRefreshWindowInMs: 1000, // Force waiting for a refresh 1s before the token expires
+ retryIntervalInMs: 3000, // Allow refresh attempts every 3s
+ refreshWindowInMs: 1000 * 60 * 2, // Start refreshing 2m before expiry
+};
+/**
+ * Converts an an unreliable access token getter (which may resolve with null)
+ * into an AccessTokenGetter by retrying the unreliable getter in a regular
+ * interval.
+ *
+ * @param getAccessToken - A function that produces a promise of an access token that may fail by returning null.
+ * @param retryIntervalInMs - The time (in milliseconds) to wait between retry attempts.
+ * @param refreshTimeout - The timestamp after which the refresh attempt will fail, throwing an exception.
+ * @returns - A promise that, if it resolves, will resolve with an access token.
+ */
+async function beginRefresh(getAccessToken, retryIntervalInMs, refreshTimeout) {
+ // This wrapper handles exceptions gracefully as long as we haven't exceeded
+ // the timeout.
+ async function tryGetAccessToken() {
+ if (Date.now() < refreshTimeout) {
+ try {
+ return await getAccessToken();
+ }
+ catch {
+ return null;
+ }
+ }
+ else {
+ const finalToken = await getAccessToken();
+ // Timeout is up, so throw if it's still null
+ if (finalToken === null) {
+ throw new Error("Failed to refresh access token.");
+ }
+ return finalToken;
+ }
+ }
+ let token = await tryGetAccessToken();
+ while (token === null) {
+ await delay_delay(retryIntervalInMs);
+ token = await tryGetAccessToken();
+ }
+ return token;
+}
+/**
+ * Creates a token cycler from a credential, scopes, and optional settings.
+ *
+ * A token cycler represents a way to reliably retrieve a valid access token
+ * from a TokenCredential. It will handle initializing the token, refreshing it
+ * when it nears expiration, and synchronizes refresh attempts to avoid
+ * concurrency hazards.
+ *
+ * @param credential - the underlying TokenCredential that provides the access
+ * token
+ * @param tokenCyclerOptions - optionally override default settings for the cycler
+ *
+ * @returns - a function that reliably produces a valid access token
+ */
+function tokenCycler_createTokenCycler(credential, tokenCyclerOptions) {
+ let refreshWorker = null;
+ let token = null;
+ let tenantId;
+ const options = {
+ ...DEFAULT_CYCLER_OPTIONS,
+ ...tokenCyclerOptions,
+ };
+ /**
+ * This little holder defines several predicates that we use to construct
+ * the rules of refreshing the token.
+ */
+ const cycler = {
+ /**
+ * Produces true if a refresh job is currently in progress.
+ */
+ get isRefreshing() {
+ return refreshWorker !== null;
+ },
+ /**
+ * Produces true if the cycler SHOULD refresh (we are within the refresh
+ * window and not already refreshing)
+ */
+ get shouldRefresh() {
+ if (token === null) {
+ return true;
+ }
+ if (cycler.isRefreshing) {
+ return false;
+ }
+ if (token.refreshAfterTimestamp && token.refreshAfterTimestamp < Date.now()) {
+ return true;
+ }
+ return token.expiresOnTimestamp - options.refreshWindowInMs < Date.now();
+ },
+ /**
+ * Produces true if the cycler MUST refresh (null or nearly-expired
+ * token).
+ */
+ get mustRefresh() {
+ return (token === null || token.expiresOnTimestamp - options.forcedRefreshWindowInMs < Date.now());
+ },
+ };
+ /**
+ * Starts a refresh job or returns the existing job if one is already
+ * running.
+ */
+ function refresh(scopes, getTokenOptions) {
+ if (!cycler.isRefreshing) {
+ // We bind `scopes` here to avoid passing it around a lot
+ const tryGetAccessToken = () => credential.getToken(scopes, getTokenOptions);
+ // Take advantage of promise chaining to insert an assignment to `token`
+ // before the refresh can be considered done.
+ refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs,
+ // If we don't have a token, then we should timeout immediately
+ token?.expiresOnTimestamp ?? Date.now())
+ .then((_token) => {
+ refreshWorker = null;
+ token = _token;
+ tenantId = getTokenOptions.tenantId;
+ return token;
+ })
+ .catch((reason) => {
+ // We also should reset the refresher if we enter a failed state. All
+ // existing awaiters will throw, but subsequent requests will start a
+ // new retry chain.
+ refreshWorker = null;
+ token = null;
+ tenantId = undefined;
+ throw reason;
+ });
+ }
+ return refreshWorker;
+ }
+ return async (scopes, tokenOptions) => {
+ //
+ // Simple rules:
+ // - If we MUST refresh, then return the refresh task, blocking
+ // the pipeline until a token is available.
+ // - If we SHOULD refresh, then run refresh but don't return it
+ // (we can still use the cached token).
+ // - Return the token, since it's fine if we didn't return in
+ // step 1.
+ //
+ const hasClaimChallenge = Boolean(tokenOptions.claims);
+ const tenantIdChanged = tenantId !== tokenOptions.tenantId;
+ if (hasClaimChallenge) {
+ // If we've received a claim, we know the existing token isn't valid
+ // We want to clear it so that that refresh worker won't use the old expiration time as a timeout
+ token = null;
+ }
+ // If the tenantId passed in token options is different to the one we have
+ // Or if we are in claim challenge and the token was rejected and a new access token need to be issued, we need to
+ // refresh the token with the new tenantId or token.
+ const mustRefresh = tenantIdChanged || hasClaimChallenge || cycler.mustRefresh;
+ if (mustRefresh) {
+ return refresh(scopes, tokenOptions);
+ }
+ if (cycler.shouldRefresh) {
+ refresh(scopes, tokenOptions);
+ }
+ return token;
+ };
+}
+//# sourceMappingURL=tokenCycler.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/bearerTokenAuthenticationPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+/**
+ * The programmatic identifier of the bearerTokenAuthenticationPolicy.
+ */
+const bearerTokenAuthenticationPolicyName = "bearerTokenAuthenticationPolicy";
+/**
+ * Try to send the given request.
+ *
+ * When a response is received, returns a tuple of the response received and, if the response was received
+ * inside a thrown RestError, the RestError that was thrown.
+ *
+ * Otherwise, if an error was thrown while sending the request that did not provide an underlying response, it
+ * will be rethrown.
+ */
+async function trySendRequest(request, next) {
+ try {
+ return [await next(request), undefined];
+ }
+ catch (e) {
+ if (esm_restError_isRestError(e) && e.response) {
+ return [e.response, e];
+ }
+ else {
+ throw e;
+ }
+ }
+}
+/**
+ * Default authorize request handler
+ */
+async function defaultAuthorizeRequest(options) {
+ const { scopes, getAccessToken, request } = options;
+ // Enable CAE true by default
+ const getTokenOptions = {
+ abortSignal: request.abortSignal,
+ tracingOptions: request.tracingOptions,
+ enableCae: true,
+ };
+ const accessToken = await getAccessToken(scopes, getTokenOptions);
+ if (accessToken) {
+ options.request.headers.set("Authorization", `Bearer ${accessToken.token}`);
+ }
+}
+/**
+ * We will retrieve the challenge only if the response status code was 401,
+ * and if the response contained the header "WWW-Authenticate" with a non-empty value.
+ */
+function isChallengeResponse(response) {
+ return response.status === 401 && response.headers.has("WWW-Authenticate");
+}
+/**
+ * Re-authorize the request for CAE challenge.
+ * The response containing the challenge is `options.response`.
+ * If this method returns true, the underlying request will be sent once again.
+ */
+async function authorizeRequestOnCaeChallenge(onChallengeOptions, caeClaims) {
+ const { scopes } = onChallengeOptions;
+ const accessToken = await onChallengeOptions.getAccessToken(scopes, {
+ enableCae: true,
+ claims: caeClaims,
+ });
+ if (!accessToken) {
+ return false;
+ }
+ onChallengeOptions.request.headers.set("Authorization", `${accessToken.tokenType ?? "Bearer"} ${accessToken.token}`);
+ return true;
+}
+/**
+ * A policy that can request a token from a TokenCredential implementation and
+ * then apply it to the Authorization header of a request as a Bearer token.
+ */
+function bearerTokenAuthenticationPolicy(options) {
+ const { credential, scopes, challengeCallbacks } = options;
+ const logger = options.logger || esm_log_logger;
+ const callbacks = {
+ authorizeRequest: challengeCallbacks?.authorizeRequest?.bind(challengeCallbacks) ?? defaultAuthorizeRequest,
+ authorizeRequestOnChallenge: challengeCallbacks?.authorizeRequestOnChallenge?.bind(challengeCallbacks),
+ };
+ // This function encapsulates the entire process of reliably retrieving the token
+ // The options are left out of the public API until there's demand to configure this.
+ // Remember to extend `BearerTokenAuthenticationPolicyOptions` with `TokenCyclerOptions`
+ // in order to pass through the `options` object.
+ const getAccessToken = credential
+ ? tokenCycler_createTokenCycler(credential /* , options */)
+ : () => Promise.resolve(null);
+ return {
+ name: bearerTokenAuthenticationPolicyName,
+ /**
+ * If there's no challenge parameter:
+ * - It will try to retrieve the token using the cache, or the credential's getToken.
+ * - Then it will try the next policy with or without the retrieved token.
+ *
+ * It uses the challenge parameters to:
+ * - Skip a first attempt to get the token from the credential if there's no cached token,
+ * since it expects the token to be retrievable only after the challenge.
+ * - Prepare the outgoing request if the `prepareRequest` method has been provided.
+ * - Send an initial request to receive the challenge if it fails.
+ * - Process a challenge if the response contains it.
+ * - Retrieve a token with the challenge information, then re-send the request.
+ */
+ async sendRequest(request, next) {
+ if (!request.url.toLowerCase().startsWith("https://")) {
+ throw new Error("Bearer token authentication is not permitted for non-TLS protected (non-https) URLs.");
+ }
+ await callbacks.authorizeRequest({
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
+ request,
+ getAccessToken,
+ logger,
+ });
+ let response;
+ let error;
+ let shouldSendRequest;
+ [response, error] = await trySendRequest(request, next);
+ if (isChallengeResponse(response)) {
+ let claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate"));
+ // Handle CAE by default when receive CAE claim
+ if (claims) {
+ let parsedClaim;
+ // Return the response immediately if claims is not a valid base64 encoded string
+ try {
+ parsedClaim = atob(claims);
+ }
+ catch (e) {
+ logger.warning(`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`);
+ return response;
+ }
+ shouldSendRequest = await authorizeRequestOnCaeChallenge({
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
+ response,
+ request,
+ getAccessToken,
+ logger,
+ }, parsedClaim);
+ // Send updated request and handle response for RestError
+ if (shouldSendRequest) {
+ [response, error] = await trySendRequest(request, next);
+ }
+ }
+ else if (callbacks.authorizeRequestOnChallenge) {
+ // Handle custom challenges when client provides custom callback
+ shouldSendRequest = await callbacks.authorizeRequestOnChallenge({
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
+ request,
+ response,
+ getAccessToken,
+ logger,
+ });
+ // Send updated request and handle response for RestError
+ if (shouldSendRequest) {
+ [response, error] = await trySendRequest(request, next);
+ }
+ // If we get another CAE Claim, we will handle it by default and return whatever value we receive for this
+ if (isChallengeResponse(response)) {
+ claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate") ?? "");
+ if (claims) {
+ let parsedClaim;
+ try {
+ parsedClaim = atob(claims);
+ }
+ catch (e) {
+ logger.warning(`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`);
+ return response;
+ }
+ shouldSendRequest = await authorizeRequestOnCaeChallenge({
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
+ response,
+ request,
+ getAccessToken,
+ logger,
+ }, parsedClaim);
+ // Send updated request and handle response for RestError
+ if (shouldSendRequest) {
+ [response, error] = await trySendRequest(request, next);
+ }
+ }
+ }
+ }
+ }
+ if (error) {
+ throw error;
+ }
+ else {
+ return response;
+ }
+ },
+ };
+}
+/**
+ * Converts: `Bearer a="b", c="d", Pop e="f", g="h"`.
+ * Into: `[ { scheme: 'Bearer', params: { a: 'b', c: 'd' } }, { scheme: 'Pop', params: { e: 'f', g: 'h' } } ]`.
+ *
+ * @internal
+ */
+function parseChallenges(challenges) {
+ // Challenge regex seperates the string to individual challenges with different schemes in the format `Scheme a="b", c=d`
+ // The challenge regex captures parameteres with either quotes values or unquoted values
+ const challengeRegex = /(\w+)\s+((?:\w+=(?:"[^"]*"|[^,]*),?\s*)+)/g;
+ // Parameter regex captures the claims group removed from the scheme in the format `a="b"` and `c="d"`
+ // CAE challenge always have quoted parameters. For more reference, https://learn.microsoft.com/entra/identity-platform/claims-challenge
+ const paramRegex = /(\w+)="([^"]*)"/g;
+ const parsedChallenges = [];
+ let match;
+ // Iterate over each challenge match
+ while ((match = challengeRegex.exec(challenges)) !== null) {
+ const scheme = match[1];
+ const paramsString = match[2];
+ const params = {};
+ let paramMatch;
+ // Iterate over each parameter match
+ while ((paramMatch = paramRegex.exec(paramsString)) !== null) {
+ params[paramMatch[1]] = paramMatch[2];
+ }
+ parsedChallenges.push({ scheme, params });
+ }
+ return parsedChallenges;
+}
+/**
+ * Parse a pipeline response and look for a CAE challenge with "Bearer" scheme
+ * Return the value in the header without parsing the challenge
+ * @internal
+ */
+function getCaeChallengeClaims(challenges) {
+ if (!challenges) {
+ return;
+ }
+ // Find all challenges present in the header
+ const parsedChallenges = parseChallenges(challenges);
+ return parsedChallenges.find((x) => x.scheme === "Bearer" && x.params.claims && x.params.error === "insufficient_claims")?.params.claims;
+}
+//# sourceMappingURL=bearerTokenAuthenticationPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/policies/auxiliaryAuthenticationHeaderPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * The programmatic identifier of the auxiliaryAuthenticationHeaderPolicy.
+ */
+const auxiliaryAuthenticationHeaderPolicyName = "auxiliaryAuthenticationHeaderPolicy";
+const AUTHORIZATION_AUXILIARY_HEADER = "x-ms-authorization-auxiliary";
+async function sendAuthorizeRequest(options) {
+ const { scopes, getAccessToken, request } = options;
+ const getTokenOptions = {
+ abortSignal: request.abortSignal,
+ tracingOptions: request.tracingOptions,
+ };
+ return (await getAccessToken(scopes, getTokenOptions))?.token ?? "";
+}
+/**
+ * A policy for external tokens to `x-ms-authorization-auxiliary` header.
+ * This header will be used when creating a cross-tenant application we may need to handle authentication requests
+ * for resources that are in different tenants.
+ * You could see [ARM docs](https://learn.microsoft.com/azure/azure-resource-manager/management/authenticate-multi-tenant) for a rundown of how this feature works
+ */
+function auxiliaryAuthenticationHeaderPolicy(options) {
+ const { credentials, scopes } = options;
+ const logger = options.logger || coreLogger;
+ const tokenCyclerMap = new WeakMap();
+ return {
+ name: auxiliaryAuthenticationHeaderPolicyName,
+ async sendRequest(request, next) {
+ if (!request.url.toLowerCase().startsWith("https://")) {
+ throw new Error("Bearer token authentication for auxiliary header is not permitted for non-TLS protected (non-https) URLs.");
+ }
+ if (!credentials || credentials.length === 0) {
+ logger.info(`${auxiliaryAuthenticationHeaderPolicyName} header will not be set due to empty credentials.`);
+ return next(request);
+ }
+ const tokenPromises = [];
+ for (const credential of credentials) {
+ let getAccessToken = tokenCyclerMap.get(credential);
+ if (!getAccessToken) {
+ getAccessToken = createTokenCycler(credential);
+ tokenCyclerMap.set(credential, getAccessToken);
+ }
+ tokenPromises.push(sendAuthorizeRequest({
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
+ request,
+ getAccessToken,
+ logger,
+ }));
+ }
+ const auxiliaryTokens = (await Promise.all(tokenPromises)).filter((token) => Boolean(token));
+ if (auxiliaryTokens.length === 0) {
+ logger.warning(`None of the auxiliary tokens are valid. ${AUTHORIZATION_AUXILIARY_HEADER} header will not be set.`);
+ return next(request);
+ }
+ request.headers.set(AUTHORIZATION_AUXILIARY_HEADER, auxiliaryTokens.map((token) => `Bearer ${token}`).join(", "));
+ return next(request);
+ },
+ };
+}
+//# sourceMappingURL=auxiliaryAuthenticationHeaderPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-auth/dist/esm/keyCredential.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Tests an object to determine whether it implements KeyCredential.
+ *
+ * @param credential - The assumed KeyCredential to be tested.
+ */
+function isKeyCredential(credential) {
+ return isObjectWithProperties(credential, ["key"]) && typeof credential.key === "string";
+}
+//# sourceMappingURL=keyCredential.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-auth/dist/esm/azureNamedKeyCredential.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * A static name/key-based credential that supports updating
+ * the underlying name and key values.
+ */
+class AzureNamedKeyCredential {
+ _key;
+ _name;
+ /**
+ * The value of the key to be used in authentication.
+ */
+ get key() {
+ return this._key;
+ }
+ /**
+ * The value of the name to be used in authentication.
+ */
+ get name() {
+ return this._name;
+ }
+ /**
+ * Create an instance of an AzureNamedKeyCredential for use
+ * with a service client.
+ *
+ * @param name - The initial value of the name to use in authentication.
+ * @param key - The initial value of the key to use in authentication.
+ */
+ constructor(name, key) {
+ if (!name || !key) {
+ throw new TypeError("name and key must be non-empty strings");
+ }
+ this._name = name;
+ this._key = key;
+ }
+ /**
+ * Change the value of the key.
+ *
+ * Updates will take effect upon the next request after
+ * updating the key value.
+ *
+ * @param newName - The new name value to be used.
+ * @param newKey - The new key value to be used.
+ */
+ update(newName, newKey) {
+ if (!newName || !newKey) {
+ throw new TypeError("newName and newKey must be non-empty strings");
+ }
+ this._name = newName;
+ this._key = newKey;
+ }
+}
+/**
+ * Tests an object to determine whether it implements NamedKeyCredential.
+ *
+ * @param credential - The assumed NamedKeyCredential to be tested.
+ */
+function isNamedKeyCredential(credential) {
+ return (isObjectWithProperties(credential, ["name", "key"]) &&
+ typeof credential.key === "string" &&
+ typeof credential.name === "string");
+}
+//# sourceMappingURL=azureNamedKeyCredential.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-auth/dist/esm/azureSASCredential.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * A static-signature-based credential that supports updating
+ * the underlying signature value.
+ */
+class AzureSASCredential {
+ _signature;
+ /**
+ * The value of the shared access signature to be used in authentication
+ */
+ get signature() {
+ return this._signature;
+ }
+ /**
+ * Create an instance of an AzureSASCredential for use
+ * with a service client.
+ *
+ * @param signature - The initial value of the shared access signature to use in authentication
+ */
+ constructor(signature) {
+ if (!signature) {
+ throw new Error("shared access signature must be a non-empty string");
+ }
+ this._signature = signature;
+ }
+ /**
+ * Change the value of the signature.
+ *
+ * Updates will take effect upon the next request after
+ * updating the signature value.
+ *
+ * @param newSignature - The new shared access signature value to be used
+ */
+ update(newSignature) {
+ if (!newSignature) {
+ throw new Error("shared access signature must be a non-empty string");
+ }
+ this._signature = newSignature;
+ }
+}
+/**
+ * Tests an object to determine whether it implements SASCredential.
+ *
+ * @param credential - The assumed SASCredential to be tested.
+ */
+function isSASCredential(credential) {
+ return (isObjectWithProperties(credential, ["signature"]) && typeof credential.signature === "string");
+}
+//# sourceMappingURL=azureSASCredential.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-auth/dist/esm/tokenCredential.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Tests an object to determine whether it implements TokenCredential.
+ *
+ * @param credential - The assumed TokenCredential to be tested.
+ */
+function isTokenCredential(credential) {
+ // Check for an object with a 'getToken' function and possibly with
+ // a 'signRequest' function. We do this check to make sure that
+ // a ServiceClientCredentials implementor (like TokenClientCredentials
+ // in ms-rest-nodeauth) doesn't get mistaken for a TokenCredential if
+ // it doesn't actually implement TokenCredential also.
+ const castCredential = credential;
+ return (castCredential &&
+ typeof castCredential.getToken === "function" &&
+ (castCredential.signRequest === undefined || castCredential.getToken.length > 0));
+}
+//# sourceMappingURL=tokenCredential.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-auth/dist/esm/index.js
+
+
+
+
+
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-http-compat/dist/esm/policies/disableKeepAlivePolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+const disableKeepAlivePolicyName = "DisableKeepAlivePolicy";
+function createDisableKeepAlivePolicy() {
+ return {
+ name: disableKeepAlivePolicyName,
+ sendRequest(request, next) {
+ request.disableKeepAlive = true;
+ return next(request);
+ },
+ };
+}
+/**
+ * @internal
+ */
+function pipelineContainsDisableKeepAlivePolicy(pipeline) {
+ return pipeline.getOrderedPolicies().some((policy) => policy.name === disableKeepAlivePolicyName);
+}
+//# sourceMappingURL=disableKeepAlivePolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/base64.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Encodes a string in base64 format.
+ * @param value - the string to encode
+ * @internal
+ */
+function encodeString(value) {
+ return uint8ArrayToString(stringToUint8Array(value, "utf-8"), "base64");
+}
+/**
+ * Encodes a byte array in base64 format.
+ * @param value - the Uint8Array to encode
+ * @internal
+ */
+function encodeByteArray(value) {
+ return esm_uint8ArrayToString(value, "base64");
+}
+/**
+ * Decodes a base64 string into a byte array.
+ * @param value - the base64 string to decode
+ * @internal
+ */
+function decodeString(value) {
+ return esm_stringToUint8Array(value, "base64");
+}
+/**
+ * Decodes a base64 string into a string.
+ * @param value - the base64 string to decode
+ * @internal
+ */
+function base64_decodeStringToString(value) {
+ return uint8ArrayToString(stringToUint8Array(value, "base64"), "utf-8");
+}
+//# sourceMappingURL=base64.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/interfaces.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * Default key used to access the XML attributes.
+ */
+const XML_ATTRKEY = "$";
+/**
+ * Default key used to access the XML value content.
+ */
+const XML_CHARKEY = "_";
+//# sourceMappingURL=interfaces.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/utils.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * A type guard for a primitive response body.
+ * @param value - Value to test
+ *
+ * @internal
+ */
+function isPrimitiveBody(value, mapperTypeName) {
+ return (mapperTypeName !== "Composite" &&
+ mapperTypeName !== "Dictionary" &&
+ (typeof value === "string" ||
+ typeof value === "number" ||
+ typeof value === "boolean" ||
+ mapperTypeName?.match(/^(Date|DateTime|DateTimeRfc1123|UnixTime|ByteArray|Base64Url)$/i) !==
+ null ||
+ value === undefined ||
+ value === null));
+}
+const validateISODuration = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
+/**
+ * Returns true if the given string is in ISO 8601 format.
+ * @param value - The value to be validated for ISO 8601 duration format.
+ * @internal
+ */
+function isDuration(value) {
+ return validateISODuration.test(value);
+}
+const validUuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/i;
+/**
+ * Returns true if the provided uuid is valid.
+ *
+ * @param uuid - The uuid that needs to be validated.
+ *
+ * @internal
+ */
+function isValidUuid(uuid) {
+ return validUuidRegex.test(uuid);
+}
+/**
+ * Maps the response as follows:
+ * - wraps the response body if needed (typically if its type is primitive).
+ * - returns null if the combination of the headers and the body is empty.
+ * - otherwise, returns the combination of the headers and the body.
+ *
+ * @param responseObject - a representation of the parsed response
+ * @returns the response that will be returned to the user which can be null and/or wrapped
+ *
+ * @internal
+ */
+function handleNullableResponseAndWrappableBody(responseObject) {
+ const combinedHeadersAndBody = {
+ ...responseObject.headers,
+ ...responseObject.body,
+ };
+ if (responseObject.hasNullableType &&
+ Object.getOwnPropertyNames(combinedHeadersAndBody).length === 0) {
+ return responseObject.shouldWrapBody ? { body: null } : null;
+ }
+ else {
+ return responseObject.shouldWrapBody
+ ? {
+ ...responseObject.headers,
+ body: responseObject.body,
+ }
+ : combinedHeadersAndBody;
+ }
+}
+/**
+ * Take a `FullOperationResponse` and turn it into a flat
+ * response object to hand back to the consumer.
+ * @param fullResponse - The processed response from the operation request
+ * @param responseSpec - The response map from the OperationSpec
+ *
+ * @internal
+ */
+function flattenResponse(fullResponse, responseSpec) {
+ const parsedHeaders = fullResponse.parsedHeaders;
+ // head methods never have a body, but we return a boolean set to body property
+ // to indicate presence/absence of the resource
+ if (fullResponse.request.method === "HEAD") {
+ return {
+ ...parsedHeaders,
+ body: fullResponse.parsedBody,
+ };
+ }
+ const bodyMapper = responseSpec && responseSpec.bodyMapper;
+ const isNullable = Boolean(bodyMapper?.nullable);
+ const expectedBodyTypeName = bodyMapper?.type.name;
+ /** If the body is asked for, we look at the expected body type to handle it */
+ if (expectedBodyTypeName === "Stream") {
+ return {
+ ...parsedHeaders,
+ blobBody: fullResponse.blobBody,
+ readableStreamBody: fullResponse.readableStreamBody,
+ };
+ }
+ const modelProperties = (expectedBodyTypeName === "Composite" &&
+ bodyMapper.type.modelProperties) ||
+ {};
+ const isPageableResponse = Object.keys(modelProperties).some((k) => modelProperties[k].serializedName === "");
+ if (expectedBodyTypeName === "Sequence" || isPageableResponse) {
+ const arrayResponse = fullResponse.parsedBody ?? [];
+ for (const key of Object.keys(modelProperties)) {
+ if (modelProperties[key].serializedName) {
+ arrayResponse[key] = fullResponse.parsedBody?.[key];
+ }
+ }
+ if (parsedHeaders) {
+ for (const key of Object.keys(parsedHeaders)) {
+ arrayResponse[key] = parsedHeaders[key];
+ }
+ }
+ return isNullable &&
+ !fullResponse.parsedBody &&
+ !parsedHeaders &&
+ Object.getOwnPropertyNames(modelProperties).length === 0
+ ? null
+ : arrayResponse;
+ }
+ return handleNullableResponseAndWrappableBody({
+ body: fullResponse.parsedBody,
+ headers: parsedHeaders,
+ hasNullableType: isNullable,
+ shouldWrapBody: isPrimitiveBody(fullResponse.parsedBody, expectedBodyTypeName),
+ });
+}
+//# sourceMappingURL=utils.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/serializer.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+class SerializerImpl {
+ modelMappers;
+ isXML;
+ constructor(modelMappers = {}, isXML = false) {
+ this.modelMappers = modelMappers;
+ this.isXML = isXML;
+ }
+ /**
+ * @deprecated Removing the constraints validation on client side.
+ */
+ validateConstraints(mapper, value, objectName) {
+ const failValidation = (constraintName, constraintValue) => {
+ throw new Error(`"${objectName}" with value "${value}" should satisfy the constraint "${constraintName}": ${constraintValue}.`);
+ };
+ if (mapper.constraints && value !== undefined && value !== null) {
+ const { ExclusiveMaximum, ExclusiveMinimum, InclusiveMaximum, InclusiveMinimum, MaxItems, MaxLength, MinItems, MinLength, MultipleOf, Pattern, UniqueItems, } = mapper.constraints;
+ if (ExclusiveMaximum !== undefined && value >= ExclusiveMaximum) {
+ failValidation("ExclusiveMaximum", ExclusiveMaximum);
+ }
+ if (ExclusiveMinimum !== undefined && value <= ExclusiveMinimum) {
+ failValidation("ExclusiveMinimum", ExclusiveMinimum);
+ }
+ if (InclusiveMaximum !== undefined && value > InclusiveMaximum) {
+ failValidation("InclusiveMaximum", InclusiveMaximum);
+ }
+ if (InclusiveMinimum !== undefined && value < InclusiveMinimum) {
+ failValidation("InclusiveMinimum", InclusiveMinimum);
+ }
+ if (MaxItems !== undefined && value.length > MaxItems) {
+ failValidation("MaxItems", MaxItems);
+ }
+ if (MaxLength !== undefined && value.length > MaxLength) {
+ failValidation("MaxLength", MaxLength);
+ }
+ if (MinItems !== undefined && value.length < MinItems) {
+ failValidation("MinItems", MinItems);
+ }
+ if (MinLength !== undefined && value.length < MinLength) {
+ failValidation("MinLength", MinLength);
+ }
+ if (MultipleOf !== undefined && value % MultipleOf !== 0) {
+ failValidation("MultipleOf", MultipleOf);
+ }
+ if (Pattern) {
+ const pattern = typeof Pattern === "string" ? new RegExp(Pattern) : Pattern;
+ if (typeof value !== "string" || value.match(pattern) === null) {
+ failValidation("Pattern", Pattern);
+ }
+ }
+ if (UniqueItems &&
+ value.some((item, i, ar) => ar.indexOf(item) !== i)) {
+ failValidation("UniqueItems", UniqueItems);
+ }
+ }
+ }
+ /**
+ * Serialize the given object based on its metadata defined in the mapper
+ *
+ * @param mapper - The mapper which defines the metadata of the serializable object
+ *
+ * @param object - A valid Javascript object to be serialized
+ *
+ * @param objectName - Name of the serialized object
+ *
+ * @param options - additional options to serialization
+ *
+ * @returns A valid serialized Javascript object
+ */
+ serialize(mapper, object, objectName, options = { xml: {} }) {
+ const updatedOptions = {
+ xml: {
+ rootName: options.xml.rootName ?? "",
+ includeRoot: options.xml.includeRoot ?? false,
+ xmlCharKey: options.xml.xmlCharKey ?? XML_CHARKEY,
+ },
+ };
+ let payload = {};
+ const mapperType = mapper.type.name;
+ if (!objectName) {
+ objectName = mapper.serializedName;
+ }
+ if (mapperType.match(/^Sequence$/i) !== null) {
+ payload = [];
+ }
+ if (mapper.isConstant) {
+ object = mapper.defaultValue;
+ }
+ // This table of allowed values should help explain
+ // the mapper.required and mapper.nullable properties.
+ // X means "neither undefined or null are allowed".
+ // || required
+ // || true | false
+ // nullable || ==========================
+ // true || null | undefined/null
+ // false || X | undefined
+ // undefined || X | undefined/null
+ const { required, nullable } = mapper;
+ if (required && nullable && object === undefined) {
+ throw new Error(`${objectName} cannot be undefined.`);
+ }
+ if (required && !nullable && (object === undefined || object === null)) {
+ throw new Error(`${objectName} cannot be null or undefined.`);
+ }
+ if (!required && nullable === false && object === null) {
+ throw new Error(`${objectName} cannot be null.`);
+ }
+ if (object === undefined || object === null) {
+ payload = object;
+ }
+ else {
+ if (mapperType.match(/^any$/i) !== null) {
+ payload = object;
+ }
+ else if (mapperType.match(/^(Number|String|Boolean|Object|Stream|Uuid)$/i) !== null) {
+ payload = serializeBasicTypes(mapperType, objectName, object);
+ }
+ else if (mapperType.match(/^Enum$/i) !== null) {
+ const enumMapper = mapper;
+ payload = serializeEnumType(objectName, enumMapper.type.allowedValues, object);
+ }
+ else if (mapperType.match(/^(Date|DateTime|TimeSpan|DateTimeRfc1123|UnixTime)$/i) !== null) {
+ payload = serializeDateTypes(mapperType, object, objectName);
+ }
+ else if (mapperType.match(/^ByteArray$/i) !== null) {
+ payload = serializeByteArrayType(objectName, object);
+ }
+ else if (mapperType.match(/^Base64Url$/i) !== null) {
+ payload = serializeBase64UrlType(objectName, object);
+ }
+ else if (mapperType.match(/^Sequence$/i) !== null) {
+ payload = serializeSequenceType(this, mapper, object, objectName, Boolean(this.isXML), updatedOptions);
+ }
+ else if (mapperType.match(/^Dictionary$/i) !== null) {
+ payload = serializeDictionaryType(this, mapper, object, objectName, Boolean(this.isXML), updatedOptions);
+ }
+ else if (mapperType.match(/^Composite$/i) !== null) {
+ payload = serializeCompositeType(this, mapper, object, objectName, Boolean(this.isXML), updatedOptions);
+ }
+ }
+ return payload;
+ }
+ /**
+ * Deserialize the given object based on its metadata defined in the mapper
+ *
+ * @param mapper - The mapper which defines the metadata of the serializable object
+ *
+ * @param responseBody - A valid Javascript entity to be deserialized
+ *
+ * @param objectName - Name of the deserialized object
+ *
+ * @param options - Controls behavior of XML parser and builder.
+ *
+ * @returns A valid deserialized Javascript object
+ */
+ deserialize(mapper, responseBody, objectName, options = { xml: {} }) {
+ const updatedOptions = {
+ xml: {
+ rootName: options.xml.rootName ?? "",
+ includeRoot: options.xml.includeRoot ?? false,
+ xmlCharKey: options.xml.xmlCharKey ?? XML_CHARKEY,
+ },
+ ignoreUnknownProperties: options.ignoreUnknownProperties ?? false,
+ };
+ if (responseBody === undefined || responseBody === null) {
+ if (this.isXML && mapper.type.name === "Sequence" && !mapper.xmlIsWrapped) {
+ // Edge case for empty XML non-wrapped lists. xml2js can't distinguish
+ // between the list being empty versus being missing,
+ // so let's do the more user-friendly thing and return an empty list.
+ responseBody = [];
+ }
+ // specifically check for undefined as default value can be a falsey value `0, "", false, null`
+ if (mapper.defaultValue !== undefined) {
+ responseBody = mapper.defaultValue;
+ }
+ return responseBody;
+ }
+ let payload;
+ const mapperType = mapper.type.name;
+ if (!objectName) {
+ objectName = mapper.serializedName;
+ }
+ if (mapperType.match(/^Composite$/i) !== null) {
+ payload = deserializeCompositeType(this, mapper, responseBody, objectName, updatedOptions);
+ }
+ else {
+ if (this.isXML) {
+ const xmlCharKey = updatedOptions.xml.xmlCharKey;
+ /**
+ * If the mapper specifies this as a non-composite type value but the responseBody contains
+ * both header ("$" i.e., XML_ATTRKEY) and body ("#" i.e., XML_CHARKEY) properties,
+ * then just reduce the responseBody value to the body ("#" i.e., XML_CHARKEY) property.
+ */
+ if (responseBody[XML_ATTRKEY] !== undefined && responseBody[xmlCharKey] !== undefined) {
+ responseBody = responseBody[xmlCharKey];
+ }
+ }
+ if (mapperType.match(/^Number$/i) !== null) {
+ payload = parseFloat(responseBody);
+ if (isNaN(payload)) {
+ payload = responseBody;
+ }
+ }
+ else if (mapperType.match(/^Boolean$/i) !== null) {
+ if (responseBody === "true") {
+ payload = true;
+ }
+ else if (responseBody === "false") {
+ payload = false;
+ }
+ else {
+ payload = responseBody;
+ }
+ }
+ else if (mapperType.match(/^(String|Enum|Object|Stream|Uuid|TimeSpan|any)$/i) !== null) {
+ payload = responseBody;
+ }
+ else if (mapperType.match(/^(Date|DateTime|DateTimeRfc1123)$/i) !== null) {
+ payload = new Date(responseBody);
+ }
+ else if (mapperType.match(/^UnixTime$/i) !== null) {
+ payload = unixTimeToDate(responseBody);
+ }
+ else if (mapperType.match(/^ByteArray$/i) !== null) {
+ payload = decodeString(responseBody);
+ }
+ else if (mapperType.match(/^Base64Url$/i) !== null) {
+ payload = base64UrlToByteArray(responseBody);
+ }
+ else if (mapperType.match(/^Sequence$/i) !== null) {
+ payload = deserializeSequenceType(this, mapper, responseBody, objectName, updatedOptions);
+ }
+ else if (mapperType.match(/^Dictionary$/i) !== null) {
+ payload = deserializeDictionaryType(this, mapper, responseBody, objectName, updatedOptions);
+ }
+ }
+ if (mapper.isConstant) {
+ payload = mapper.defaultValue;
+ }
+ return payload;
+ }
+}
+/**
+ * Method that creates and returns a Serializer.
+ * @param modelMappers - Known models to map
+ * @param isXML - If XML should be supported
+ */
+function createSerializer(modelMappers = {}, isXML = false) {
+ return new SerializerImpl(modelMappers, isXML);
+}
+function trimEnd(str, ch) {
+ let len = str.length;
+ while (len - 1 >= 0 && str[len - 1] === ch) {
+ --len;
+ }
+ return str.substr(0, len);
+}
+function bufferToBase64Url(buffer) {
+ if (!buffer) {
+ return undefined;
+ }
+ if (!(buffer instanceof Uint8Array)) {
+ throw new Error(`Please provide an input of type Uint8Array for converting to Base64Url.`);
+ }
+ // Uint8Array to Base64.
+ const str = encodeByteArray(buffer);
+ // Base64 to Base64Url.
+ return trimEnd(str, "=").replace(/\+/g, "-").replace(/\//g, "_");
+}
+function base64UrlToByteArray(str) {
+ if (!str) {
+ return undefined;
+ }
+ if (str && typeof str.valueOf() !== "string") {
+ throw new Error("Please provide an input of type string for converting to Uint8Array");
+ }
+ // Base64Url to Base64.
+ str = str.replace(/-/g, "+").replace(/_/g, "/");
+ // Base64 to Uint8Array.
+ return decodeString(str);
+}
+function splitSerializeName(prop) {
+ const classes = [];
+ let partialclass = "";
+ if (prop) {
+ const subwords = prop.split(".");
+ for (const item of subwords) {
+ if (item.charAt(item.length - 1) === "\\") {
+ partialclass += item.substr(0, item.length - 1) + ".";
+ }
+ else {
+ partialclass += item;
+ classes.push(partialclass);
+ partialclass = "";
+ }
+ }
+ }
+ return classes;
+}
+function dateToUnixTime(d) {
+ if (!d) {
+ return undefined;
+ }
+ if (typeof d.valueOf() === "string") {
+ d = new Date(d);
+ }
+ return Math.floor(d.getTime() / 1000);
+}
+function unixTimeToDate(n) {
+ if (!n) {
+ return undefined;
+ }
+ return new Date(n * 1000);
+}
+function serializeBasicTypes(typeName, objectName, value) {
+ if (value !== null && value !== undefined) {
+ if (typeName.match(/^Number$/i) !== null) {
+ if (typeof value !== "number") {
+ throw new Error(`${objectName} with value ${value} must be of type number.`);
+ }
+ }
+ else if (typeName.match(/^String$/i) !== null) {
+ if (typeof value.valueOf() !== "string") {
+ throw new Error(`${objectName} with value "${value}" must be of type string.`);
+ }
+ }
+ else if (typeName.match(/^Uuid$/i) !== null) {
+ if (!(typeof value.valueOf() === "string" && isValidUuid(value))) {
+ throw new Error(`${objectName} with value "${value}" must be of type string and a valid uuid.`);
+ }
+ }
+ else if (typeName.match(/^Boolean$/i) !== null) {
+ if (typeof value !== "boolean") {
+ throw new Error(`${objectName} with value ${value} must be of type boolean.`);
+ }
+ }
+ else if (typeName.match(/^Stream$/i) !== null) {
+ const objectType = typeof value;
+ if (objectType !== "string" &&
+ typeof value.pipe !== "function" && // NodeJS.ReadableStream
+ typeof value.tee !== "function" && // browser ReadableStream
+ !(value instanceof ArrayBuffer) &&
+ !ArrayBuffer.isView(value) &&
+ // File objects count as a type of Blob, so we want to use instanceof explicitly
+ !((typeof Blob === "function" || typeof Blob === "object") && value instanceof Blob) &&
+ objectType !== "function") {
+ throw new Error(`${objectName} must be a string, Blob, ArrayBuffer, ArrayBufferView, ReadableStream, or () => ReadableStream.`);
+ }
+ }
+ }
+ return value;
+}
+function serializeEnumType(objectName, allowedValues, value) {
+ if (!allowedValues) {
+ throw new Error(`Please provide a set of allowedValues to validate ${objectName} as an Enum Type.`);
+ }
+ const isPresent = allowedValues.some((item) => {
+ if (typeof item.valueOf() === "string") {
+ return item.toLowerCase() === value.toLowerCase();
+ }
+ return item === value;
+ });
+ if (!isPresent) {
+ throw new Error(`${value} is not a valid value for ${objectName}. The valid values are: ${JSON.stringify(allowedValues)}.`);
+ }
+ return value;
+}
+function serializeByteArrayType(objectName, value) {
+ if (value !== undefined && value !== null) {
+ if (!(value instanceof Uint8Array)) {
+ throw new Error(`${objectName} must be of type Uint8Array.`);
+ }
+ value = encodeByteArray(value);
+ }
+ return value;
+}
+function serializeBase64UrlType(objectName, value) {
+ if (value !== undefined && value !== null) {
+ if (!(value instanceof Uint8Array)) {
+ throw new Error(`${objectName} must be of type Uint8Array.`);
+ }
+ value = bufferToBase64Url(value);
+ }
+ return value;
+}
+function serializeDateTypes(typeName, value, objectName) {
+ if (value !== undefined && value !== null) {
+ if (typeName.match(/^Date$/i) !== null) {
+ if (!(value instanceof Date ||
+ (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
+ throw new Error(`${objectName} must be an instanceof Date or a string in ISO8601 format.`);
+ }
+ value =
+ value instanceof Date
+ ? value.toISOString().substring(0, 10)
+ : new Date(value).toISOString().substring(0, 10);
+ }
+ else if (typeName.match(/^DateTime$/i) !== null) {
+ if (!(value instanceof Date ||
+ (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
+ throw new Error(`${objectName} must be an instanceof Date or a string in ISO8601 format.`);
+ }
+ value = value instanceof Date ? value.toISOString() : new Date(value).toISOString();
+ }
+ else if (typeName.match(/^DateTimeRfc1123$/i) !== null) {
+ if (!(value instanceof Date ||
+ (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
+ throw new Error(`${objectName} must be an instanceof Date or a string in RFC-1123 format.`);
+ }
+ value = value instanceof Date ? value.toUTCString() : new Date(value).toUTCString();
+ }
+ else if (typeName.match(/^UnixTime$/i) !== null) {
+ if (!(value instanceof Date ||
+ (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
+ throw new Error(`${objectName} must be an instanceof Date or a string in RFC-1123/ISO8601 format ` +
+ `for it to be serialized in UnixTime/Epoch format.`);
+ }
+ value = dateToUnixTime(value);
+ }
+ else if (typeName.match(/^TimeSpan$/i) !== null) {
+ if (!isDuration(value)) {
+ throw new Error(`${objectName} must be a string in ISO 8601 format. Instead was "${value}".`);
+ }
+ }
+ }
+ return value;
+}
+function serializeSequenceType(serializer, mapper, object, objectName, isXml, options) {
+ if (!Array.isArray(object)) {
+ throw new Error(`${objectName} must be of type Array.`);
+ }
+ let elementType = mapper.type.element;
+ if (!elementType || typeof elementType !== "object") {
+ throw new Error(`"element" metadata for an Array must be defined in the ` +
+ `mapper and it must be of type "object" in ${objectName}.`);
+ }
+ // Quirk: Composite mappers referenced by `element` might
+ // not have *all* properties declared (like uberParent),
+ // so let's try to look up the full definition by name.
+ if (elementType.type.name === "Composite" && elementType.type.className) {
+ elementType = serializer.modelMappers[elementType.type.className] ?? elementType;
+ }
+ const tempArray = [];
+ for (let i = 0; i < object.length; i++) {
+ const serializedValue = serializer.serialize(elementType, object[i], objectName, options);
+ if (isXml && elementType.xmlNamespace) {
+ const xmlnsKey = elementType.xmlNamespacePrefix
+ ? `xmlns:${elementType.xmlNamespacePrefix}`
+ : "xmlns";
+ if (elementType.type.name === "Composite") {
+ tempArray[i] = { ...serializedValue };
+ tempArray[i][XML_ATTRKEY] = { [xmlnsKey]: elementType.xmlNamespace };
+ }
+ else {
+ tempArray[i] = {};
+ tempArray[i][options.xml.xmlCharKey] = serializedValue;
+ tempArray[i][XML_ATTRKEY] = { [xmlnsKey]: elementType.xmlNamespace };
+ }
+ }
+ else {
+ tempArray[i] = serializedValue;
+ }
+ }
+ return tempArray;
+}
+function serializeDictionaryType(serializer, mapper, object, objectName, isXml, options) {
+ if (typeof object !== "object") {
+ throw new Error(`${objectName} must be of type object.`);
+ }
+ const valueType = mapper.type.value;
+ if (!valueType || typeof valueType !== "object") {
+ throw new Error(`"value" metadata for a Dictionary must be defined in the ` +
+ `mapper and it must of type "object" in ${objectName}.`);
+ }
+ const tempDictionary = {};
+ for (const key of Object.keys(object)) {
+ const serializedValue = serializer.serialize(valueType, object[key], objectName, options);
+ // If the element needs an XML namespace we need to add it within the $ property
+ tempDictionary[key] = getXmlObjectValue(valueType, serializedValue, isXml, options);
+ }
+ // Add the namespace to the root element if needed
+ if (isXml && mapper.xmlNamespace) {
+ const xmlnsKey = mapper.xmlNamespacePrefix ? `xmlns:${mapper.xmlNamespacePrefix}` : "xmlns";
+ const result = tempDictionary;
+ result[XML_ATTRKEY] = { [xmlnsKey]: mapper.xmlNamespace };
+ return result;
+ }
+ return tempDictionary;
+}
+/**
+ * Resolves the additionalProperties property from a referenced mapper
+ * @param serializer - the serializer containing the entire set of mappers
+ * @param mapper - the composite mapper to resolve
+ * @param objectName - name of the object being serialized
+ */
+function resolveAdditionalProperties(serializer, mapper, objectName) {
+ const additionalProperties = mapper.type.additionalProperties;
+ if (!additionalProperties && mapper.type.className) {
+ const modelMapper = resolveReferencedMapper(serializer, mapper, objectName);
+ return modelMapper?.type.additionalProperties;
+ }
+ return additionalProperties;
+}
+/**
+ * Finds the mapper referenced by className
+ * @param serializer - the serializer containing the entire set of mappers
+ * @param mapper - the composite mapper to resolve
+ * @param objectName - name of the object being serialized
+ */
+function resolveReferencedMapper(serializer, mapper, objectName) {
+ const className = mapper.type.className;
+ if (!className) {
+ throw new Error(`Class name for model "${objectName}" is not provided in the mapper "${JSON.stringify(mapper, undefined, 2)}".`);
+ }
+ return serializer.modelMappers[className];
+}
+/**
+ * Resolves a composite mapper's modelProperties.
+ * @param serializer - the serializer containing the entire set of mappers
+ * @param mapper - the composite mapper to resolve
+ */
+function resolveModelProperties(serializer, mapper, objectName) {
+ let modelProps = mapper.type.modelProperties;
+ if (!modelProps) {
+ const modelMapper = resolveReferencedMapper(serializer, mapper, objectName);
+ if (!modelMapper) {
+ throw new Error(`mapper() cannot be null or undefined for model "${mapper.type.className}".`);
+ }
+ modelProps = modelMapper?.type.modelProperties;
+ if (!modelProps) {
+ throw new Error(`modelProperties cannot be null or undefined in the ` +
+ `mapper "${JSON.stringify(modelMapper)}" of type "${mapper.type.className}" for object "${objectName}".`);
+ }
+ }
+ return modelProps;
+}
+function serializeCompositeType(serializer, mapper, object, objectName, isXml, options) {
+ if (getPolymorphicDiscriminatorRecursively(serializer, mapper)) {
+ mapper = getPolymorphicMapper(serializer, mapper, object, "clientName");
+ }
+ if (object !== undefined && object !== null) {
+ const payload = {};
+ const modelProps = resolveModelProperties(serializer, mapper, objectName);
+ for (const key of Object.keys(modelProps)) {
+ const propertyMapper = modelProps[key];
+ if (propertyMapper.readOnly) {
+ continue;
+ }
+ let propName;
+ let parentObject = payload;
+ if (serializer.isXML) {
+ if (propertyMapper.xmlIsWrapped) {
+ propName = propertyMapper.xmlName;
+ }
+ else {
+ propName = propertyMapper.xmlElementName || propertyMapper.xmlName;
+ }
+ }
+ else {
+ const paths = splitSerializeName(propertyMapper.serializedName);
+ propName = paths.pop();
+ for (const pathName of paths) {
+ const childObject = parentObject[pathName];
+ if ((childObject === undefined || childObject === null) &&
+ ((object[key] !== undefined && object[key] !== null) ||
+ propertyMapper.defaultValue !== undefined)) {
+ parentObject[pathName] = {};
+ }
+ parentObject = parentObject[pathName];
+ }
+ }
+ if (parentObject !== undefined && parentObject !== null) {
+ if (isXml && mapper.xmlNamespace) {
+ const xmlnsKey = mapper.xmlNamespacePrefix
+ ? `xmlns:${mapper.xmlNamespacePrefix}`
+ : "xmlns";
+ parentObject[XML_ATTRKEY] = {
+ ...parentObject[XML_ATTRKEY],
+ [xmlnsKey]: mapper.xmlNamespace,
+ };
+ }
+ const propertyObjectName = propertyMapper.serializedName !== ""
+ ? objectName + "." + propertyMapper.serializedName
+ : objectName;
+ let toSerialize = object[key];
+ const polymorphicDiscriminator = getPolymorphicDiscriminatorRecursively(serializer, mapper);
+ if (polymorphicDiscriminator &&
+ polymorphicDiscriminator.clientName === key &&
+ (toSerialize === undefined || toSerialize === null)) {
+ toSerialize = mapper.serializedName;
+ }
+ const serializedValue = serializer.serialize(propertyMapper, toSerialize, propertyObjectName, options);
+ if (serializedValue !== undefined && propName !== undefined && propName !== null) {
+ const value = getXmlObjectValue(propertyMapper, serializedValue, isXml, options);
+ if (isXml && propertyMapper.xmlIsAttribute) {
+ // XML_ATTRKEY, i.e., $ is the key attributes are kept under in xml2js.
+ // This keeps things simple while preventing name collision
+ // with names in user documents.
+ parentObject[XML_ATTRKEY] = parentObject[XML_ATTRKEY] || {};
+ parentObject[XML_ATTRKEY][propName] = serializedValue;
+ }
+ else if (isXml && propertyMapper.xmlIsWrapped) {
+ parentObject[propName] = { [propertyMapper.xmlElementName]: value };
+ }
+ else {
+ parentObject[propName] = value;
+ }
+ }
+ }
+ }
+ const additionalPropertiesMapper = resolveAdditionalProperties(serializer, mapper, objectName);
+ if (additionalPropertiesMapper) {
+ const propNames = Object.keys(modelProps);
+ for (const clientPropName of Object.keys(object)) {
+ const isAdditionalProperty = propNames.every((pn) => pn !== clientPropName);
+ if (isAdditionalProperty) {
+ Object.defineProperty(payload, clientPropName, {
+ value: serializer.serialize(additionalPropertiesMapper, object[clientPropName], objectName + '["' + clientPropName + '"]', options),
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ });
+ }
+ }
+ }
+ return payload;
+ }
+ return object;
+}
+function getXmlObjectValue(propertyMapper, serializedValue, isXml, options) {
+ if (!isXml || !propertyMapper.xmlNamespace) {
+ return serializedValue;
+ }
+ const xmlnsKey = propertyMapper.xmlNamespacePrefix
+ ? `xmlns:${propertyMapper.xmlNamespacePrefix}`
+ : "xmlns";
+ const xmlNamespace = { [xmlnsKey]: propertyMapper.xmlNamespace };
+ if (["Composite"].includes(propertyMapper.type.name)) {
+ if (serializedValue[XML_ATTRKEY]) {
+ return serializedValue;
+ }
+ else {
+ const result = { ...serializedValue };
+ result[XML_ATTRKEY] = xmlNamespace;
+ return result;
+ }
+ }
+ const result = {};
+ result[options.xml.xmlCharKey] = serializedValue;
+ result[XML_ATTRKEY] = xmlNamespace;
+ return result;
+}
+function isSpecialXmlProperty(propertyName, options) {
+ return [XML_ATTRKEY, options.xml.xmlCharKey].includes(propertyName);
+}
+function deserializeCompositeType(serializer, mapper, responseBody, objectName, options) {
+ const xmlCharKey = options.xml.xmlCharKey ?? XML_CHARKEY;
+ if (getPolymorphicDiscriminatorRecursively(serializer, mapper)) {
+ mapper = getPolymorphicMapper(serializer, mapper, responseBody, "serializedName");
+ }
+ const modelProps = resolveModelProperties(serializer, mapper, objectName);
+ let instance = {};
+ const handledPropertyNames = [];
+ for (const key of Object.keys(modelProps)) {
+ const propertyMapper = modelProps[key];
+ const paths = splitSerializeName(modelProps[key].serializedName);
+ handledPropertyNames.push(paths[0]);
+ const { serializedName, xmlName, xmlElementName } = propertyMapper;
+ let propertyObjectName = objectName;
+ if (serializedName !== "" && serializedName !== undefined) {
+ propertyObjectName = objectName + "." + serializedName;
+ }
+ const headerCollectionPrefix = propertyMapper.headerCollectionPrefix;
+ if (headerCollectionPrefix) {
+ const dictionary = {};
+ for (const headerKey of Object.keys(responseBody)) {
+ if (headerKey.startsWith(headerCollectionPrefix)) {
+ dictionary[headerKey.substring(headerCollectionPrefix.length)] = serializer.deserialize(propertyMapper.type.value, responseBody[headerKey], propertyObjectName, options);
+ }
+ handledPropertyNames.push(headerKey);
+ }
+ instance[key] = dictionary;
+ }
+ else if (serializer.isXML) {
+ if (propertyMapper.xmlIsAttribute && responseBody[XML_ATTRKEY]) {
+ instance[key] = serializer.deserialize(propertyMapper, responseBody[XML_ATTRKEY][xmlName], propertyObjectName, options);
+ }
+ else if (propertyMapper.xmlIsMsText) {
+ if (responseBody[xmlCharKey] !== undefined) {
+ instance[key] = responseBody[xmlCharKey];
+ }
+ else if (typeof responseBody === "string") {
+ // The special case where xml parser parses "content" into JSON of
+ // `{ name: "content"}` instead of `{ name: { "_": "content" }}`
+ instance[key] = responseBody;
+ }
+ }
+ else {
+ const propertyName = xmlElementName || xmlName || serializedName;
+ if (propertyMapper.xmlIsWrapped) {
+ /* a list of wrapped by
+ For the xml example below
+
+ ...
+ ...
+
+ the responseBody has
+ {
+ Cors: {
+ CorsRule: [{...}, {...}]
+ }
+ }
+ xmlName is "Cors" and xmlElementName is"CorsRule".
+ */
+ const wrapped = responseBody[xmlName];
+ const elementList = wrapped?.[xmlElementName] ?? [];
+ Object.defineProperty(instance, key, {
+ value: serializer.deserialize(propertyMapper, elementList, propertyObjectName, options),
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ });
+ handledPropertyNames.push(xmlName);
+ }
+ else {
+ const property = responseBody[propertyName];
+ instance[key] = serializer.deserialize(propertyMapper, property, propertyObjectName, options);
+ handledPropertyNames.push(propertyName);
+ }
+ }
+ }
+ else {
+ // deserialize the property if it is present in the provided responseBody instance
+ let propertyInstance;
+ let res = responseBody;
+ // traversing the object step by step.
+ let steps = 0;
+ for (const item of paths) {
+ if (!res)
+ break;
+ steps++;
+ res = res[item];
+ }
+ // only accept null when reaching the last position of object otherwise it would be undefined
+ if (res === null && steps < paths.length) {
+ res = undefined;
+ }
+ propertyInstance = res;
+ const polymorphicDiscriminator = mapper.type.polymorphicDiscriminator;
+ // checking that the model property name (key)(ex: "fishtype") and the
+ // clientName of the polymorphicDiscriminator {metadata} (ex: "fishtype")
+ // instead of the serializedName of the polymorphicDiscriminator (ex: "fish.type")
+ // is a better approach. The generator is not consistent with escaping '\.' in the
+ // serializedName of the property (ex: "fish\.type") that is marked as polymorphic discriminator
+ // and the serializedName of the metadata polymorphicDiscriminator (ex: "fish.type"). However,
+ // the clientName transformation of the polymorphicDiscriminator (ex: "fishtype") and
+ // the transformation of model property name (ex: "fishtype") is done consistently.
+ // Hence, it is a safer bet to rely on the clientName of the polymorphicDiscriminator.
+ if (polymorphicDiscriminator &&
+ key === polymorphicDiscriminator.clientName &&
+ (propertyInstance === undefined || propertyInstance === null)) {
+ propertyInstance = mapper.serializedName;
+ }
+ let serializedValue;
+ // paging
+ if (Array.isArray(responseBody[key]) && modelProps[key].serializedName === "") {
+ propertyInstance = responseBody[key];
+ const arrayInstance = serializer.deserialize(propertyMapper, propertyInstance, propertyObjectName, options);
+ // Copy over any properties that have already been added into the instance, where they do
+ // not exist on the newly de-serialized array
+ for (const [k, v] of Object.entries(instance)) {
+ if (!Object.prototype.hasOwnProperty.call(arrayInstance, k)) {
+ arrayInstance[k] = v;
+ }
+ }
+ instance = arrayInstance;
+ }
+ else if (propertyInstance !== undefined || propertyMapper.defaultValue !== undefined) {
+ serializedValue = serializer.deserialize(propertyMapper, propertyInstance, propertyObjectName, options);
+ instance[key] = serializedValue;
+ }
+ }
+ }
+ const additionalPropertiesMapper = mapper.type.additionalProperties;
+ if (additionalPropertiesMapper) {
+ const isAdditionalProperty = (responsePropName) => {
+ for (const clientPropName of Object.keys(modelProps)) {
+ const paths = splitSerializeName(modelProps[clientPropName].serializedName);
+ if (paths[0] === responsePropName) {
+ return false;
+ }
+ }
+ return true;
+ };
+ for (const responsePropName of Object.keys(responseBody)) {
+ if (isAdditionalProperty(responsePropName)) {
+ const deserializedValue = serializer.deserialize(additionalPropertiesMapper, responseBody[responsePropName], objectName + '["' + responsePropName + '"]', options);
+ Object.defineProperty(instance, responsePropName, {
+ value: deserializedValue,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ });
+ }
+ }
+ }
+ else if (responseBody && !options.ignoreUnknownProperties) {
+ for (const key of Object.keys(responseBody)) {
+ if (instance[key] === undefined &&
+ !handledPropertyNames.includes(key) &&
+ !isSpecialXmlProperty(key, options)) {
+ Object.defineProperty(instance, key, {
+ value: responseBody[key],
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ });
+ }
+ }
+ }
+ return instance;
+}
+function deserializeDictionaryType(serializer, mapper, responseBody, objectName, options) {
+ /* jshint validthis: true */
+ const value = mapper.type.value;
+ if (!value || typeof value !== "object") {
+ throw new Error(`"value" metadata for a Dictionary must be defined in the ` +
+ `mapper and it must of type "object" in ${objectName}`);
+ }
+ if (responseBody) {
+ const tempDictionary = {};
+ for (const key of Object.keys(responseBody)) {
+ tempDictionary[key] = serializer.deserialize(value, responseBody[key], objectName, options);
+ }
+ return tempDictionary;
+ }
+ return responseBody;
+}
+function deserializeSequenceType(serializer, mapper, responseBody, objectName, options) {
+ let element = mapper.type.element;
+ if (!element || typeof element !== "object") {
+ throw new Error(`"element" metadata for an Array must be defined in the ` +
+ `mapper and it must be of type "object" in ${objectName}`);
+ }
+ if (responseBody) {
+ if (!Array.isArray(responseBody)) {
+ // xml2js will interpret a single element array as just the element, so force it to be an array
+ responseBody = [responseBody];
+ }
+ // Quirk: Composite mappers referenced by `element` might
+ // not have *all* properties declared (like uberParent),
+ // so let's try to look up the full definition by name.
+ if (element.type.name === "Composite" && element.type.className) {
+ element = serializer.modelMappers[element.type.className] ?? element;
+ }
+ const tempArray = [];
+ for (let i = 0; i < responseBody.length; i++) {
+ tempArray[i] = serializer.deserialize(element, responseBody[i], `${objectName}[${i}]`, options);
+ }
+ return tempArray;
+ }
+ return responseBody;
+}
+function getIndexDiscriminator(discriminators, discriminatorValue, typeName) {
+ const typeNamesToCheck = [typeName];
+ while (typeNamesToCheck.length) {
+ const currentName = typeNamesToCheck.shift();
+ const indexDiscriminator = discriminatorValue === currentName
+ ? discriminatorValue
+ : currentName + "." + discriminatorValue;
+ if (Object.prototype.hasOwnProperty.call(discriminators, indexDiscriminator)) {
+ return discriminators[indexDiscriminator];
+ }
+ else {
+ for (const [name, mapper] of Object.entries(discriminators)) {
+ if (name.startsWith(currentName + ".") &&
+ mapper.type.uberParent === currentName &&
+ mapper.type.className) {
+ typeNamesToCheck.push(mapper.type.className);
+ }
+ }
+ }
+ }
+ return undefined;
+}
+function getPolymorphicMapper(serializer, mapper, object, polymorphicPropertyName) {
+ const polymorphicDiscriminator = getPolymorphicDiscriminatorRecursively(serializer, mapper);
+ if (polymorphicDiscriminator) {
+ let discriminatorName = polymorphicDiscriminator[polymorphicPropertyName];
+ if (discriminatorName) {
+ // The serializedName might have \\, which we just want to ignore
+ if (polymorphicPropertyName === "serializedName") {
+ discriminatorName = discriminatorName.replace(/\\/gi, "");
+ }
+ const discriminatorValue = object[discriminatorName];
+ const typeName = mapper.type.uberParent ?? mapper.type.className;
+ if (typeof discriminatorValue === "string" && typeName) {
+ const polymorphicMapper = getIndexDiscriminator(serializer.modelMappers.discriminators, discriminatorValue, typeName);
+ if (polymorphicMapper) {
+ mapper = polymorphicMapper;
+ }
+ }
+ }
+ }
+ return mapper;
+}
+function getPolymorphicDiscriminatorRecursively(serializer, mapper) {
+ return (mapper.type.polymorphicDiscriminator ||
+ getPolymorphicDiscriminatorSafely(serializer, mapper.type.uberParent) ||
+ getPolymorphicDiscriminatorSafely(serializer, mapper.type.className));
+}
+function getPolymorphicDiscriminatorSafely(serializer, typeName) {
+ return (typeName &&
+ serializer.modelMappers[typeName] &&
+ serializer.modelMappers[typeName].type.polymorphicDiscriminator);
+}
+/**
+ * Known types of Mappers
+ */
+const MapperTypeNames = {
+ Base64Url: "Base64Url",
+ Boolean: "Boolean",
+ ByteArray: "ByteArray",
+ Composite: "Composite",
+ Date: "Date",
+ DateTime: "DateTime",
+ DateTimeRfc1123: "DateTimeRfc1123",
+ Dictionary: "Dictionary",
+ Enum: "Enum",
+ Number: "Number",
+ Object: "Object",
+ Sequence: "Sequence",
+ String: "String",
+ Stream: "Stream",
+ TimeSpan: "TimeSpan",
+ UnixTime: "UnixTime",
+};
+//# sourceMappingURL=serializer.js.map
+// EXTERNAL MODULE: ./node_modules/@azure/core-client/dist/commonjs/state-cjs.js
+var commonjs_state_cjs = __webpack_require__(30);
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/state.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// @ts-expect-error The recommended approach to sharing module state between ESM and CJS.
+// See https://github.com/isaacs/tshy/blob/main/README.md#module-local-state for additional information.
+
+/**
+ * Defines the shared state between CJS and ESM by re-exporting the CJS state.
+ */
+const esm_state_state = commonjs_state_cjs/* state */.w;
+//# sourceMappingURL=state.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/operationHelpers.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * @internal
+ * Retrieves the value to use for a given operation argument
+ * @param operationArguments - The arguments passed from the generated client
+ * @param parameter - The parameter description
+ * @param fallbackObject - If something isn't found in the arguments bag, look here.
+ * Generally used to look at the service client properties.
+ */
+function getOperationArgumentValueFromParameter(operationArguments, parameter, fallbackObject) {
+ let parameterPath = parameter.parameterPath;
+ const parameterMapper = parameter.mapper;
+ let value;
+ if (typeof parameterPath === "string") {
+ parameterPath = [parameterPath];
+ }
+ if (Array.isArray(parameterPath)) {
+ if (parameterPath.length > 0) {
+ if (parameterMapper.isConstant) {
+ value = parameterMapper.defaultValue;
+ }
+ else {
+ let propertySearchResult = getPropertyFromParameterPath(operationArguments, parameterPath);
+ if (!propertySearchResult.propertyFound && fallbackObject) {
+ propertySearchResult = getPropertyFromParameterPath(fallbackObject, parameterPath);
+ }
+ let useDefaultValue = false;
+ if (!propertySearchResult.propertyFound) {
+ useDefaultValue =
+ parameterMapper.required ||
+ (parameterPath[0] === "options" && parameterPath.length === 2);
+ }
+ value = useDefaultValue ? parameterMapper.defaultValue : propertySearchResult.propertyValue;
+ }
+ }
+ }
+ else {
+ if (parameterMapper.required) {
+ value = {};
+ }
+ for (const [propertyName, propertyPath] of Object.entries(parameterPath)) {
+ const propertyMapper = parameterMapper.type.modelProperties[propertyName];
+ const propertyValue = getOperationArgumentValueFromParameter(operationArguments, {
+ parameterPath: propertyPath,
+ mapper: propertyMapper,
+ }, fallbackObject);
+ if (propertyValue !== undefined) {
+ if (!value) {
+ value = {};
+ }
+ Object.defineProperty(value, propertyName, {
+ value: propertyValue,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ });
+ }
+ }
+ }
+ return value;
+}
+function getPropertyFromParameterPath(parent, parameterPath) {
+ const result = { propertyFound: false };
+ let i = 0;
+ for (; i < parameterPath.length; ++i) {
+ const parameterPathPart = parameterPath[i];
+ // Make sure to check inherited properties too, so don't use hasOwnProperty().
+ if (parent && parameterPathPart in parent) {
+ parent = parent[parameterPathPart];
+ }
+ else {
+ break;
+ }
+ }
+ if (i === parameterPath.length) {
+ result.propertyValue = parent;
+ result.propertyFound = true;
+ }
+ return result;
+}
+const originalRequestSymbol = Symbol.for("@azure/core-client original request");
+function hasOriginalRequest(request) {
+ return originalRequestSymbol in request;
+}
+function getOperationRequestInfo(request) {
+ if (hasOriginalRequest(request)) {
+ return getOperationRequestInfo(request[originalRequestSymbol]);
+ }
+ let info = esm_state_state.operationRequestMap.get(request);
+ if (!info) {
+ info = {};
+ esm_state_state.operationRequestMap.set(request, info);
+ }
+ return info;
+}
+//# sourceMappingURL=operationHelpers.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/deserializationPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+const defaultJsonContentTypes = ["application/json", "text/json"];
+const defaultXmlContentTypes = ["application/xml", "application/atom+xml"];
+/**
+ * The programmatic identifier of the deserializationPolicy.
+ */
+const deserializationPolicyName = "deserializationPolicy";
+/**
+ * This policy handles parsing out responses according to OperationSpecs on the request.
+ */
+function deserializationPolicy(options = {}) {
+ const jsonContentTypes = options.expectedContentTypes?.json ?? defaultJsonContentTypes;
+ const xmlContentTypes = options.expectedContentTypes?.xml ?? defaultXmlContentTypes;
+ const parseXML = options.parseXML;
+ const serializerOptions = options.serializerOptions;
+ const updatedOptions = {
+ xml: {
+ rootName: serializerOptions?.xml.rootName ?? "",
+ includeRoot: serializerOptions?.xml.includeRoot ?? false,
+ xmlCharKey: serializerOptions?.xml.xmlCharKey ?? XML_CHARKEY,
+ },
+ };
+ return {
+ name: deserializationPolicyName,
+ async sendRequest(request, next) {
+ const response = await next(request);
+ return deserializeResponseBody(jsonContentTypes, xmlContentTypes, response, updatedOptions, parseXML);
+ },
+ };
+}
+function getOperationResponseMap(parsedResponse) {
+ let result;
+ const request = parsedResponse.request;
+ const operationInfo = getOperationRequestInfo(request);
+ const operationSpec = operationInfo?.operationSpec;
+ if (operationSpec) {
+ if (!operationInfo?.operationResponseGetter) {
+ result = operationSpec.responses[parsedResponse.status];
+ }
+ else {
+ result = operationInfo?.operationResponseGetter(operationSpec, parsedResponse);
+ }
+ }
+ return result;
+}
+function shouldDeserializeResponse(parsedResponse) {
+ const request = parsedResponse.request;
+ const operationInfo = getOperationRequestInfo(request);
+ const shouldDeserialize = operationInfo?.shouldDeserialize;
+ let result;
+ if (shouldDeserialize === undefined) {
+ result = true;
+ }
+ else if (typeof shouldDeserialize === "boolean") {
+ result = shouldDeserialize;
+ }
+ else {
+ result = shouldDeserialize(parsedResponse);
+ }
+ return result;
+}
+async function deserializeResponseBody(jsonContentTypes, xmlContentTypes, response, options, parseXML) {
+ const parsedResponse = await parse(jsonContentTypes, xmlContentTypes, response, options, parseXML);
+ if (!shouldDeserializeResponse(parsedResponse)) {
+ return parsedResponse;
+ }
+ const operationInfo = getOperationRequestInfo(parsedResponse.request);
+ const operationSpec = operationInfo?.operationSpec;
+ if (!operationSpec || !operationSpec.responses) {
+ return parsedResponse;
+ }
+ const responseSpec = getOperationResponseMap(parsedResponse);
+ const { error, shouldReturnResponse } = handleErrorResponse(parsedResponse, operationSpec, responseSpec, options);
+ if (error) {
+ throw error;
+ }
+ else if (shouldReturnResponse) {
+ return parsedResponse;
+ }
+ // An operation response spec does exist for current status code, so
+ // use it to deserialize the response.
+ if (responseSpec) {
+ if (responseSpec.bodyMapper) {
+ let valueToDeserialize = parsedResponse.parsedBody;
+ if (operationSpec.isXML && responseSpec.bodyMapper.type.name === MapperTypeNames.Sequence) {
+ valueToDeserialize =
+ typeof valueToDeserialize === "object"
+ ? valueToDeserialize[responseSpec.bodyMapper.xmlElementName]
+ : [];
+ }
+ try {
+ parsedResponse.parsedBody = operationSpec.serializer.deserialize(responseSpec.bodyMapper, valueToDeserialize, "operationRes.parsedBody", options);
+ }
+ catch (deserializeError) {
+ const restError = new esm_restError_RestError(`Error ${deserializeError} occurred in deserializing the responseBody - ${parsedResponse.bodyAsText}`, {
+ statusCode: parsedResponse.status,
+ request: parsedResponse.request,
+ response: parsedResponse,
+ });
+ throw restError;
+ }
+ }
+ else if (operationSpec.httpMethod === "HEAD") {
+ // head methods never have a body, but we return a boolean to indicate presence/absence of the resource
+ parsedResponse.parsedBody = response.status >= 200 && response.status < 300;
+ }
+ if (responseSpec.headersMapper) {
+ parsedResponse.parsedHeaders = operationSpec.serializer.deserialize(responseSpec.headersMapper, parsedResponse.headers.toJSON(), "operationRes.parsedHeaders", { xml: {}, ignoreUnknownProperties: true });
+ }
+ }
+ return parsedResponse;
+}
+function isOperationSpecEmpty(operationSpec) {
+ const expectedStatusCodes = Object.keys(operationSpec.responses);
+ return (expectedStatusCodes.length === 0 ||
+ (expectedStatusCodes.length === 1 && expectedStatusCodes[0] === "default"));
+}
+function handleErrorResponse(parsedResponse, operationSpec, responseSpec, options) {
+ const isSuccessByStatus = 200 <= parsedResponse.status && parsedResponse.status < 300;
+ const isExpectedStatusCode = isOperationSpecEmpty(operationSpec)
+ ? isSuccessByStatus
+ : !!responseSpec;
+ if (isExpectedStatusCode) {
+ if (responseSpec) {
+ if (!responseSpec.isError) {
+ return { error: null, shouldReturnResponse: false };
+ }
+ }
+ else {
+ return { error: null, shouldReturnResponse: false };
+ }
+ }
+ const errorResponseSpec = responseSpec ?? operationSpec.responses.default;
+ const initialErrorMessage = parsedResponse.request.streamResponseStatusCodes?.has(parsedResponse.status)
+ ? `Unexpected status code: ${parsedResponse.status}`
+ : parsedResponse.bodyAsText;
+ const error = new esm_restError_RestError(initialErrorMessage, {
+ statusCode: parsedResponse.status,
+ request: parsedResponse.request,
+ response: parsedResponse,
+ });
+ // If the item failed but there's no error spec or default spec to deserialize the error,
+ // and the parsed body doesn't look like an error object,
+ // we should fail so we just throw the parsed response
+ if (!errorResponseSpec &&
+ !(parsedResponse.parsedBody?.error?.code && parsedResponse.parsedBody?.error?.message)) {
+ throw error;
+ }
+ const defaultBodyMapper = errorResponseSpec?.bodyMapper;
+ const defaultHeadersMapper = errorResponseSpec?.headersMapper;
+ try {
+ // If error response has a body, try to deserialize it using default body mapper.
+ // Then try to extract error code & message from it
+ if (parsedResponse.parsedBody) {
+ const parsedBody = parsedResponse.parsedBody;
+ let deserializedError;
+ if (defaultBodyMapper) {
+ let valueToDeserialize = parsedBody;
+ if (operationSpec.isXML && defaultBodyMapper.type.name === MapperTypeNames.Sequence) {
+ valueToDeserialize = [];
+ const elementName = defaultBodyMapper.xmlElementName;
+ if (typeof parsedBody === "object" && elementName) {
+ valueToDeserialize = parsedBody[elementName];
+ }
+ }
+ deserializedError = operationSpec.serializer.deserialize(defaultBodyMapper, valueToDeserialize, "error.response.parsedBody", options);
+ }
+ const internalError = parsedBody.error || deserializedError || parsedBody;
+ error.code = internalError.code;
+ if (internalError.message) {
+ error.message = internalError.message;
+ }
+ if (defaultBodyMapper) {
+ error.response.parsedBody = deserializedError;
+ }
+ }
+ // If error response has headers, try to deserialize it using default header mapper
+ if (parsedResponse.headers && defaultHeadersMapper) {
+ error.response.parsedHeaders =
+ operationSpec.serializer.deserialize(defaultHeadersMapper, parsedResponse.headers.toJSON(), "operationRes.parsedHeaders");
+ }
+ }
+ catch (defaultError) {
+ error.message = `Error "${defaultError.message}" occurred in deserializing the responseBody - "${parsedResponse.bodyAsText}" for the default response.`;
+ }
+ return { error, shouldReturnResponse: false };
+}
+async function parse(jsonContentTypes, xmlContentTypes, operationResponse, opts, parseXML) {
+ if (!operationResponse.request.streamResponseStatusCodes?.has(operationResponse.status) &&
+ operationResponse.bodyAsText) {
+ const text = operationResponse.bodyAsText;
+ const contentType = operationResponse.headers.get("Content-Type") || "";
+ const contentComponents = !contentType
+ ? []
+ : contentType.split(";").map((component) => component.toLowerCase());
+ try {
+ if (contentComponents.length === 0 ||
+ contentComponents.some((component) => jsonContentTypes.indexOf(component) !== -1)) {
+ operationResponse.parsedBody = JSON.parse(text);
+ return operationResponse;
+ }
+ else if (contentComponents.some((component) => xmlContentTypes.indexOf(component) !== -1)) {
+ if (!parseXML) {
+ throw new Error("Parsing XML not supported.");
+ }
+ const body = await parseXML(text, opts.xml);
+ operationResponse.parsedBody = body;
+ return operationResponse;
+ }
+ }
+ catch (err) {
+ const msg = `Error "${err}" occurred while parsing the response body - ${operationResponse.bodyAsText}.`;
+ const errCode = err.code || esm_restError_RestError.PARSE_ERROR;
+ const e = new esm_restError_RestError(msg, {
+ code: errCode,
+ statusCode: operationResponse.status,
+ request: operationResponse.request,
+ response: operationResponse,
+ });
+ throw e;
+ }
+ }
+ return operationResponse;
+}
+//# sourceMappingURL=deserializationPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/interfaceHelpers.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Gets the list of status codes for streaming responses.
+ * @internal
+ */
+function getStreamingResponseStatusCodes(operationSpec) {
+ const result = new Set();
+ for (const [statusCode, operationResponse] of Object.entries(operationSpec.responses)) {
+ if (operationResponse.bodyMapper &&
+ operationResponse.bodyMapper.type.name === MapperTypeNames.Stream) {
+ result.add(Number(statusCode));
+ }
+ }
+ return result;
+}
+/**
+ * Get the path to this parameter's value as a dotted string (a.b.c).
+ * @param parameter - The parameter to get the path string for.
+ * @returns The path to this parameter's value as a dotted string.
+ * @internal
+ */
+function getPathStringFromParameter(parameter) {
+ const { parameterPath, mapper } = parameter;
+ let result;
+ if (typeof parameterPath === "string") {
+ result = parameterPath;
+ }
+ else if (Array.isArray(parameterPath)) {
+ result = parameterPath.join(".");
+ }
+ else {
+ result = mapper.serializedName;
+ }
+ return result;
+}
+//# sourceMappingURL=interfaceHelpers.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/serializationPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+/**
+ * The programmatic identifier of the serializationPolicy.
+ */
+const serializationPolicyName = "serializationPolicy";
+/**
+ * This policy handles assembling the request body and headers using
+ * an OperationSpec and OperationArguments on the request.
+ */
+function serializationPolicy(options = {}) {
+ const stringifyXML = options.stringifyXML;
+ return {
+ name: serializationPolicyName,
+ sendRequest(request, next) {
+ const operationInfo = getOperationRequestInfo(request);
+ const operationSpec = operationInfo?.operationSpec;
+ const operationArguments = operationInfo?.operationArguments;
+ if (operationSpec && operationArguments) {
+ serializeHeaders(request, operationArguments, operationSpec);
+ serializeRequestBody(request, operationArguments, operationSpec, stringifyXML);
+ }
+ return next(request);
+ },
+ };
+}
+/**
+ * @internal
+ */
+function serializeHeaders(request, operationArguments, operationSpec) {
+ if (operationSpec.headerParameters) {
+ for (const headerParameter of operationSpec.headerParameters) {
+ let headerValue = getOperationArgumentValueFromParameter(operationArguments, headerParameter);
+ if ((headerValue !== null && headerValue !== undefined) || headerParameter.mapper.required) {
+ headerValue = operationSpec.serializer.serialize(headerParameter.mapper, headerValue, getPathStringFromParameter(headerParameter));
+ const headerCollectionPrefix = headerParameter.mapper
+ .headerCollectionPrefix;
+ if (headerCollectionPrefix) {
+ for (const key of Object.keys(headerValue)) {
+ request.headers.set(headerCollectionPrefix + key, headerValue[key]);
+ }
+ }
+ else {
+ request.headers.set(headerParameter.mapper.serializedName || getPathStringFromParameter(headerParameter), headerValue);
+ }
+ }
+ }
+ }
+ const customHeaders = operationArguments.options?.requestOptions?.customHeaders;
+ if (customHeaders) {
+ for (const customHeaderName of Object.keys(customHeaders)) {
+ request.headers.set(customHeaderName, customHeaders[customHeaderName]);
+ }
+ }
+}
+/**
+ * @internal
+ */
+function serializeRequestBody(request, operationArguments, operationSpec, stringifyXML = function () {
+ throw new Error("XML serialization unsupported!");
+}) {
+ const serializerOptions = operationArguments.options?.serializerOptions;
+ const updatedOptions = {
+ xml: {
+ rootName: serializerOptions?.xml.rootName ?? "",
+ includeRoot: serializerOptions?.xml.includeRoot ?? false,
+ xmlCharKey: serializerOptions?.xml.xmlCharKey ?? XML_CHARKEY,
+ },
+ };
+ const xmlCharKey = updatedOptions.xml.xmlCharKey;
+ if (operationSpec.requestBody && operationSpec.requestBody.mapper) {
+ request.body = getOperationArgumentValueFromParameter(operationArguments, operationSpec.requestBody);
+ const bodyMapper = operationSpec.requestBody.mapper;
+ const { required, serializedName, xmlName, xmlElementName, xmlNamespace, xmlNamespacePrefix, nullable, } = bodyMapper;
+ const typeName = bodyMapper.type.name;
+ try {
+ if ((request.body !== undefined && request.body !== null) ||
+ (nullable && request.body === null) ||
+ required) {
+ const requestBodyParameterPathString = getPathStringFromParameter(operationSpec.requestBody);
+ request.body = operationSpec.serializer.serialize(bodyMapper, request.body, requestBodyParameterPathString, updatedOptions);
+ const isStream = typeName === MapperTypeNames.Stream;
+ if (operationSpec.isXML) {
+ const xmlnsKey = xmlNamespacePrefix ? `xmlns:${xmlNamespacePrefix}` : "xmlns";
+ const value = getXmlValueWithNamespace(xmlNamespace, xmlnsKey, typeName, request.body, updatedOptions);
+ if (typeName === MapperTypeNames.Sequence) {
+ request.body = stringifyXML(prepareXMLRootList(value, xmlElementName || xmlName || serializedName, xmlnsKey, xmlNamespace), { rootName: xmlName || serializedName, xmlCharKey });
+ }
+ else if (!isStream) {
+ request.body = stringifyXML(value, {
+ rootName: xmlName || serializedName,
+ xmlCharKey,
+ });
+ }
+ }
+ else if (typeName === MapperTypeNames.String &&
+ (operationSpec.contentType?.match("text/plain") || operationSpec.mediaType === "text")) {
+ // the String serializer has validated that request body is a string
+ // so just send the string.
+ return;
+ }
+ else if (!isStream) {
+ request.body = JSON.stringify(request.body);
+ }
+ }
+ }
+ catch (error) {
+ throw new Error(`Error "${error.message}" occurred in serializing the payload - ${JSON.stringify(serializedName, undefined, " ")}.`);
+ }
+ }
+ else if (operationSpec.formDataParameters && operationSpec.formDataParameters.length > 0) {
+ request.formData = {};
+ for (const formDataParameter of operationSpec.formDataParameters) {
+ const formDataParameterValue = getOperationArgumentValueFromParameter(operationArguments, formDataParameter);
+ if (formDataParameterValue !== undefined && formDataParameterValue !== null) {
+ const formDataParameterPropertyName = formDataParameter.mapper.serializedName || getPathStringFromParameter(formDataParameter);
+ request.formData[formDataParameterPropertyName] = operationSpec.serializer.serialize(formDataParameter.mapper, formDataParameterValue, getPathStringFromParameter(formDataParameter), updatedOptions);
+ }
+ }
+ }
+}
+/**
+ * Adds an xml namespace to the xml serialized object if needed, otherwise it just returns the value itself
+ */
+function getXmlValueWithNamespace(xmlNamespace, xmlnsKey, typeName, serializedValue, options) {
+ // Composite and Sequence schemas already got their root namespace set during serialization
+ // We just need to add xmlns to the other schema types
+ if (xmlNamespace && !["Composite", "Sequence", "Dictionary"].includes(typeName)) {
+ const result = {};
+ result[options.xml.xmlCharKey] = serializedValue;
+ result[XML_ATTRKEY] = { [xmlnsKey]: xmlNamespace };
+ return result;
+ }
+ return serializedValue;
+}
+function prepareXMLRootList(obj, elementName, xmlNamespaceKey, xmlNamespace) {
+ if (!Array.isArray(obj)) {
+ obj = [obj];
+ }
+ if (!xmlNamespaceKey || !xmlNamespace) {
+ return { [elementName]: obj };
+ }
+ const result = { [elementName]: obj };
+ result[XML_ATTRKEY] = { [xmlNamespaceKey]: xmlNamespace };
+ return result;
+}
+//# sourceMappingURL=serializationPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/pipeline.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+/**
+ * Creates a new Pipeline for use with a Service Client.
+ * Adds in deserializationPolicy by default.
+ * Also adds in bearerTokenAuthenticationPolicy if passed a TokenCredential.
+ * @param options - Options to customize the created pipeline.
+ */
+function createClientPipeline(options = {}) {
+ const pipeline = esm_createPipelineFromOptions_createPipelineFromOptions(options ?? {});
+ if (options.credentialOptions) {
+ pipeline.addPolicy(bearerTokenAuthenticationPolicy({
+ credential: options.credentialOptions.credential,
+ scopes: options.credentialOptions.credentialScopes,
+ }));
+ }
+ pipeline.addPolicy(serializationPolicy(options.serializationOptions), { phase: "Serialize" });
+ pipeline.addPolicy(deserializationPolicy(options.deserializationOptions), {
+ phase: "Deserialize",
+ });
+ return pipeline;
+}
+//# sourceMappingURL=pipeline.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/httpClientCache.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+let httpClientCache_cachedHttpClient;
+function getCachedDefaultHttpClient() {
+ if (!httpClientCache_cachedHttpClient) {
+ httpClientCache_cachedHttpClient = esm_defaultHttpClient_createDefaultHttpClient();
+ }
+ return httpClientCache_cachedHttpClient;
+}
+//# sourceMappingURL=httpClientCache.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/urlHelpers.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+const CollectionFormatToDelimiterMap = {
+ CSV: ",",
+ SSV: " ",
+ Multi: "Multi",
+ TSV: "\t",
+ Pipes: "|",
+};
+function getRequestUrl(baseUri, operationSpec, operationArguments, fallbackObject) {
+ const urlReplacements = calculateUrlReplacements(operationSpec, operationArguments, fallbackObject);
+ let isAbsolutePath = false;
+ let requestUrl = replaceAll(baseUri, urlReplacements);
+ if (operationSpec.path) {
+ let path = replaceAll(operationSpec.path, urlReplacements);
+ // QUIRK: sometimes we get a path component like /{nextLink}
+ // which may be a fully formed URL with a leading /. In that case, we should
+ // remove the leading /
+ if (operationSpec.path === "/{nextLink}" && path.startsWith("/")) {
+ path = path.substring(1);
+ }
+ // QUIRK: sometimes we get a path component like {nextLink}
+ // which may be a fully formed URL. In that case, we should
+ // ignore the baseUri.
+ if (isAbsoluteUrl(path)) {
+ requestUrl = path;
+ isAbsolutePath = true;
+ }
+ else {
+ requestUrl = appendPath(requestUrl, path);
+ }
+ }
+ const { queryParams, sequenceParams } = calculateQueryParameters(operationSpec, operationArguments, fallbackObject);
+ /**
+ * Notice that this call sets the `noOverwrite` parameter to true if the `requestUrl`
+ * is an absolute path. This ensures that existing query parameter values in `requestUrl`
+ * do not get overwritten. On the other hand when `requestUrl` is not absolute path, it
+ * is still being built so there is nothing to overwrite.
+ */
+ requestUrl = appendQueryParams(requestUrl, queryParams, sequenceParams, isAbsolutePath);
+ return requestUrl;
+}
+function replaceAll(input, replacements) {
+ let result = input;
+ for (const [searchValue, replaceValue] of replacements) {
+ result = result.split(searchValue).join(replaceValue);
+ }
+ return result;
+}
+function calculateUrlReplacements(operationSpec, operationArguments, fallbackObject) {
+ const result = new Map();
+ if (operationSpec.urlParameters?.length) {
+ for (const urlParameter of operationSpec.urlParameters) {
+ let urlParameterValue = getOperationArgumentValueFromParameter(operationArguments, urlParameter, fallbackObject);
+ const parameterPathString = getPathStringFromParameter(urlParameter);
+ urlParameterValue = operationSpec.serializer.serialize(urlParameter.mapper, urlParameterValue, parameterPathString);
+ if (!urlParameter.skipEncoding) {
+ urlParameterValue = encodeURIComponent(urlParameterValue);
+ }
+ result.set(`{${urlParameter.mapper.serializedName || parameterPathString}}`, urlParameterValue);
+ }
+ }
+ return result;
+}
+function isAbsoluteUrl(url) {
+ return url.includes("://");
+}
+function appendPath(url, pathToAppend) {
+ if (!pathToAppend) {
+ return url;
+ }
+ const parsedUrl = new URL(url);
+ let newPath = parsedUrl.pathname;
+ if (!newPath.endsWith("/")) {
+ newPath = `${newPath}/`;
+ }
+ if (pathToAppend.startsWith("/")) {
+ pathToAppend = pathToAppend.substring(1);
+ }
+ const searchStart = pathToAppend.indexOf("?");
+ if (searchStart !== -1) {
+ const path = pathToAppend.substring(0, searchStart);
+ const search = pathToAppend.substring(searchStart + 1);
+ newPath = newPath + path;
+ if (search) {
+ parsedUrl.search = parsedUrl.search ? `${parsedUrl.search}&${search}` : search;
+ }
+ }
+ else {
+ newPath = newPath + pathToAppend;
+ }
+ // Use Object.assign to bypass react-native's incorrect readonly URL.pathname declaration
+ Object.assign(parsedUrl, { pathname: newPath });
+ return parsedUrl.toString();
+}
+function calculateQueryParameters(operationSpec, operationArguments, fallbackObject) {
+ const result = new Map();
+ const sequenceParams = new Set();
+ if (operationSpec.queryParameters?.length) {
+ for (const queryParameter of operationSpec.queryParameters) {
+ if (queryParameter.mapper.type.name === "Sequence" && queryParameter.mapper.serializedName) {
+ sequenceParams.add(queryParameter.mapper.serializedName);
+ }
+ let queryParameterValue = getOperationArgumentValueFromParameter(operationArguments, queryParameter, fallbackObject);
+ if ((queryParameterValue !== undefined && queryParameterValue !== null) ||
+ queryParameter.mapper.required) {
+ queryParameterValue = operationSpec.serializer.serialize(queryParameter.mapper, queryParameterValue, getPathStringFromParameter(queryParameter));
+ const delimiter = queryParameter.collectionFormat
+ ? CollectionFormatToDelimiterMap[queryParameter.collectionFormat]
+ : "";
+ if (Array.isArray(queryParameterValue)) {
+ // replace null and undefined
+ queryParameterValue = queryParameterValue.map((item) => {
+ if (item === null || item === undefined) {
+ return "";
+ }
+ return item;
+ });
+ }
+ if (queryParameter.collectionFormat === "Multi" && queryParameterValue.length === 0) {
+ continue;
+ }
+ else if (Array.isArray(queryParameterValue) &&
+ (queryParameter.collectionFormat === "SSV" || queryParameter.collectionFormat === "TSV")) {
+ queryParameterValue = queryParameterValue.join(delimiter);
+ }
+ if (!queryParameter.skipEncoding) {
+ if (Array.isArray(queryParameterValue)) {
+ queryParameterValue = queryParameterValue.map((item) => {
+ return encodeURIComponent(item);
+ });
+ }
+ else {
+ queryParameterValue = encodeURIComponent(queryParameterValue);
+ }
+ }
+ // Join pipes and CSV *after* encoding, or the server will be upset.
+ if (Array.isArray(queryParameterValue) &&
+ (queryParameter.collectionFormat === "CSV" || queryParameter.collectionFormat === "Pipes")) {
+ queryParameterValue = queryParameterValue.join(delimiter);
+ }
+ result.set(queryParameter.mapper.serializedName || getPathStringFromParameter(queryParameter), queryParameterValue);
+ }
+ }
+ }
+ return {
+ queryParams: result,
+ sequenceParams,
+ };
+}
+function simpleParseQueryParams(queryString) {
+ const result = new Map();
+ if (!queryString || queryString[0] !== "?") {
+ return result;
+ }
+ // remove the leading ?
+ queryString = queryString.slice(1);
+ const pairs = queryString.split("&");
+ for (const pair of pairs) {
+ const [name, value] = pair.split("=", 2);
+ const existingValue = result.get(name);
+ if (existingValue) {
+ if (Array.isArray(existingValue)) {
+ existingValue.push(value);
+ }
+ else {
+ result.set(name, [existingValue, value]);
+ }
+ }
+ else {
+ result.set(name, value);
+ }
+ }
+ return result;
+}
+/** @internal */
+function appendQueryParams(url, queryParams, sequenceParams, noOverwrite = false) {
+ if (queryParams.size === 0) {
+ return url;
+ }
+ const parsedUrl = new URL(url);
+ // QUIRK: parsedUrl.searchParams will have their name/value pairs decoded, which
+ // can change their meaning to the server, such as in the case of a SAS signature.
+ // To avoid accidentally un-encoding a query param, we parse the key/values ourselves
+ const combinedParams = simpleParseQueryParams(parsedUrl.search);
+ for (const [name, value] of queryParams) {
+ const existingValue = combinedParams.get(name);
+ if (Array.isArray(existingValue)) {
+ if (Array.isArray(value)) {
+ existingValue.push(...value);
+ const valueSet = new Set(existingValue);
+ combinedParams.set(name, Array.from(valueSet));
+ }
+ else {
+ existingValue.push(value);
+ }
+ }
+ else if (existingValue) {
+ if (Array.isArray(value)) {
+ value.unshift(existingValue);
+ }
+ else if (sequenceParams.has(name)) {
+ combinedParams.set(name, [existingValue, value]);
+ }
+ if (!noOverwrite) {
+ combinedParams.set(name, value);
+ }
+ }
+ else {
+ combinedParams.set(name, value);
+ }
+ }
+ const searchPieces = [];
+ for (const [name, value] of combinedParams) {
+ if (typeof value === "string") {
+ searchPieces.push(`${name}=${value}`);
+ }
+ else if (Array.isArray(value)) {
+ // QUIRK: If we get an array of values, include multiple key/value pairs
+ for (const subValue of value) {
+ searchPieces.push(`${name}=${subValue}`);
+ }
+ }
+ else {
+ searchPieces.push(`${name}=${value}`);
+ }
+ }
+ // QUIRK: we have to set search manually as searchParams will encode comma when it shouldn't.
+ parsedUrl.search = searchPieces.length ? `?${searchPieces.join("&")}` : "";
+ return parsedUrl.toString();
+}
+//# sourceMappingURL=urlHelpers.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/log.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+const dist_esm_log_logger = esm_createClientLogger("core-client");
+//# sourceMappingURL=log.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/serviceClient.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+/**
+ * Initializes a new instance of the ServiceClient.
+ */
+class ServiceClient {
+ /**
+ * If specified, this is the base URI that requests will be made against for this ServiceClient.
+ * If it is not specified, then all OperationSpecs must contain a baseUrl property.
+ */
+ _endpoint;
+ /**
+ * The default request content type for the service.
+ * Used if no requestContentType is present on an OperationSpec.
+ */
+ _requestContentType;
+ /**
+ * Set to true if the request is sent over HTTP instead of HTTPS
+ */
+ _allowInsecureConnection;
+ /**
+ * The HTTP client that will be used to send requests.
+ */
+ _httpClient;
+ /**
+ * The pipeline used by this client to make requests
+ */
+ pipeline;
+ /**
+ * The ServiceClient constructor
+ * @param options - The service client options that govern the behavior of the client.
+ */
+ constructor(options = {}) {
+ this._requestContentType = options.requestContentType;
+ this._endpoint = options.endpoint ?? options.baseUri;
+ if (options.baseUri) {
+ dist_esm_log_logger.warning("The baseUri option for SDK Clients has been deprecated, please use endpoint instead.");
+ }
+ this._allowInsecureConnection = options.allowInsecureConnection;
+ this._httpClient = options.httpClient || getCachedDefaultHttpClient();
+ this.pipeline = options.pipeline || serviceClient_createDefaultPipeline(options);
+ if (options.additionalPolicies?.length) {
+ for (const { policy, position } of options.additionalPolicies) {
+ // Sign happens after Retry and is commonly needed to occur
+ // before policies that intercept post-retry.
+ const afterPhase = position === "perRetry" ? "Sign" : undefined;
+ this.pipeline.addPolicy(policy, {
+ afterPhase,
+ });
+ }
+ }
+ }
+ /**
+ * Send the provided httpRequest.
+ */
+ sendRequest(request) {
+ return this.pipeline.sendRequest(this._httpClient, request);
+ }
+ /**
+ * Send an HTTP request that is populated using the provided OperationSpec.
+ * @typeParam T - The typed result of the request, based on the OperationSpec.
+ * @param operationArguments - The arguments that the HTTP request's templated values will be populated from.
+ * @param operationSpec - The OperationSpec to use to populate the httpRequest.
+ */
+ async sendOperationRequest(operationArguments, operationSpec) {
+ const endpoint = operationSpec.baseUrl || this._endpoint;
+ if (!endpoint) {
+ throw new Error("If operationSpec.baseUrl is not specified, then the ServiceClient must have a endpoint string property that contains the base URL to use.");
+ }
+ // Templatized URLs sometimes reference properties on the ServiceClient child class,
+ // so we have to pass `this` below in order to search these properties if they're
+ // not part of OperationArguments
+ const url = getRequestUrl(endpoint, operationSpec, operationArguments, this);
+ const request = esm_pipelineRequest_createPipelineRequest({
+ url,
+ });
+ request.method = operationSpec.httpMethod;
+ const operationInfo = getOperationRequestInfo(request);
+ operationInfo.operationSpec = operationSpec;
+ operationInfo.operationArguments = operationArguments;
+ const contentType = operationSpec.contentType || this._requestContentType;
+ if (contentType && operationSpec.requestBody) {
+ request.headers.set("Content-Type", contentType);
+ }
+ const options = operationArguments.options;
+ if (options) {
+ const requestOptions = options.requestOptions;
+ if (requestOptions) {
+ if (requestOptions.timeout) {
+ request.timeout = requestOptions.timeout;
+ }
+ if (requestOptions.onUploadProgress) {
+ request.onUploadProgress = requestOptions.onUploadProgress;
+ }
+ if (requestOptions.onDownloadProgress) {
+ request.onDownloadProgress = requestOptions.onDownloadProgress;
+ }
+ if (requestOptions.shouldDeserialize !== undefined) {
+ operationInfo.shouldDeserialize = requestOptions.shouldDeserialize;
+ }
+ if (requestOptions.allowInsecureConnection) {
+ request.allowInsecureConnection = true;
+ }
+ }
+ if (options.abortSignal) {
+ request.abortSignal = options.abortSignal;
+ }
+ if (options.tracingOptions) {
+ request.tracingOptions = options.tracingOptions;
+ }
+ }
+ if (this._allowInsecureConnection) {
+ request.allowInsecureConnection = true;
+ }
+ if (request.streamResponseStatusCodes === undefined) {
+ request.streamResponseStatusCodes = getStreamingResponseStatusCodes(operationSpec);
+ }
+ try {
+ const rawResponse = await this.sendRequest(request);
+ const flatResponse = flattenResponse(rawResponse, operationSpec.responses[rawResponse.status]);
+ if (options?.onResponse) {
+ options.onResponse(rawResponse, flatResponse);
+ }
+ return flatResponse;
+ }
+ catch (error) {
+ if (typeof error === "object" && error?.response) {
+ const rawResponse = error.response;
+ const flatResponse = flattenResponse(rawResponse, operationSpec.responses[error.statusCode] || operationSpec.responses["default"]);
+ error.details = flatResponse;
+ if (options?.onResponse) {
+ options.onResponse(rawResponse, flatResponse, error);
+ }
+ }
+ throw error;
+ }
+ }
+}
+function serviceClient_createDefaultPipeline(options) {
+ const credentialScopes = getCredentialScopes(options);
+ const credentialOptions = options.credential && credentialScopes
+ ? { credentialScopes, credential: options.credential }
+ : undefined;
+ return createClientPipeline({
+ ...options,
+ credentialOptions,
+ });
+}
+function getCredentialScopes(options) {
+ if (options.credentialScopes) {
+ return options.credentialScopes;
+ }
+ if (options.endpoint) {
+ return `${options.endpoint}/.default`;
+ }
+ if (options.baseUri) {
+ return `${options.baseUri}/.default`;
+ }
+ if (options.credential) {
+ throw new Error(`When using credentials, the ServiceClientOptions must contain either a endpoint or a credentialScopes. Unable to create a bearerTokenAuthenticationPolicy`);
+ }
+ return undefined;
+}
+//# sourceMappingURL=serviceClient.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/authorizeRequestOnClaimChallenge.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * Converts: `Bearer a="b", c="d", Bearer d="e", f="g"`.
+ * Into: `[ { a: 'b', c: 'd' }, { d: 'e', f: 'g' } ]`.
+ *
+ * @internal
+ */
+function parseCAEChallenge(challenges) {
+ const bearerChallenges = `, ${challenges.trim()}`.split(", Bearer ").filter((x) => x);
+ return bearerChallenges.map((challenge) => {
+ const challengeParts = `${challenge.trim()}, `.split('", ').filter((x) => x);
+ const keyValuePairs = challengeParts.map((keyValue) => (([key, value]) => ({ [key]: value }))(keyValue.trim().split('="')));
+ // Key-value pairs to plain object:
+ return keyValuePairs.reduce((a, b) => ({ ...a, ...b }), {});
+ });
+}
+/**
+ * This function can be used as a callback for the `bearerTokenAuthenticationPolicy` of `@azure/core-rest-pipeline`, to support CAE challenges:
+ * [Continuous Access Evaluation](https://learn.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation).
+ *
+ * Call the `bearerTokenAuthenticationPolicy` with the following options:
+ *
+ * ```ts snippet:AuthorizeRequestOnClaimChallenge
+ * import { bearerTokenAuthenticationPolicy } from "@azure/core-rest-pipeline";
+ * import { authorizeRequestOnClaimChallenge } from "@azure/core-client";
+ *
+ * const policy = bearerTokenAuthenticationPolicy({
+ * challengeCallbacks: {
+ * authorizeRequestOnChallenge: authorizeRequestOnClaimChallenge,
+ * },
+ * scopes: ["https://service/.default"],
+ * });
+ * ```
+ *
+ * Once provided, the `bearerTokenAuthenticationPolicy` policy will internally handle Continuous Access Evaluation (CAE) challenges.
+ * When it can't complete a challenge it will return the 401 (unauthorized) response from ARM.
+ *
+ * Example challenge with claims:
+ *
+ * ```
+ * Bearer authorization_uri="https://login.windows-ppe.net/", error="invalid_token",
+ * error_description="User session has been revoked",
+ * claims="eyJhY2Nlc3NfdG9rZW4iOnsibmJmIjp7ImVzc2VudGlhbCI6dHJ1ZSwgInZhbHVlIjoiMTYwMzc0MjgwMCJ9fX0="
+ * ```
+ */
+async function authorizeRequestOnClaimChallenge(onChallengeOptions) {
+ const { scopes, response } = onChallengeOptions;
+ const logger = onChallengeOptions.logger || coreClientLogger;
+ const challenge = response.headers.get("WWW-Authenticate");
+ if (!challenge) {
+ logger.info(`The WWW-Authenticate header was missing. Failed to perform the Continuous Access Evaluation authentication flow.`);
+ return false;
+ }
+ const challenges = parseCAEChallenge(challenge) || [];
+ const parsedChallenge = challenges.find((x) => x.claims);
+ if (!parsedChallenge) {
+ logger.info(`The WWW-Authenticate header was missing the necessary "claims" to perform the Continuous Access Evaluation authentication flow.`);
+ return false;
+ }
+ const accessToken = await onChallengeOptions.getAccessToken(parsedChallenge.scope ? [parsedChallenge.scope] : scopes, {
+ claims: decodeStringToString(parsedChallenge.claims),
+ });
+ if (!accessToken) {
+ return false;
+ }
+ onChallengeOptions.request.headers.set("Authorization", `${accessToken.tokenType ?? "Bearer"} ${accessToken.token}`);
+ return true;
+}
+//# sourceMappingURL=authorizeRequestOnClaimChallenge.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/authorizeRequestOnTenantChallenge.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * A set of constants used internally when processing requests.
+ */
+const Constants = {
+ DefaultScope: "/.default",
+ /**
+ * Defines constants for use with HTTP headers.
+ */
+ HeaderConstants: {
+ /**
+ * The Authorization header.
+ */
+ AUTHORIZATION: "authorization",
+ },
+};
+function isUuid(text) {
+ return /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/.test(text);
+}
+/**
+ * Defines a callback to handle auth challenge for Storage APIs.
+ * This implements the bearer challenge process described here: https://learn.microsoft.com/rest/api/storageservices/authorize-with-azure-active-directory#bearer-challenge
+ * Handling has specific features for storage that departs to the general AAD challenge docs.
+ **/
+const authorizeRequestOnTenantChallenge = async (challengeOptions) => {
+ const requestOptions = requestToOptions(challengeOptions.request);
+ const challenge = getChallenge(challengeOptions.response);
+ if (challenge) {
+ const challengeInfo = parseChallenge(challenge);
+ const challengeScopes = buildScopes(challengeOptions, challengeInfo);
+ const tenantId = extractTenantId(challengeInfo);
+ if (!tenantId) {
+ return false;
+ }
+ const accessToken = await challengeOptions.getAccessToken(challengeScopes, {
+ ...requestOptions,
+ tenantId,
+ });
+ if (!accessToken) {
+ return false;
+ }
+ challengeOptions.request.headers.set(Constants.HeaderConstants.AUTHORIZATION, `${accessToken.tokenType ?? "Bearer"} ${accessToken.token}`);
+ return true;
+ }
+ return false;
+};
+/**
+ * Extracts the tenant id from the challenge information
+ * The tenant id is contained in the authorization_uri as the first
+ * path part.
+ */
+function extractTenantId(challengeInfo) {
+ const parsedAuthUri = new URL(challengeInfo.authorization_uri);
+ const pathSegments = parsedAuthUri.pathname.split("/");
+ const tenantId = pathSegments[1];
+ if (tenantId && isUuid(tenantId)) {
+ return tenantId;
+ }
+ return undefined;
+}
+/**
+ * Builds the authentication scopes based on the information that comes in the
+ * challenge information. Scopes url is present in the resource_id, if it is empty
+ * we keep using the original scopes.
+ */
+function buildScopes(challengeOptions, challengeInfo) {
+ if (!challengeInfo.resource_id) {
+ return challengeOptions.scopes;
+ }
+ const challengeScopes = new URL(challengeInfo.resource_id);
+ let scope = new URL(Constants.DefaultScope, challengeScopes.origin).toString();
+ if (scope === "https://disk.azure.com/.default") {
+ // the extra slash is required by the service
+ scope = "https://disk.azure.com//.default";
+ }
+ return [scope];
+}
+/**
+ * We will retrieve the challenge only if the response status code was 401,
+ * and if the response contained the header "WWW-Authenticate" with a non-empty value.
+ */
+function getChallenge(response) {
+ const challenge = response.headers.get("WWW-Authenticate");
+ if (response.status === 401 && challenge) {
+ return challenge;
+ }
+ return;
+}
+/**
+ * Converts: `Bearer a="b" c="d"`.
+ * Into: `[ { a: 'b', c: 'd' }]`.
+ *
+ * @internal
+ */
+function parseChallenge(challenge) {
+ const bearerChallenge = challenge.slice("Bearer ".length);
+ const challengeParts = `${bearerChallenge.trim()} `.split(" ").filter((x) => x);
+ const keyValuePairs = challengeParts.map((keyValue) => (([key, value]) => ({ [key]: value }))(keyValue.trim().split("=")));
+ // Key-value pairs to plain object:
+ return keyValuePairs.reduce((a, b) => ({ ...a, ...b }), {});
+}
+/**
+ * Extracts the options form a Pipeline Request for later re-use
+ */
+function requestToOptions(request) {
+ return {
+ abortSignal: request.abortSignal,
+ requestOptions: {
+ timeout: request.timeout,
+ },
+ tracingOptions: request.tracingOptions,
+ };
+}
+//# sourceMappingURL=authorizeRequestOnTenantChallenge.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-client/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+
+
+
+
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-http-compat/dist/esm/util.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// We use a custom symbol to cache a reference to the original request without
+// exposing it on the public interface.
+const util_originalRequestSymbol = Symbol("Original PipelineRequest");
+// Symbol.for() will return the same symbol if it's already been created
+// This particular one is used in core-client to handle the case of when a request is
+// cloned but we need to retrieve the OperationSpec and OperationArguments from the
+// original request.
+const originalClientRequestSymbol = Symbol.for("@azure/core-client original request");
+const passThroughProps = new Set([
+ "url",
+ "method",
+ "withCredentials",
+ "timeout",
+ "requestId",
+ "abortSignal",
+ "body",
+ "formData",
+ "onDownloadProgress",
+ "onUploadProgress",
+ "proxySettings",
+ "streamResponseStatusCodes",
+ "agent",
+ "requestOverrides",
+]);
+function toPipelineRequest(webResource, options = {}) {
+ const compatWebResource = webResource;
+ const request = compatWebResource[util_originalRequestSymbol];
+ const headers = esm_httpHeaders_createHttpHeaders(webResource.headers.toJson({ preserveCase: true }));
+ if (request) {
+ request.headers = headers;
+ return request;
+ }
+ else {
+ const newRequest = esm_pipelineRequest_createPipelineRequest({
+ url: webResource.url,
+ method: webResource.method,
+ headers,
+ withCredentials: webResource.withCredentials,
+ timeout: webResource.timeout,
+ requestId: webResource.requestId,
+ abortSignal: webResource.abortSignal,
+ body: webResource.body,
+ formData: webResource.formData,
+ disableKeepAlive: !!webResource.keepAlive,
+ onDownloadProgress: webResource.onDownloadProgress,
+ onUploadProgress: webResource.onUploadProgress,
+ proxySettings: webResource.proxySettings,
+ streamResponseStatusCodes: webResource.streamResponseStatusCodes,
+ agent: webResource.agent,
+ requestOverrides: webResource.requestOverrides,
+ });
+ if (options.originalRequest) {
+ newRequest[originalClientRequestSymbol] =
+ options.originalRequest;
+ }
+ return newRequest;
+ }
+}
+function toWebResourceLike(request, options) {
+ const originalRequest = options?.originalRequest ?? request;
+ const webResource = {
+ url: request.url,
+ method: request.method,
+ headers: toHttpHeadersLike(request.headers),
+ withCredentials: request.withCredentials,
+ timeout: request.timeout,
+ requestId: request.headers.get("x-ms-client-request-id") || request.requestId,
+ abortSignal: request.abortSignal,
+ body: request.body,
+ formData: request.formData,
+ keepAlive: !!request.disableKeepAlive,
+ onDownloadProgress: request.onDownloadProgress,
+ onUploadProgress: request.onUploadProgress,
+ proxySettings: request.proxySettings,
+ streamResponseStatusCodes: request.streamResponseStatusCodes,
+ agent: request.agent,
+ requestOverrides: request.requestOverrides,
+ clone() {
+ throw new Error("Cannot clone a non-proxied WebResourceLike");
+ },
+ prepare() {
+ throw new Error("WebResourceLike.prepare() is not supported by @azure/core-http-compat");
+ },
+ validateRequestProperties() {
+ /** do nothing */
+ },
+ };
+ if (options?.createProxy) {
+ return new Proxy(webResource, {
+ get(target, prop, receiver) {
+ if (prop === util_originalRequestSymbol) {
+ return request;
+ }
+ else if (prop === "clone") {
+ return () => {
+ return toWebResourceLike(toPipelineRequest(webResource, { originalRequest }), {
+ createProxy: true,
+ originalRequest,
+ });
+ };
+ }
+ return Reflect.get(target, prop, receiver);
+ },
+ set(target, prop, value, receiver) {
+ if (prop === "keepAlive") {
+ request.disableKeepAlive = !value;
+ }
+ if (typeof prop === "string" && passThroughProps.has(prop)) {
+ request[prop] = value;
+ }
+ return Reflect.set(target, prop, value, receiver);
+ },
+ });
+ }
+ else {
+ return webResource;
+ }
+}
+/**
+ * Converts HttpHeaders from core-rest-pipeline to look like
+ * HttpHeaders from core-http.
+ * @param headers - HttpHeaders from core-rest-pipeline
+ * @returns HttpHeaders as they looked in core-http
+ */
+function toHttpHeadersLike(headers) {
+ return new HttpHeaders(headers.toJSON({ preserveCase: true }));
+}
+/**
+ * A collection of HttpHeaders that can be sent with a HTTP request.
+ */
+function getHeaderKey(headerName) {
+ return headerName.toLowerCase();
+}
+/**
+ * A collection of HTTP header key/value pairs.
+ */
+class HttpHeaders {
+ _headersMap;
+ constructor(rawHeaders) {
+ this._headersMap = {};
+ if (rawHeaders) {
+ for (const headerName in rawHeaders) {
+ this.set(headerName, rawHeaders[headerName]);
+ }
+ }
+ }
+ /**
+ * Set a header in this collection with the provided name and value. The name is
+ * case-insensitive.
+ * @param headerName - The name of the header to set. This value is case-insensitive.
+ * @param headerValue - The value of the header to set.
+ */
+ set(headerName, headerValue) {
+ this._headersMap[getHeaderKey(headerName)] = {
+ name: headerName,
+ value: headerValue.toString(),
+ };
+ }
+ /**
+ * Get the header value for the provided header name, or undefined if no header exists in this
+ * collection with the provided name.
+ * @param headerName - The name of the header.
+ */
+ get(headerName) {
+ const header = this._headersMap[getHeaderKey(headerName)];
+ return !header ? undefined : header.value;
+ }
+ /**
+ * Get whether or not this header collection contains a header entry for the provided header name.
+ */
+ contains(headerName) {
+ return !!this._headersMap[getHeaderKey(headerName)];
+ }
+ /**
+ * Remove the header with the provided headerName. Return whether or not the header existed and
+ * was removed.
+ * @param headerName - The name of the header to remove.
+ */
+ remove(headerName) {
+ const result = this.contains(headerName);
+ delete this._headersMap[getHeaderKey(headerName)];
+ return result;
+ }
+ /**
+ * Get the headers that are contained this collection as an object.
+ */
+ rawHeaders() {
+ return this.toJson({ preserveCase: true });
+ }
+ /**
+ * Get the headers that are contained in this collection as an array.
+ */
+ headersArray() {
+ const headers = [];
+ for (const headerKey in this._headersMap) {
+ headers.push(this._headersMap[headerKey]);
+ }
+ return headers;
+ }
+ /**
+ * Get the header names that are contained in this collection.
+ */
+ headerNames() {
+ const headerNames = [];
+ const headers = this.headersArray();
+ for (let i = 0; i < headers.length; ++i) {
+ headerNames.push(headers[i].name);
+ }
+ return headerNames;
+ }
+ /**
+ * Get the header values that are contained in this collection.
+ */
+ headerValues() {
+ const headerValues = [];
+ const headers = this.headersArray();
+ for (let i = 0; i < headers.length; ++i) {
+ headerValues.push(headers[i].value);
+ }
+ return headerValues;
+ }
+ /**
+ * Get the JSON object representation of this HTTP header collection.
+ */
+ toJson(options = {}) {
+ const result = {};
+ if (options.preserveCase) {
+ for (const headerKey in this._headersMap) {
+ const header = this._headersMap[headerKey];
+ result[header.name] = header.value;
+ }
+ }
+ else {
+ for (const headerKey in this._headersMap) {
+ const header = this._headersMap[headerKey];
+ result[getHeaderKey(header.name)] = header.value;
+ }
+ }
+ return result;
+ }
+ /**
+ * Get the string representation of this HTTP header collection.
+ */
+ toString() {
+ return JSON.stringify(this.toJson({ preserveCase: true }));
+ }
+ /**
+ * Create a deep clone/copy of this HttpHeaders collection.
+ */
+ clone() {
+ const resultPreservingCasing = {};
+ for (const headerKey in this._headersMap) {
+ const header = this._headersMap[headerKey];
+ resultPreservingCasing[header.name] = header.value;
+ }
+ return new HttpHeaders(resultPreservingCasing);
+ }
+}
+//# sourceMappingURL=util.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-http-compat/dist/esm/response.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+const originalResponse = Symbol("Original FullOperationResponse");
+/**
+ * A helper to convert response objects from the new pipeline back to the old one.
+ * @param response - A response object from core-client.
+ * @returns A response compatible with `HttpOperationResponse` from core-http.
+ */
+function toCompatResponse(response, options) {
+ let request = toWebResourceLike(response.request);
+ let headers = toHttpHeadersLike(response.headers);
+ if (options?.createProxy) {
+ return new Proxy(response, {
+ get(target, prop, receiver) {
+ if (prop === "headers") {
+ return headers;
+ }
+ else if (prop === "request") {
+ return request;
+ }
+ else if (prop === originalResponse) {
+ return response;
+ }
+ return Reflect.get(target, prop, receiver);
+ },
+ set(target, prop, value, receiver) {
+ if (prop === "headers") {
+ headers = value;
+ }
+ else if (prop === "request") {
+ request = value;
+ }
+ return Reflect.set(target, prop, value, receiver);
+ },
+ });
+ }
+ else {
+ return {
+ ...response,
+ request,
+ headers,
+ };
+ }
+}
+/**
+ * A helper to convert back to a PipelineResponse
+ * @param compatResponse - A response compatible with `HttpOperationResponse` from core-http.
+ */
+function response_toPipelineResponse(compatResponse) {
+ const extendedCompatResponse = compatResponse;
+ const response = extendedCompatResponse[originalResponse];
+ const headers = esm_httpHeaders_createHttpHeaders(compatResponse.headers.toJson({ preserveCase: true }));
+ if (response) {
+ response.headers = headers;
+ return response;
+ }
+ else {
+ return {
+ ...compatResponse,
+ headers,
+ request: toPipelineRequest(compatResponse.request),
+ };
+ }
+}
+//# sourceMappingURL=response.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-http-compat/dist/esm/extendedClient.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+
+
+/**
+ * Client to provide compatability between core V1 & V2.
+ */
+class ExtendedServiceClient extends ServiceClient {
+ constructor(options) {
+ super(options);
+ if (options.keepAliveOptions?.enable === false &&
+ !pipelineContainsDisableKeepAlivePolicy(this.pipeline)) {
+ this.pipeline.addPolicy(createDisableKeepAlivePolicy());
+ }
+ if (options.redirectOptions?.handleRedirects === false) {
+ this.pipeline.removePolicy({
+ name: redirectPolicy_redirectPolicyName,
+ });
+ }
+ }
+ /**
+ * Compatible send operation request function.
+ *
+ * @param operationArguments - Operation arguments
+ * @param operationSpec - Operation Spec
+ * @returns
+ */
+ async sendOperationRequest(operationArguments, operationSpec) {
+ const userProvidedCallBack = operationArguments?.options?.onResponse;
+ let lastResponse;
+ function onResponse(rawResponse, flatResponse, error) {
+ lastResponse = rawResponse;
+ if (userProvidedCallBack) {
+ userProvidedCallBack(rawResponse, flatResponse, error);
+ }
+ }
+ operationArguments.options = {
+ ...operationArguments.options,
+ onResponse,
+ };
+ const result = await super.sendOperationRequest(operationArguments, operationSpec);
+ if (lastResponse) {
+ Object.defineProperty(result, "_response", {
+ value: toCompatResponse(lastResponse),
+ });
+ }
+ return result;
+ }
+}
+//# sourceMappingURL=extendedClient.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-http-compat/dist/esm/policies/requestPolicyFactoryPolicy.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * An enum for compatibility with RequestPolicy
+ */
+var HttpPipelineLogLevel;
+(function (HttpPipelineLogLevel) {
+ HttpPipelineLogLevel[HttpPipelineLogLevel["ERROR"] = 1] = "ERROR";
+ HttpPipelineLogLevel[HttpPipelineLogLevel["INFO"] = 3] = "INFO";
+ HttpPipelineLogLevel[HttpPipelineLogLevel["OFF"] = 0] = "OFF";
+ HttpPipelineLogLevel[HttpPipelineLogLevel["WARNING"] = 2] = "WARNING";
+})(HttpPipelineLogLevel || (HttpPipelineLogLevel = {}));
+const mockRequestPolicyOptions = {
+ log(_logLevel, _message) {
+ /* do nothing */
+ },
+ shouldLog(_logLevel) {
+ return false;
+ },
+};
+/**
+ * The name of the RequestPolicyFactoryPolicy
+ */
+const requestPolicyFactoryPolicyName = "RequestPolicyFactoryPolicy";
+/**
+ * A policy that wraps policies written for core-http.
+ * @param factories - An array of `RequestPolicyFactory` objects from a core-http pipeline
+ */
+function createRequestPolicyFactoryPolicy(factories) {
+ const orderedFactories = factories.slice().reverse();
+ return {
+ name: requestPolicyFactoryPolicyName,
+ async sendRequest(request, next) {
+ let httpPipeline = {
+ async sendRequest(httpRequest) {
+ const response = await next(toPipelineRequest(httpRequest));
+ return toCompatResponse(response, { createProxy: true });
+ },
+ };
+ for (const factory of orderedFactories) {
+ httpPipeline = factory.create(httpPipeline, mockRequestPolicyOptions);
+ }
+ const webResourceLike = toWebResourceLike(request, { createProxy: true });
+ const response = await httpPipeline.sendRequest(webResourceLike);
+ return response_toPipelineResponse(response);
+ },
+ };
+}
+//# sourceMappingURL=requestPolicyFactoryPolicy.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-http-compat/dist/esm/httpClientAdapter.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+
+/**
+ * Converts a RequestPolicy based HttpClient to a PipelineRequest based HttpClient.
+ * @param requestPolicyClient - A HttpClient compatible with core-http
+ * @returns A HttpClient compatible with core-rest-pipeline
+ */
+function convertHttpClient(requestPolicyClient) {
+ return {
+ sendRequest: async (request) => {
+ const response = await requestPolicyClient.sendRequest(toWebResourceLike(request, { createProxy: true }));
+ return response_toPipelineResponse(response);
+ },
+ };
+}
+//# sourceMappingURL=httpClientAdapter.js.map
+;// CONCATENATED MODULE: ./node_modules/@azure/core-http-compat/dist/esm/index.js
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+/**
+ * A Shim Library that provides compatibility between Core V1 & V2 Packages.
+ *
+ * @packageDocumentation
+ */
+
+
+
+
+
+
+//# sourceMappingURL=index.js.map
+;// CONCATENATED MODULE: ./node_modules/path-expression-matcher/src/Expression.js
+/**
+ * Expression - Parses and stores a tag pattern expression
+ *
+ * Patterns are parsed once and stored in an optimized structure for fast matching.
+ *
+ * @example
+ * const expr = new Expression("root.users.user");
+ * const expr2 = new Expression("..user[id]:first");
+ * const expr3 = new Expression("root/users/user", { separator: '/' });
+ */
+class Expression {
+ /**
+ * Create a new Expression
+ * @param {string} pattern - Pattern string (e.g., "root.users.user", "..user[id]")
+ * @param {Object} options - Configuration options
+ * @param {string} options.separator - Path separator (default: '.')
+ */
+ constructor(pattern, options = {}, data) {
+ this.pattern = pattern;
+ this.separator = options.separator || '.';
+ this.segments = this._parse(pattern);
+ this.data = data;
+ // Cache expensive checks for performance (O(1) instead of O(n))
+ this._hasDeepWildcard = this.segments.some(seg => seg.type === 'deep-wildcard');
+ this._hasAttributeCondition = this.segments.some(seg => seg.attrName !== undefined);
+ this._hasPositionSelector = this.segments.some(seg => seg.position !== undefined);
+ }
+
+ /**
+ * Parse pattern string into segments
+ * @private
+ * @param {string} pattern - Pattern to parse
+ * @returns {Array} Array of segment objects
+ */
+ _parse(pattern) {
+ const segments = [];
+
+ // Split by separator but handle ".." specially
+ let i = 0;
+ let currentPart = '';
+
+ while (i < pattern.length) {
+ if (pattern[i] === this.separator) {
+ // Check if next char is also separator (deep wildcard)
+ if (i + 1 < pattern.length && pattern[i + 1] === this.separator) {
+ // Flush current part if any
+ if (currentPart.trim()) {
+ segments.push(this._parseSegment(currentPart.trim()));
+ currentPart = '';
+ }
+ // Add deep wildcard
+ segments.push({ type: 'deep-wildcard' });
+ i += 2; // Skip both separators
+ } else {
+ // Regular separator
+ if (currentPart.trim()) {
+ segments.push(this._parseSegment(currentPart.trim()));
+ }
+ currentPart = '';
+ i++;
+ }
+ } else {
+ currentPart += pattern[i];
+ i++;
+ }
+ }
+
+ // Flush remaining part
+ if (currentPart.trim()) {
+ segments.push(this._parseSegment(currentPart.trim()));
+ }
+
+ return segments;
+ }
+
+ /**
+ * Parse a single segment
+ * @private
+ * @param {string} part - Segment string (e.g., "user", "ns::user", "user[id]", "ns::user:first")
+ * @returns {Object} Segment object
+ */
+ _parseSegment(part) {
+ const segment = { type: 'tag' };
+
+ // NEW NAMESPACE SYNTAX (v2.0):
+ // ============================
+ // Namespace uses DOUBLE colon (::)
+ // Position uses SINGLE colon (:)
+ //
+ // Examples:
+ // "user" → tag
+ // "user:first" → tag + position
+ // "user[id]" → tag + attribute
+ // "user[id]:first" → tag + attribute + position
+ // "ns::user" → namespace + tag
+ // "ns::user:first" → namespace + tag + position
+ // "ns::user[id]" → namespace + tag + attribute
+ // "ns::user[id]:first" → namespace + tag + attribute + position
+ // "ns::first" → namespace + tag named "first" (NO ambiguity!)
+ //
+ // This eliminates all ambiguity:
+ // :: = namespace separator
+ // : = position selector
+ // [] = attributes
+
+ // Step 1: Extract brackets [attr] or [attr=value]
+ let bracketContent = null;
+ let withoutBrackets = part;
+
+ const bracketMatch = part.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);
+ if (bracketMatch) {
+ withoutBrackets = bracketMatch[1] + bracketMatch[3];
+ if (bracketMatch[2]) {
+ const content = bracketMatch[2].slice(1, -1);
+ if (content) {
+ bracketContent = content;
+ }
+ }
+ }
+
+ // Step 2: Check for namespace (double colon ::)
+ let namespace = undefined;
+ let tagAndPosition = withoutBrackets;
+
+ if (withoutBrackets.includes('::')) {
+ const nsIndex = withoutBrackets.indexOf('::');
+ namespace = withoutBrackets.substring(0, nsIndex).trim();
+ tagAndPosition = withoutBrackets.substring(nsIndex + 2).trim(); // Skip ::
+
+ if (!namespace) {
+ throw new Error(`Invalid namespace in pattern: ${part}`);
+ }
+ }
+
+ // Step 3: Parse tag and position (single colon :)
+ let tag = undefined;
+ let positionMatch = null;
+
+ if (tagAndPosition.includes(':')) {
+ const colonIndex = tagAndPosition.lastIndexOf(':'); // Use last colon for position
+ const tagPart = tagAndPosition.substring(0, colonIndex).trim();
+ const posPart = tagAndPosition.substring(colonIndex + 1).trim();
+
+ // Verify position is a valid keyword
+ const isPositionKeyword = ['first', 'last', 'odd', 'even'].includes(posPart) ||
+ /^nth\(\d+\)$/.test(posPart);
+
+ if (isPositionKeyword) {
+ tag = tagPart;
+ positionMatch = posPart;
+ } else {
+ // Not a valid position keyword, treat whole thing as tag
+ tag = tagAndPosition;
+ }
+ } else {
+ tag = tagAndPosition;
+ }
+
+ if (!tag) {
+ throw new Error(`Invalid segment pattern: ${part}`);
+ }
+
+ segment.tag = tag;
+ if (namespace) {
+ segment.namespace = namespace;
+ }
+
+ // Step 4: Parse attributes
+ if (bracketContent) {
+ if (bracketContent.includes('=')) {
+ const eqIndex = bracketContent.indexOf('=');
+ segment.attrName = bracketContent.substring(0, eqIndex).trim();
+ segment.attrValue = bracketContent.substring(eqIndex + 1).trim();
+ } else {
+ segment.attrName = bracketContent.trim();
+ }
+ }
+
+ // Step 5: Parse position selector
+ if (positionMatch) {
+ const nthMatch = positionMatch.match(/^nth\((\d+)\)$/);
+ if (nthMatch) {
+ segment.position = 'nth';
+ segment.positionValue = parseInt(nthMatch[1], 10);
+ } else {
+ segment.position = positionMatch;
+ }
+ }
+
+ return segment;
+ }
+
+ /**
+ * Get the number of segments
+ * @returns {number}
+ */
+ get length() {
+ return this.segments.length;
+ }
+
+ /**
+ * Check if expression contains deep wildcard
+ * @returns {boolean}
+ */
+ hasDeepWildcard() {
+ return this._hasDeepWildcard;
+ }
+
+ /**
+ * Check if expression has attribute conditions
+ * @returns {boolean}
+ */
+ hasAttributeCondition() {
+ return this._hasAttributeCondition;
+ }
+
+ /**
+ * Check if expression has position selectors
+ * @returns {boolean}
+ */
+ hasPositionSelector() {
+ return this._hasPositionSelector;
+ }
+
+ /**
+ * Get string representation
+ * @returns {string}
+ */
+ toString() {
+ return this.pattern;
+ }
+}
+;// CONCATENATED MODULE: ./node_modules/path-expression-matcher/src/Matcher.js
+
+
+/**
+ * MatcherView - A lightweight read-only view over a Matcher's internal state.
+ *
+ * Created once by Matcher and reused across all callbacks. Holds a direct
+ * reference to the parent Matcher so it always reflects current parser state
+ * with zero copying or freezing overhead.
+ *
+ * Users receive this via {@link Matcher#readOnly} or directly from parser
+ * callbacks. It exposes all query and matching methods but has no mutation
+ * methods — misuse is caught at the TypeScript level rather than at runtime.
+ *
+ * @example
+ * const matcher = new Matcher();
+ * const view = matcher.readOnly();
+ *
+ * matcher.push("root", {});
+ * view.getCurrentTag(); // "root"
+ * view.getDepth(); // 1
+ */
+class MatcherView {
+ /**
+ * @param {Matcher} matcher - The parent Matcher instance to read from.
+ */
+ constructor(matcher) {
+ this._matcher = matcher;
+ }
+
+ /**
+ * Get the path separator used by the parent matcher.
+ * @returns {string}
+ */
+ get separator() {
+ return this._matcher.separator;
+ }
+
+ /**
+ * Get current tag name.
+ * @returns {string|undefined}
+ */
+ getCurrentTag() {
+ const path = this._matcher.path;
+ return path.length > 0 ? path[path.length - 1].tag : undefined;
+ }
+
+ /**
+ * Get current namespace.
+ * @returns {string|undefined}
+ */
+ getCurrentNamespace() {
+ const path = this._matcher.path;
+ return path.length > 0 ? path[path.length - 1].namespace : undefined;
+ }
+
+ /**
+ * Get current node's attribute value.
+ * @param {string} attrName
+ * @returns {*}
+ */
+ getAttrValue(attrName) {
+ const path = this._matcher.path;
+ if (path.length === 0) return undefined;
+ return path[path.length - 1].values?.[attrName];
+ }
+
+ /**
+ * Check if current node has an attribute.
+ * @param {string} attrName
+ * @returns {boolean}
+ */
+ hasAttr(attrName) {
+ const path = this._matcher.path;
+ if (path.length === 0) return false;
+ const current = path[path.length - 1];
+ return current.values !== undefined && attrName in current.values;
+ }
+
+ /**
+ * Get the value of a "kept" attribute from the nearest ancestor (or
+ * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
+ * @param {string} attrName
+ * @returns {*}
+ */
+ getAnyParentAttr(attrName) {
+ return this._matcher.getAnyParentAttr(attrName);
+ }
+
+ /**
+ * Check whether any ancestor (or the current node) kept the given
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
+ * @param {string} attrName
+ * @returns {boolean}
+ */
+ hasAnyParentAttr(attrName) {
+ return this._matcher.hasAnyParentAttr(attrName);
+ }
+
+ /**
+ * Get current node's sibling position (child index in parent).
+ * @returns {number}
+ */
+ getPosition() {
+ const path = this._matcher.path;
+ if (path.length === 0) return -1;
+ return path[path.length - 1].position ?? 0;
+ }
+
+ /**
+ * Get current node's repeat counter (occurrence count of this tag name).
+ * @returns {number}
+ */
+ getCounter() {
+ const path = this._matcher.path;
+ if (path.length === 0) return -1;
+ return path[path.length - 1].counter ?? 0;
+ }
+
+ /**
+ * Get current node's sibling index (alias for getPosition).
+ * @returns {number}
+ * @deprecated Use getPosition() or getCounter() instead
+ */
+ getIndex() {
+ return this.getPosition();
+ }
+
+ /**
+ * Get current path depth.
+ * @returns {number}
+ */
+ getDepth() {
+ return this._matcher.path.length;
+ }
+
+ /**
+ * Get path as string.
+ * @param {string} [separator] - Optional separator (uses default if not provided)
+ * @param {boolean} [includeNamespace=true]
+ * @returns {string}
+ */
+ toString(separator, includeNamespace = true) {
+ return this._matcher.toString(separator, includeNamespace);
+ }
+
+ /**
+ * Get path as array of tag names.
+ * @returns {string[]}
+ */
+ toArray() {
+ return this._matcher.path.map(n => n.tag);
+ }
+
+ /**
+ * Match current path against an Expression.
+ * @param {Expression} expression
+ * @returns {boolean}
+ */
+ matches(expression) {
+ return this._matcher.matches(expression);
+ }
+
+ /**
+ * Match any expression in the given set against the current path.
+ * @param {ExpressionSet} exprSet
+ * @returns {boolean}
+ */
+ matchesAny(exprSet) {
+ return exprSet.matchesAny(this._matcher);
+ }
+}
+
+/**
+ * Matcher - Tracks current path in XML/JSON tree and matches against Expressions.
+ *
+ * The matcher maintains a stack of nodes representing the current path from root to
+ * current tag. It only stores attribute values for the current (top) node to minimize
+ * memory usage. Sibling tracking is used to auto-calculate position and counter.
+ *
+ * Use {@link Matcher#readOnly} to obtain a {@link MatcherView} safe to pass to
+ * user callbacks — it always reflects current state with no Proxy overhead.
+ *
+ * @example
+ * const matcher = new Matcher();
+ * matcher.push("root", {});
+ * matcher.push("users", {});
+ * matcher.push("user", { id: "123", type: "admin" });
+ *
+ * const expr = new Expression("root.users.user");
+ * matcher.matches(expr); // true
+ */
+class Matcher {
+ /**
+ * Create a new Matcher.
+ * @param {Object} [options={}]
+ * @param {string} [options.separator='.'] - Default path separator
+ */
+ constructor(options = {}) {
+ this.separator = options.separator || '.';
+ this.path = [];
+ this.siblingStacks = [];
+ // Each path node: { tag, values, position, counter, namespace? }
+ // values only present for current (last) node
+ // Each siblingStacks entry: Map tracking occurrences at each level
+ this._pathStringCache = null;
+ this._view = new MatcherView(this);
+
+ // Kept-attribute stack: only populated when push() is called with options.keep.
+ this._keptAttrs = [];
+ }
+
+ /**
+ * Push a new tag onto the path.
+ * @param {string} tagName
+ * @param {Object|null} [attrValues=null]
+ * @param {string|null} [namespace=null]
+ * @param {Object|null} [options=null]
+ * @param {string[]} [options.keep] - Names of attributes (from attrValues)
+ */
+ push(tagName, attrValues = null, namespace = null, options = null) {
+ this._pathStringCache = null;
+
+ // Remove values from previous current node (now becoming ancestor)
+ if (this.path.length > 0) {
+ this.path[this.path.length - 1].values = undefined;
+ }
+
+ // Get or create sibling tracking for current level
+ const currentLevel = this.path.length;
+ let level = this.siblingStacks[currentLevel];
+ if (!level) {
+ // `counts` tells same-name siblings apart (the "counter" — nth -
+ // among other
- s). `total` is every child seen at this level so
+ // far, kept as a running number instead of re-added from `counts` on
+ // every push — a parent with many differently-named children would
+ // otherwise cost more per child the more distinct names it has.
+ level = { counts: new Map(), total: 0 };
+ this.siblingStacks[currentLevel] = level;
+ }
+
+ // Create a unique key for sibling tracking that includes namespace
+ const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;
+
+ // Calculate counter (how many times this tag appeared at this level)
+ const counter = level.counts.get(siblingKey) || 0;
+
+ // Position = total children at this level seen before this one.
+ const position = level.total;
+
+ // Update sibling count for this tag, and the level's running total.
+ level.counts.set(siblingKey, counter + 1);
+ level.total++;
+
+ // Create new node
+ const node = {
+ tag: tagName,
+ position: position,
+ counter: counter
+ };
+
+ if (namespace !== null && namespace !== undefined) {
+ node.namespace = namespace;
+ }
+
+ if (attrValues !== null && attrValues !== undefined) {
+ node.values = attrValues;
+ }
+
+ this.path.push(node);
+
+ // Depth of the node we just pushed (1-based, matches this.path.length)
+ const depth = this.path.length;
+
+ // Copy only the requested attributes into the kept-attrs stack. This is
+ // the one part of push() whose cost scales with input (O(keep.length))
+ // rather than being O(1) — by design, since the caller is explicitly
+ // opting in for specific attribute names. No options/keep => zero added
+ // cost beyond the two property reads below.
+ const keep = options !== null ? options.keep : null;
+ if (keep !== null && keep !== undefined && keep.length > 0 && attrValues) {
+ for (let i = 0; i < keep.length; i++) {
+ const name = keep[i];
+ if (attrValues[name] !== undefined) {
+ this._keptAttrs.push({ depth, name, value: attrValues[name] });
+ }
+ }
+ }
+ }
+
+ /**
+ * Pop the last tag from the path.
+ * @returns {Object|undefined} The popped node
+ */
+ pop() {
+ if (this.path.length === 0) return undefined;
+ this._pathStringCache = null;
+
+ const node = this.path.pop();
+
+ if (this.siblingStacks.length > this.path.length + 1) {
+ this.siblingStacks.length = this.path.length + 1;
+ }
+
+ // Drop any kept attributes that belonged to the popped node (or deeper).
+ // _keptAttrs is depth-ordered (push only ever appends increasing depths),
+ // so this is a backward scan that stops at the first surviving entry —
+ // typically O(1) since kept attrs are rare by design.
+ const poppedDepth = this.path.length + 1;
+ while (
+ this._keptAttrs.length > 0 &&
+ this._keptAttrs[this._keptAttrs.length - 1].depth >= poppedDepth
+ ) {
+ this._keptAttrs.pop();
+ }
+
+ return node;
+ }
+
+ /**
+ * Update current node's attribute values.
+ * Useful when attributes are parsed after push.
+ * @param {Object} attrValues
+ */
+ updateCurrent(attrValues) {
+ if (this.path.length > 0) {
+ const current = this.path[this.path.length - 1];
+ if (attrValues !== null && attrValues !== undefined) {
+ current.values = attrValues;
+ }
+ }
+ }
+
+ /**
+ * Get current tag name.
+ * @returns {string|undefined}
+ */
+ getCurrentTag() {
+ return this.path.length > 0 ? this.path[this.path.length - 1].tag : undefined;
+ }
+
+ /**
+ * Get current namespace.
+ * @returns {string|undefined}
+ */
+ getCurrentNamespace() {
+ return this.path.length > 0 ? this.path[this.path.length - 1].namespace : undefined;
+ }
+
+ /**
+ * Get current node's attribute value.
+ * @param {string} attrName
+ * @returns {*}
+ */
+ getAttrValue(attrName) {
+ if (this.path.length === 0) return undefined;
+ return this.path[this.path.length - 1].values?.[attrName];
+ }
+
+ /**
+ * Check if current node has an attribute.
+ * @param {string} attrName
+ * @returns {boolean}
+ */
+ hasAttr(attrName) {
+ if (this.path.length === 0) return false;
+ const current = this.path[this.path.length - 1];
+ return current.values !== undefined && attrName in current.values;
+ }
+
+ /**
+ * Get the value of a "kept" attribute from the nearest ancestor (or
+ * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
+ * Unlike getAttrValue(), this works regardless of how deep the path has
+ * gone since the attribute was pushed — but only for attribute names that
+ * were explicitly marked with `keep` at push time. Cost is proportional to
+ * the number of currently-kept attributes (typically 0-3), not path depth.
+ * @param {string} attrName
+ * @returns {*} the value, or undefined if no ancestor kept this attribute
+ */
+ getAnyParentAttr(attrName) {
+ const kept = this._keptAttrs;
+ for (let i = kept.length - 1; i >= 0; i--) {
+ if (kept[i].name === attrName) return kept[i].value;
+ }
+ return undefined;
+ }
+
+ /**
+ * Check whether any ancestor (or the current node) kept the given
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
+ * @param {string} attrName
+ * @returns {boolean}
+ */
+ hasAnyParentAttr(attrName) {
+ const kept = this._keptAttrs;
+ for (let i = kept.length - 1; i >= 0; i--) {
+ if (kept[i].name === attrName) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get current node's sibling position (child index in parent).
+ * @returns {number}
+ */
+ getPosition() {
+ if (this.path.length === 0) return -1;
+ return this.path[this.path.length - 1].position ?? 0;
+ }
+
+ /**
+ * Get current node's repeat counter (occurrence count of this tag name).
+ * @returns {number}
+ */
+ getCounter() {
+ if (this.path.length === 0) return -1;
+ return this.path[this.path.length - 1].counter ?? 0;
+ }
+
+ /**
+ * Get current node's sibling index (alias for getPosition).
+ * @returns {number}
+ * @deprecated Use getPosition() or getCounter() instead
+ */
+ getIndex() {
+ return this.getPosition();
+ }
+
+ /**
+ * Get current path depth.
+ * @returns {number}
+ */
+ getDepth() {
+ return this.path.length;
+ }
+
+ /**
+ * Get path as string.
+ * @param {string} [separator] - Optional separator (uses default if not provided)
+ * @param {boolean} [includeNamespace=true]
+ * @returns {string}
+ */
+ toString(separator, includeNamespace = true) {
+ const sep = separator || this.separator;
+ const isDefault = (sep === this.separator && includeNamespace === true);
+
+ if (isDefault) {
+ if (this._pathStringCache !== null) {
+ return this._pathStringCache;
+ }
+ const result = this.path.map(n =>
+ (n.namespace) ? `${n.namespace}:${n.tag}` : n.tag
+ ).join(sep);
+ this._pathStringCache = result;
+ return result;
+ }
+
+ return this.path.map(n =>
+ (includeNamespace && n.namespace) ? `${n.namespace}:${n.tag}` : n.tag
+ ).join(sep);
+ }
+
+ /**
+ * Get path as array of tag names.
+ * @returns {string[]}
+ */
+ toArray() {
+ return this.path.map(n => n.tag);
+ }
+
+ /**
+ * Reset the path to empty.
+ */
+ reset() {
+ this._pathStringCache = null;
+ this.path = [];
+ this.siblingStacks = [];
+ this._keptAttrs = [];
+ }
+
+ /**
+ * Match current path against an Expression.
+ * @param {Expression} expression
+ * @returns {boolean}
+ */
+ matches(expression) {
+ const segments = expression.segments;
+
+ if (segments.length === 0) {
+ return false;
+ }
+
+ if (expression.hasDeepWildcard()) {
+ return this._matchWithDeepWildcard(segments);
+ }
+
+ return this._matchSimple(segments);
+ }
+
+ /**
+ * @private
+ */
+ _matchSimple(segments) {
+ if (this.path.length !== segments.length) {
+ return false;
+ }
+
+ for (let i = 0; i < segments.length; i++) {
+ if (!this._matchSegment(segments[i], this.path[i], i === this.path.length - 1)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @private
+ */
+ _matchWithDeepWildcard(segments) {
+ let pathIdx = this.path.length - 1;
+ let segIdx = segments.length - 1;
+
+ while (segIdx >= 0 && pathIdx >= 0) {
+ const segment = segments[segIdx];
+
+ if (segment.type === 'deep-wildcard') {
+ segIdx--;
+
+ if (segIdx < 0) {
+ return true;
+ }
+
+ const nextSeg = segments[segIdx];
+ let found = false;
+
+ for (let i = pathIdx; i >= 0; i--) {
+ if (this._matchSegment(nextSeg, this.path[i], i === this.path.length - 1)) {
+ pathIdx = i - 1;
+ segIdx--;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return false;
+ }
+ } else {
+ if (!this._matchSegment(segment, this.path[pathIdx], pathIdx === this.path.length - 1)) {
+ return false;
+ }
+ pathIdx--;
+ segIdx--;
+ }
+ }
+
+ return segIdx < 0;
+ }
+
+ /**
+ * @private
+ */
+ _matchSegment(segment, node, isCurrentNode) {
+ if (segment.tag !== '*' && segment.tag !== node.tag) {
+ return false;
+ }
+
+ if (segment.namespace !== undefined) {
+ if (segment.namespace !== '*' && segment.namespace !== node.namespace) {
+ return false;
+ }
+ }
+
+ if (segment.attrName !== undefined) {
+ if (!isCurrentNode) {
+ return false;
+ }
+
+ if (!node.values || !(segment.attrName in node.values)) {
+ return false;
+ }
+
+ if (segment.attrValue !== undefined) {
+ if (String(node.values[segment.attrName]) !== String(segment.attrValue)) {
+ return false;
+ }
+ }
+ }
+
+ if (segment.position !== undefined) {
+ if (!isCurrentNode) {
+ return false;
+ }
+
+ const counter = node.counter ?? 0;
+
+ if (segment.position === 'first' && counter !== 0) {
+ return false;
+ } else if (segment.position === 'odd' && counter % 2 !== 1) {
+ return false;
+ } else if (segment.position === 'even' && counter % 2 !== 0) {
+ return false;
+ } else if (segment.position === 'nth' && counter !== segment.positionValue) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Match any expression in the given set against the current path.
+ * @param {ExpressionSet} exprSet
+ * @returns {boolean}
+ */
+ matchesAny(exprSet) {
+ return exprSet.matchesAny(this);
+ }
+
+ /**
+ * Create a snapshot of current state.
+ * @returns {Object}
+ */
+ snapshot() {
+ return {
+ path: this.path.map(node => ({ ...node })),
+ siblingStacks: this.siblingStacks.map(level => level ? { counts: new Map(level.counts), total: level.total } : level),
+ keptAttrs: this._keptAttrs.map(entry => ({ ...entry }))
+ };
+ }
+
+ /**
+ * Restore state from snapshot.
+ * @param {Object} snapshot
+ */
+ restore(snapshot) {
+ this._pathStringCache = null;
+ this.path = snapshot.path.map(node => ({ ...node }));
+ this.siblingStacks = snapshot.siblingStacks.map(level => level ? { counts: new Map(level.counts), total: level.total } : level);
+ this._keptAttrs = (snapshot.keptAttrs || []).map(entry => ({ ...entry }));
+ }
+
+ /**
+ * Return the read-only {@link MatcherView} for this matcher.
+ *
+ * The same instance is returned on every call — no allocation occurs.
+ * It always reflects the current parser state and is safe to pass to
+ * user callbacks without risk of accidental mutation.
+ *
+ * @returns {MatcherView}
+ *
+ * @example
+ * const view = matcher.readOnly();
+ * // pass view to callbacks — it stays in sync automatically
+ * view.matches(expr); // ✓
+ * view.getCurrentTag(); // ✓
+ * // view.push(...) // ✗ method does not exist — caught by TypeScript
+ */
+ readOnly() {
+ return this._view;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/fast-xml-builder/src/util.js
+
+
+function safeComment(val) {
+ return String(val)
+ .replace(/--/g, '- -') // -- is illegal anywhere in comment content
+ .replace(/--/g, '- -') // handle the scenario when 2 consiucative dashes appears
+ .replace(/-$/, '- '); // trailing - would form -- with the closing -->
+}
+
+function safeCdata(val) {
+ return String(val).replace(/\]\]>/g, ']]]]>')
+}
+
+function escapeAttribute(val) {
+ return String(val).replace(/"/g, '"').replace(/'/g, ''')
+}
+;// CONCATENATED MODULE: ./node_modules/xml-naming/src/index.js
+/**
+ * xml-naming
+ * Validates XML Name productions as defined in the XML 1.0 and 1.1 specifications.
+ * Covers: Name, NCName, QName, NMToken, NMTokens
+ *
+ * XML 1.0 spec: https://www.w3.org/TR/xml/#NT-Name
+ * XML 1.1 spec: https://www.w3.org/TR/xml11/#NT-NameStartChar
+ * XML NS spec: https://www.w3.org/TR/xml-names/#NT-NCName
+ */
+
+// ---------------------------------------------------------------------------
+// Character class strings — XML 1.0
+//
+// NameStartChar ::= ":" | [A-Z] | "_" | [a-z]
+// | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF]
+// | [#x370-#x37D] | [#x37F-#x1FFF] <- split to exclude #x0487
+// | [#x200C-#x200D]
+// | [#x2070-#x218F] | [#x2C00-#x2FEF]
+// | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD]
+//
+// NameChar ::= NameStartChar | "-" | "." | [0-9]
+// | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
+//
+// Note: \u0487 (Combining Cyrillic Millions Sign) was added in Unicode 4.0,
+// after XML 1.0 was defined against Unicode 2.0. It falls inside the range
+// \u037F-\u1FFF but must be excluded. We split that range into
+// \u037F-\u0486 and \u0488-\u1FFF to exclude it explicitly.
+// ---------------------------------------------------------------------------
+
+const nameStartChar10 =
+ ':A-Za-z_' +
+ '\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF' +
+ '\u0370-\u037D' +
+ '\u037F-\u0486\u0488-\u1FFF' + // split to exclude \u0487
+ '\u200C-\u200D' +
+ '\u2070-\u218F' +
+ '\u2C00-\u2FEF' +
+ '\u3001-\uD7FF' +
+ '\uF900-\uFDCF' +
+ '\uFDF0-\uFFFD';
+
+const nameChar10 =
+ nameStartChar10 +
+ '\\-\\.\\d' +
+ '\u00B7' +
+ '\u0300-\u036F' +
+ '\u203F-\u2040';
+
+// ---------------------------------------------------------------------------
+// Character class strings — XML 1.1
+//
+// Differences from XML 1.0:
+//
+// NameStartChar:
+// 1.0 has split ranges: \u00C0-\u00D6, \u00D8-\u00F6, \u00F8-\u02FF
+// 1.1 merges them into: \u00C0-\u02FF
+// (\u00D7 x and \u00F7 / are division symbols, excluded in both versions)
+//
+// 1.0 tops out at \uFFFD (BMP only)
+// 1.1 adds \u{10000}-\u{EFFFF} (supplementary planes)
+// These require the /u flag on the RegExp — see buildRegexes below.
+//
+// NameChar:
+// 1.1 adds \u0487 (Combining Cyrillic Millions Sign, added in Unicode 4.0)
+// ---------------------------------------------------------------------------
+
+const nameStartChar11 =
+ ':A-Za-z_' +
+ '\u00C0-\u02FF' + // merged — 1.0 had three split ranges here
+ '\u0370-\u037D' +
+ '\u037F-\u0486\u0488-\u1FFF' + // split to exclude \u0487 (combining mark, never a NameStartChar)
+ '\u200C-\u200D' +
+ '\u2070-\u218F' +
+ '\u2C00-\u2FEF' +
+ '\u3001-\uD7FF' +
+ '\uF900-\uFDCF' +
+ '\uFDF0-\uFFFD' +
+ '\u{10000}-\u{EFFFF}'; // supplementary planes — REQUIRES /u flag on RegExp
+
+const nameChar11 =
+ nameStartChar11 +
+ '\\-\\.\\d' +
+ '\u00B7' +
+ '\u0300-\u036F' +
+ '\u0487' + // Combining Cyrillic Millions Sign — valid in 1.1, not 1.0
+ '\u203F-\u2040';
+
+// ---------------------------------------------------------------------------
+// Regex builders
+//
+// XML 1.0 regexes: no flags — BMP only, standard JS regex behaviour.
+// XML 1.1 regexes: /u flag — required for \u{10000}-\u{EFFFF} to match actual
+// supplementary code points rather than lone surrogates (which are illegal XML).
+// ---------------------------------------------------------------------------
+
+const buildRegexes = (startChar, char, flags = '') => {
+ const ncStart = startChar.replace(':', '');
+ const ncChar = char.replace(':', '');
+ const ncNamePat = `[${ncStart}][${ncChar}]*`;
+
+ return {
+ name: new RegExp(`^[${startChar}][${char}]*$`, flags),
+ ncName: new RegExp(`^${ncNamePat}$`, flags),
+ qName: new RegExp(`^${ncNamePat}(?::${ncNamePat})?$`, flags),
+ nmToken: new RegExp(`^[${char}]+$`, flags),
+ nmTokens: new RegExp(`^[${char}]+(?:\\s+[${char}]+)*$`, flags),
+ };
+};
+
+const regexes10 = buildRegexes(nameStartChar10, nameChar10); // no /u — BMP only
+const regexes11 = buildRegexes(nameStartChar11, nameChar11, 'u'); // /u — enables \u{10000}-\u{EFFFF}
+
+// ---------------------------------------------------------------------------
+// ASCII-only fast path (opt-in, off by default)
+//
+// The XML 1.0 vs 1.1 NameStartChar/NameChar productions differ *only* in
+// their non-ASCII ranges (merged vs split Latin-1 ranges, \u0487, and
+// supplementary planes). Restricted to ASCII, both versions collapse to the
+// same character classes, so a single regex pair covers both xmlVersion
+// values — no /u flag needed.
+//
+// Rationale: unicode-aware regexes (the /u flag, required for XML 1.1's
+// supplementary-plane range) are measurably slower in V8 than plain
+// non-unicode regexes on the same input, even when the input is pure ASCII.
+// For the common case — HTML/SVG ids, XML tags — names are ASCII, so callers
+// who know this can opt in to skip the unicode-aware matching path entirely.
+// This is a real but *conditional* win: mainly for XML 1.1 input (avoids /u),
+// or at scale where the larger unicode character classes add engine
+// overhead. It also changes behaviour (rejects legitimate non-ASCII XML
+// 1.0/1.1 names), so it must never be silently enabled — hence off by
+// default.
+// ---------------------------------------------------------------------------
+
+const nameStartCharAscii = ':A-Za-z_';
+const nameCharAscii = nameStartCharAscii + '\\-\\.\\d';
+
+const regexesAscii = buildRegexes(nameStartCharAscii, nameCharAscii); // no /u — ASCII only
+
+const getRegexes = (xmlVersion = '1.0', asciiOnly = false) => {
+ if (asciiOnly) return regexesAscii;
+ return xmlVersion === '1.1' ? regexes11 : regexes10;
+};
+
+// ---------------------------------------------------------------------------
+// Boolean validators
+// ---------------------------------------------------------------------------
+
+/**
+ * Returns true if the string is a valid XML Name.
+ * Colons are allowed anywhere (Name production).
+ * Used for: DOCTYPE entity names, notation names, DTD element declarations.
+ *
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
+ * asciiOnly: skip unicode-aware matching, ASCII names only (default false).
+ */
+const src_name = (str, { xmlVersion = '1.0', asciiOnly = false } = {}) =>
+ getRegexes(xmlVersion, asciiOnly).name.test(str);
+
+/**
+ * Returns true if the string is a valid NCName (Non-Colonized Name).
+ * Colons are not permitted.
+ * Used for: namespace prefixes, local names, SVG id attributes.
+ *
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
+ * asciiOnly: skip unicode-aware matching, ASCII names only (default false).
+ */
+const ncName = (str, { xmlVersion = '1.0', asciiOnly = false } = {}) =>
+ getRegexes(xmlVersion, asciiOnly).ncName.test(str);
+
+/**
+ * Returns true if the string is a valid QName (Qualified Name).
+ * Allows exactly one colon as a prefix separator: prefix:localName.
+ * Used for: element and attribute names in namespace-aware XML/SVG.
+ *
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
+ * asciiOnly: skip unicode-aware matching, ASCII names only (default false).
+ */
+const qName = (str, { xmlVersion = '1.0', asciiOnly = false } = {}) =>
+ getRegexes(xmlVersion, asciiOnly).qName.test(str);
+
+/**
+ * Returns true if the string is a valid NMToken.
+ * Like Name but no restriction on the first character.
+ * Used for: DTD NMTOKEN attribute values.
+ *
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
+ * asciiOnly: skip unicode-aware matching, ASCII names only (default false).
+ */
+const nmToken = (str, { xmlVersion = '1.0', asciiOnly = false } = {}) =>
+ getRegexes(xmlVersion, asciiOnly).nmToken.test(str);
+
+/**
+ * Returns true if the string is a valid NMTokens value.
+ * A whitespace-separated list of NMToken values.
+ * Used for: DTD NMTOKENS attribute values.
+ *
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
+ * asciiOnly: skip unicode-aware matching, ASCII names only (default false).
+ */
+const nmTokens = (str, { xmlVersion = '1.0', asciiOnly = false } = {}) =>
+ getRegexes(xmlVersion, asciiOnly).nmTokens.test(str);
+
+// ---------------------------------------------------------------------------
+// Memoized validator factory
+//
+// Real documents reuse a small vocabulary of tag/attribute names across many
+// siblings (e.g. `id`, `class`, `href` repeated across hundreds of elements).
+// The plain boolean validators above re-run the regex on every call
+// regardless of repeats. `createValidator` returns a closure with a private
+// string -> boolean cache, so repeated names after the first become O(1)
+// lookups instead of regex tests.
+//
+// - opts (xmlVersion, asciiOnly) are fixed at creation time, so the regex is
+// resolved once, not on every call.
+// - The cache is private to the returned closure — no shared/global state,
+// no cross-caller pollution.
+// - `maxCacheSize` bounds memory: once the cache reaches this many entries,
+// it stops accepting new ones (existing entries keep serving hits; new
+// misses just fall through to the regex, uncached). This avoids unbounded
+// growth against adversarial/high-cardinality input (e.g. validating
+// attacker-supplied names with no repeats) without the cost/complexity of
+// a full LRU, and without the perf cliff of reset-and-refill thrashing.
+// - Call `.reset()` on the returned function to clear the cache manually
+// (e.g. between unrelated parse calls).
+// ---------------------------------------------------------------------------
+
+const PRODUCTIONS = ['name', 'ncName', 'qName', 'nmToken', 'nmTokens'];
+
+/**
+ * Returns a memoized boolean validator function for a single production,
+ * with opts fixed at creation time.
+ *
+ * @param {'name'|'ncName'|'qName'|'nmToken'|'nmTokens'} production
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean, maxCacheSize?: number }} [opts]
+ * maxCacheSize: max number of distinct strings to cache (default 2048).
+ * Once reached, new strings are validated but not cached; existing cached
+ * entries keep being served.
+ * @returns {((str: string) => boolean) & { reset: () => void }}
+ */
+const createValidator = (production, { xmlVersion = '1.0', asciiOnly = false, maxCacheSize = 2048 } = {}) => {
+ if (!PRODUCTIONS.includes(production)) {
+ throw new TypeError(
+ `Unknown production "${production}". Must be one of: ${PRODUCTIONS.join(', ')}`
+ );
+ }
+
+ const regex = getRegexes(xmlVersion, asciiOnly)[production];
+ let cache = new Map();
+
+ const validator = (str) => {
+ const cached = cache.get(str);
+ if (cached !== undefined) return cached;
+
+ const result = regex.test(str);
+ if (cache.size < maxCacheSize) cache.set(str, result);
+ return result;
+ };
+
+ validator.reset = () => { cache = new Map(); };
+
+ return validator;
+};
+
+// ---------------------------------------------------------------------------
+// Diagnostic validator
+// ---------------------------------------------------------------------------
+
+/**
+ * Validates a string against a named production and returns a detailed result.
+ *
+ * @param {string} str
+ * @param {'name'|'ncName'|'qName'|'nmToken'|'nmTokens'} production
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
+ * @returns {{ valid: boolean, production: string, input: string, reason?: string, position?: number }}
+ */
+const validate = (str, production, { xmlVersion = '1.0', asciiOnly = false } = {}) => {
+ if (!PRODUCTIONS.includes(production)) {
+ throw new TypeError(
+ `Unknown production "${production}". Must be one of: ${PRODUCTIONS.join(', ')}`
+ );
+ }
+
+ const validators = { name: src_name, ncName, qName, nmToken, nmTokens };
+ const isValid = validators[production](str, { xmlVersion, asciiOnly });
+
+ if (isValid) return { valid: true, production, input: str };
+
+ let reason = 'Does not match the production rules';
+ let position;
+
+ // Diagnostic fallback char checks must mirror the same character set the
+ // boolean validator above used, or the reported reason/position could
+ // contradict the `valid: false` result (e.g. flagging a char as illegal
+ // that the unicode-aware check would have accepted).
+ const startCharPattern = asciiOnly ? /^[:A-Za-z_]/ : /^[:A-Za-z_\u00C0-\uFFFD]/;
+ const namePattern = asciiOnly ? /[\w\-\\.:]/ : /[\w\-\\.:\u00B7\u00C0-\uFFFD]/;
+
+ if (str.length === 0) {
+ reason = 'Input is empty';
+ } else if (production === 'ncName' && str.includes(':')) {
+ position = str.indexOf(':');
+ reason = 'Colon is not allowed in NCName';
+ } else if (production === 'qName' && str.startsWith(':')) {
+ reason = 'QName cannot start with a colon';
+ position = 0;
+ } else if (production === 'qName' && str.endsWith(':')) {
+ reason = 'QName cannot end with a colon';
+ position = str.length - 1;
+ } else if (production === 'qName' && (str.match(/:/g) || []).length > 1) {
+ reason = 'QName can have at most one colon';
+ position = str.lastIndexOf(':');
+ } else if (
+ ['name', 'ncName', 'qName'].includes(production) &&
+ !startCharPattern.test(str[0])
+ ) {
+ reason = `First character "${str[0]}" is not a valid NameStartChar`;
+ position = 0;
+ } else {
+ for (let i = 0; i < str.length; i++) {
+ if (!namePattern.test(str[i])) {
+ reason = `Character "${str[i]}" at position ${i} is not a valid NameChar`;
+ position = i;
+ break;
+ }
+ }
+ }
+
+ return { valid: false, production, input: str, reason, position };
+};
+
+// ---------------------------------------------------------------------------
+// Batch validator
+// ---------------------------------------------------------------------------
+
+/**
+ * Validates an array of strings against a named production.
+ *
+ * @param {string[]} strings
+ * @param {'name'|'ncName'|'qName'|'nmToken'|'nmTokens'} production
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
+ * @returns {Array<{ valid: boolean, production: string, input: string, reason?: string, position?: number }>}
+ */
+const validateAll = (strings, production, opts = {}) =>
+ strings.map(str => validate(str, production, opts));
+
+// ---------------------------------------------------------------------------
+// Sanitizer
+// ---------------------------------------------------------------------------
+
+/**
+ * Transforms an invalid string into the nearest valid XML name for the given production.
+ *
+ * @param {string} str
+ * @param {'name'|'ncName'|'qName'|'nmToken'|'nmTokens'} production
+ * @param {{ replacement?: string, asciiOnly?: boolean }} [opts]
+ * asciiOnly: also replace any non-ASCII character, not just XML-illegal
+ * ones (default false).
+ * @returns {string}
+ */
+const sanitize = (str, production = 'name', { replacement = '_', asciiOnly = false } = {}) => {
+ if (!str) return replacement;
+
+ let result = str;
+
+ // Strip colons for NCName
+ if (production === 'ncName') {
+ result = result.replace(/:/g, '');
+ }
+
+ // Replace illegal characters
+ const allowedCharPattern = asciiOnly ? /[^\w\-\.:]/g : /[^\w\-\.:\u00B7\u00C0-\uFFFD]/g;
+ result = result.replace(allowedCharPattern, replacement);
+
+ // Fix invalid start character for Name / NCName / QName
+ if (production !== 'nmToken' && production !== 'nmTokens') {
+ if (/^[\-\.\d]/.test(result)) {
+ result = replacement + result;
+ }
+ }
+
+ return result || replacement;
+};
+;// CONCATENATED MODULE: ./node_modules/fast-xml-builder/src/orderedJs2Xml.js
+
+
+
+
+const EOL = "\n";
+
+/**
+ * Detect XML version from the first element of the ordered array input.
+ * The first element must be a ?xml processing instruction with a version attribute.
+ * Returns '1.0' if not found.
+ *
+ * @param {array} jArray
+ * @param {object} options
+ */
+function detectXmlVersionFromArray(jArray, options) {
+ if (!Array.isArray(jArray) || jArray.length === 0) return '1.0';
+ const first = jArray[0];
+ const firstKey = propName(first);
+ if (firstKey === '?xml') {
+ const attrs = first[':@'];
+ if (attrs) {
+ const versionKey = options.attributeNamePrefix + 'version';
+ if (attrs[versionKey]) return attrs[versionKey];
+ }
+ }
+ return '1.0';
+}
+
+/**
+ * Resolve a tag or attribute name through sanitizeName if configured.
+ * Validation via xml-naming's qName is performed first; the sanitizeName
+ * callback is invoked only when the name is invalid. If sanitizeName is
+ * false (default), no validation occurs and the name is used as-is.
+ *
+ * @param {string} name - raw name from the JS object
+ * @param {boolean} isAttribute - true when resolving an attribute name
+ * @param {object} options
+ * @param {Matcher} matcher - current matcher state (readonly from callback perspective)
+ * @param {function} qNameValidator - function to validate tag names
+ */
+function resolveTagName(name, isAttribute, options, matcher, qNameValidator) {
+ if (!options.sanitizeName) return name;
+ if (qNameValidator(name)) return name;
+ return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() });
+}
+
+/**
+ * @param {array} jArray
+ * @param {any} options
+ * @returns
+ */
+function toXml(jArray, options) {
+ let indentation = "";
+ if (options.format) {
+ indentation = EOL;
+ }
+
+ // Pre-compile stopNode expressions for pattern matching
+ const stopNodeExpressions = [];
+ if (options.stopNodes && Array.isArray(options.stopNodes)) {
+ for (let i = 0; i < options.stopNodes.length; i++) {
+ const node = options.stopNodes[i];
+ if (typeof node === 'string') {
+ stopNodeExpressions.push(new Expression(node));
+ } else if (node instanceof Expression) {
+ stopNodeExpressions.push(node);
+ }
+ }
+ }
+
+ // Detect XML version for use in name validation
+ const xmlVersion = detectXmlVersionFromArray(jArray, options);
+ const qNameValidator = createValidator('qName', { xmlVersion });
+ // Initialize matcher for path tracking
+ const matcher = new Matcher();
+
+ return arrToStr(jArray, options, indentation, matcher, stopNodeExpressions, qNameValidator);
+}
+
+function arrToStr(arr, options, indentation, matcher, stopNodeExpressions, qNameValidator) {
+ let xmlStr = "";
+ let isPreviousElementTag = false;
+
+ if (options.maxNestedTags && matcher.getDepth() > options.maxNestedTags) {
+ throw new Error("Maximum nested tags exceeded");
+ }
+
+ if (!Array.isArray(arr)) {
+ // Non-array values (e.g. string tag values) should be treated as text content
+ if (arr !== undefined && arr !== null) {
+ let text = arr.toString();
+ text = replaceEntitiesValue(text, options);
+ return text;
+ }
+ return "";
+ }
+
+ for (let i = 0; i < arr.length; i++) {
+ const tagObj = arr[i];
+ const rawTagName = propName(tagObj);
+ if (rawTagName === undefined) continue;
+
+ // Special names are exempt from sanitizeName: internal conventions and PI tags
+ // are not user-supplied XML element names.
+ const isSpecialName = rawTagName === options.textNodeName
+ || rawTagName === options.cdataPropName
+ || rawTagName === options.commentPropName
+ || rawTagName[0] === '?';
+
+ // Resolve tag name (may transform it; may throw for invalid names)
+ const tagName = isSpecialName
+ ? rawTagName
+ : resolveTagName(rawTagName, false, options, matcher, qNameValidator);
+
+ // Extract attributes from ":@" property
+ const attrValues = extractAttributeValues(tagObj[":@"], options);
+
+ // Push resolved tag to matcher WITH attributes
+ matcher.push(tagName, attrValues);
+
+ // Check if this is a stop node using Expression matching
+ const isStopNode = checkStopNode(matcher, stopNodeExpressions);
+
+ if (tagName === options.textNodeName) {
+ let tagText = tagObj[rawTagName];
+ if (!isStopNode) {
+ tagText = options.tagValueProcessor(tagName, tagText);
+ tagText = replaceEntitiesValue(tagText, options);
+ }
+ if (isPreviousElementTag) {
+ xmlStr += indentation;
+ }
+ xmlStr += tagText;
+ isPreviousElementTag = false;
+ matcher.pop();
+ continue;
+ } else if (tagName === options.cdataPropName) {
+ if (isPreviousElementTag) {
+ xmlStr += indentation;
+ }
+ const val = tagObj[rawTagName][0][options.textNodeName];
+ const safeVal = safeCdata(val);
+ xmlStr += ``;
+ isPreviousElementTag = false;
+ matcher.pop();
+ continue;
+ } else if (tagName === options.commentPropName) {
+ const val = tagObj[rawTagName][0][options.textNodeName];
+ const safeVal = safeComment(val);
+ xmlStr += indentation + ``;
+ isPreviousElementTag = true;
+ matcher.pop();
+ continue;
+ } else if (tagName[0] === "?") {
+ const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, qNameValidator);
+ const tempInd = tagName === "?xml" ? "" : indentation;
+ // Text node content on PI/XML declaration tags is intentionally ignored.
+ // Only attributes are valid on these tags per the XML spec.
+ xmlStr += tempInd + `<${tagName}${attStr}?>`;
+ isPreviousElementTag = true;
+ matcher.pop();
+ continue;
+ }
+
+ let newIdentation = indentation;
+ if (newIdentation !== "") {
+ newIdentation += options.indentBy;
+ }
+
+ // Pass isStopNode to attr_to_str so attributes are also not processed for stopNodes
+ const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, qNameValidator);
+ const tagStart = indentation + `<${tagName}${attStr}`;
+
+ // If this is a stopNode, get raw content without processing
+ let tagValue;
+ if (isStopNode) {
+ tagValue = orderedJs2Xml_getRawContent(tagObj[rawTagName], options);
+ } else {
+ tagValue = arrToStr(tagObj[rawTagName], options, newIdentation, matcher, stopNodeExpressions, qNameValidator);
+ }
+
+ if (options.unpairedTags.indexOf(tagName) !== -1) {
+ if (options.suppressUnpairedNode) xmlStr += tagStart + ">";
+ else xmlStr += tagStart + "/>";
+ } else if ((!tagValue || tagValue.length === 0) && options.suppressEmptyNode) {
+ xmlStr += tagStart + "/>";
+ } else if (tagValue && tagValue.endsWith(">")) {
+ xmlStr += tagStart + `>${tagValue}${indentation}${tagName}>`;
+ } else {
+ xmlStr += tagStart + ">";
+ if (tagValue && indentation !== "" && (tagValue.includes("/>") || tagValue.includes(""))) {
+ xmlStr += indentation + options.indentBy + tagValue + indentation;
+ } else {
+ xmlStr += tagValue;
+ }
+ xmlStr += `${tagName}>`;
+ }
+ isPreviousElementTag = true;
+
+ // Pop tag from matcher
+ matcher.pop();
+ }
+
+ return xmlStr;
+}
+
+/**
+ * Extract attribute values from the ":@" object and return as plain object
+ * for passing to matcher.push()
+ */
+function extractAttributeValues(attrMap, options) {
+ if (!attrMap || options.ignoreAttributes) return null;
+
+ const attrValues = {};
+ let hasAttrs = false;
+
+ for (let attr in attrMap) {
+ if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
+ // Remove the attribute prefix to get clean attribute name
+ const cleanAttrName = attr.startsWith(options.attributeNamePrefix)
+ ? attr.substr(options.attributeNamePrefix.length)
+ : attr;
+ attrValues[cleanAttrName] = escapeAttribute(attrMap[attr]);
+ hasAttrs = true;
+ }
+
+ return hasAttrs ? attrValues : null;
+}
+
+/**
+ * Extract raw content from a stopNode without any processing
+ * This preserves the content exactly as-is, including special characters
+ */
+function orderedJs2Xml_getRawContent(arr, options) {
+ if (!Array.isArray(arr)) {
+ // Non-array values return as-is
+ if (arr !== undefined && arr !== null) {
+ return arr.toString();
+ }
+ return "";
+ }
+
+ let content = "";
+ for (let i = 0; i < arr.length; i++) {
+ const item = arr[i];
+ const tagName = propName(item);
+
+ if (tagName === options.textNodeName) {
+ // Raw text content - NO processing, NO entity replacement
+ content += item[tagName];
+ } else if (tagName === options.cdataPropName) {
+ // CDATA content
+ content += item[tagName][0][options.textNodeName];
+ } else if (tagName === options.commentPropName) {
+ // Comment content
+ content += item[tagName][0][options.textNodeName];
+ } else if (tagName && tagName[0] === "?") {
+ // Processing instruction - skip for stopNodes
+ continue;
+ } else if (tagName) {
+ // Nested tags within stopNode — no sanitizeName, content is raw
+ const attStr = attr_to_str_raw(item[":@"], options);
+ const nestedContent = orderedJs2Xml_getRawContent(item[tagName], options);
+
+ if (!nestedContent || nestedContent.length === 0) {
+ content += `<${tagName}${attStr}/>`;
+ } else {
+ content += `<${tagName}${attStr}>${nestedContent}${tagName}>`;
+ }
+ }
+ }
+ return content;
+}
+
+/**
+ * Build attribute string for stopNodes - NO entity replacement
+ */
+function attr_to_str_raw(attrMap, options) {
+ let attrStr = "";
+ if (attrMap && !options.ignoreAttributes) {
+ for (let attr in attrMap) {
+ if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
+ // For stopNodes, use raw value without processing
+ let attrVal = attrMap[attr];
+ if (attrVal === true && options.suppressBooleanAttributes) {
+ attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`;
+ } else {
+ attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${escapeAttribute(attrVal)}"`;
+ }
+ }
+ }
+ return attrStr;
+}
+
+function propName(obj) {
+ const keys = Object.keys(obj);
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
+ if (key !== ":@") return key;
+ }
+}
+
+/**
+ * Build attribute string, resolving attribute names through sanitizeName when configured.
+ * Accepts matcher so the callback has path context.
+ */
+function attr_to_str(attrMap, options, isStopNode, matcher, qNameValidator) {
+ let attrStr = "";
+ if (attrMap && !options.ignoreAttributes) {
+ for (let attr in attrMap) {
+ if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
+
+ // Strip prefix to get the clean XML attribute name, then optionally sanitize it
+ const cleanAttrName = attr.substr(options.attributeNamePrefix.length);
+ const resolvedAttrName = isStopNode
+ ? cleanAttrName // stopNodes are raw — skip sanitizeName for attr names too
+ : resolveTagName(cleanAttrName, true, options, matcher, qNameValidator);
+
+ let attrVal;
+ if (isStopNode) {
+ // For stopNodes, use raw value without any processing
+ attrVal = attrMap[attr];
+ } else {
+ // Normal processing: apply attributeValueProcessor and entity replacement
+ attrVal = options.attributeValueProcessor(attr, attrMap[attr]);
+ attrVal = replaceEntitiesValue(attrVal, options);
+ }
+
+ if (attrVal === true && options.suppressBooleanAttributes) {
+ attrStr += ` ${resolvedAttrName}`;
+ } else {
+ attrStr += ` ${resolvedAttrName}="${escapeAttribute(attrVal)}"`;
+ }
+ }
+ }
+ return attrStr;
+}
+
+function checkStopNode(matcher, stopNodeExpressions) {
+ if (!stopNodeExpressions || stopNodeExpressions.length === 0) return false;
+
+ for (let i = 0; i < stopNodeExpressions.length; i++) {
+ if (matcher.matches(stopNodeExpressions[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function replaceEntitiesValue(textValue, options) {
+ if (textValue && textValue.length > 0 && options.processEntities) {
+ for (let i = 0; i < options.entities.length; i++) {
+ const entity = options.entities[i];
+ textValue = textValue.replace(entity.regex, entity.val);
+ }
+ }
+ return textValue;
+}
+;// CONCATENATED MODULE: ./node_modules/fast-xml-builder/src/ignoreAttributes.js
+function getIgnoreAttributesFn(ignoreAttributes) {
+ if (typeof ignoreAttributes === 'function') {
+ return ignoreAttributes
+ }
+ if (Array.isArray(ignoreAttributes)) {
+ return (attrName) => {
+ for (const pattern of ignoreAttributes) {
+ if (typeof pattern === 'string' && attrName === pattern) {
+ return true
+ }
+ if (pattern instanceof RegExp && pattern.test(attrName)) {
+ return true
+ }
+ }
+ }
+ }
+ return () => false
+}
+;// CONCATENATED MODULE: ./node_modules/fast-xml-builder/src/fxb.js
+
+//parse Empty Node as self closing node
+
+
+
+
+
+
+const defaultOptions = {
+ attributeNamePrefix: '@_',
+ attributesGroupName: false,
+ textNodeName: '#text',
+ ignoreAttributes: true,
+ cdataPropName: false,
+ format: false,
+ indentBy: ' ',
+ suppressEmptyNode: false,
+ suppressUnpairedNode: true,
+ suppressBooleanAttributes: true,
+ tagValueProcessor: function (key, a) {
+ return a;
+ },
+ attributeValueProcessor: function (attrName, a) {
+ return a;
+ },
+ preserveOrder: false,
+ commentPropName: false,
+ unpairedTags: [],
+ entities: [
+ { regex: new RegExp("&", "g"), val: "&" },//it must be on top
+ { regex: new RegExp(">", "g"), val: ">" },
+ { regex: new RegExp("<", "g"), val: "<" },
+ { regex: new RegExp("\'", "g"), val: "'" },
+ { regex: new RegExp("\"", "g"), val: """ }
+ ],
+ processEntities: true,
+ stopNodes: [],
+ // transformTagName: false,
+ // transformAttributeName: false,
+ oneListGroup: false,
+ maxNestedTags: 100,
+ jPath: true, // When true, callbacks receive string jPath; when false, receive Matcher instance
+ sanitizeName: false // false = allow all names as-is (default, backward-compatible).
+ // Set to a function (name, { isAttribute, matcher }) => string to
+ // validate/sanitize tag and attribute names. Throw inside the function
+ // to reject an invalid name.
+};
+
+function Builder(options) {
+ this.options = Object.assign({}, defaultOptions, options);
+
+ // Convert old-style stopNodes for backward compatibility
+ // Old syntax: "*.tag" meant "tag anywhere in tree"
+ // New syntax: "..tag" means "tag anywhere in tree"
+ if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
+ this.options.stopNodes = this.options.stopNodes.map(node => {
+ if (typeof node === 'string' && node.startsWith('*.')) {
+ // Convert old wildcard syntax to deep wildcard
+ return '..' + node.substring(2);
+ }
+ return node;
+ });
+ }
+
+ // Pre-compile stopNode expressions for pattern matching
+ this.stopNodeExpressions = [];
+ if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
+ for (let i = 0; i < this.options.stopNodes.length; i++) {
+ const node = this.options.stopNodes[i];
+ if (typeof node === 'string') {
+ this.stopNodeExpressions.push(new Expression(node));
+ } else if (node instanceof Expression) {
+ this.stopNodeExpressions.push(node);
+ }
+ }
+ }
+
+ if (this.options.ignoreAttributes === true || this.options.attributesGroupName) {
+ this.isAttribute = function (/*a*/) {
+ return false;
+ };
+ } else {
+ this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes)
+ this.attrPrefixLen = this.options.attributeNamePrefix.length;
+ this.isAttribute = isAttribute;
+ }
+
+ this.processTextOrObjNode = processTextOrObjNode
+
+ if (this.options.format) {
+ this.indentate = indentate;
+ this.tagEndChar = '>\n';
+ this.newLine = '\n';
+ } else {
+ this.indentate = function () {
+ return '';
+ };
+ this.tagEndChar = '>';
+ this.newLine = '';
+ }
+}
+
+/**
+ * Detect XML version from the ?xml declaration at the root of a plain-object input.
+ * Checks both attributesGroupName and flat attribute forms.
+ * Returns '1.0' if no declaration is found.
+ */
+function detectXmlVersionFromObj(jObj, options) {
+ const decl = jObj['?xml'];
+ if (decl && typeof decl === 'object') {
+ // attributesGroupName path e.g. { '$$': { '@_version': '1.1' } }
+ if (options.attributesGroupName && decl[options.attributesGroupName]) {
+ const v = decl[options.attributesGroupName][options.attributeNamePrefix + 'version'];
+ if (v) return v;
+ }
+ // flat attribute path e.g. { '@_version': '1.1' }
+ const v = decl[options.attributeNamePrefix + 'version'];
+ if (v) return v;
+ }
+ return '1.0';
+}
+
+/**
+ * Resolve a tag or attribute name through sanitizeName if configured.
+ * Validation via xml-naming's qName is performed first; the sanitizeName
+ * callback is invoked only when the name is invalid. If sanitizeName is
+ * false (default), no validation occurs and the name is used as-is.
+ *
+ * @param {string} name - raw name from the JS object
+ * @param {boolean} isAttribute - true when resolving an attribute name
+ * @param {object} options
+ * @param {Matcher} matcher - current matcher state (readonly from callback perspective)
+ * @param {function} qNameValidator - function to validate tag names
+ */
+function fxb_resolveTagName(name, isAttribute, options, matcher, qNameValidator) {
+ if (!options.sanitizeName) return name;
+ if (qNameValidator(name)) return name;
+ return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() });
+}
+
+Builder.prototype.build = function (jObj) {
+ if (this.options.preserveOrder) {
+ return toXml(jObj, this.options);
+ } else {
+ if (Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1) {
+ jObj = {
+ [this.options.arrayNodeName]: jObj
+ }
+ }
+ // Initialize matcher for path tracking
+ const matcher = new Matcher();
+ const xmlVersion = detectXmlVersionFromObj(jObj, this.options);
+ const qNameValidator = createValidator('qName', { xmlVersion });
+ return this.j2x(jObj, 0, matcher, qNameValidator).val;
+ }
+};
+
+Builder.prototype.j2x = function (jObj, level, matcher, qNameValidator) {
+ let attrStr = '';
+ let val = '';
+ if (this.options.maxNestedTags && matcher.getDepth() >= this.options.maxNestedTags) {
+ throw new Error("Maximum nested tags exceeded");
+ }
+ // Get jPath based on option: string for backward compatibility, or Matcher for new features
+ const jPath = this.options.jPath ? matcher.toString() : matcher;
+
+ // Check if current node is a stopNode (will be used for attribute encoding)
+ const isCurrentStopNode = this.checkStopNode(matcher);
+
+ for (let key in jObj) {
+ if (!Object.prototype.hasOwnProperty.call(jObj, key)) continue;
+
+ // Resolve the key through sanitizeName before any use.
+ // Special keys (textNodeName, cdataPropName, commentPropName, attributeNamePrefix,
+ // attributesGroupName, "?" PI tags) are exempt — they are builder-internal conventions,
+ // not user-supplied XML names.
+ const isSpecialKey = key === this.options.textNodeName
+ || key === this.options.cdataPropName
+ || key === this.options.commentPropName
+ || (this.options.attributesGroupName && key === this.options.attributesGroupName)
+ || this.isAttribute(key)
+ || key[0] === '?';
+
+ const resolvedKey = isSpecialKey
+ ? key
+ : fxb_resolveTagName(key, false, this.options, matcher, qNameValidator);
+
+ if (typeof jObj[key] === 'undefined') {
+ // supress undefined node only if it is not an attribute
+ if (this.isAttribute(key)) {
+ val += '';
+ }
+ } else if (jObj[key] === null) {
+ // null attribute should be ignored by the attribute list, but should not cause the tag closing
+ if (this.isAttribute(key)) {
+ val += '';
+ } else if (resolvedKey === this.options.cdataPropName || resolvedKey === this.options.commentPropName) {
+ val += '';
+ } else if (resolvedKey[0] === '?') {
+ val += this.indentate(level) + '<' + resolvedKey + '?' + this.tagEndChar;
+ } else {
+ val += this.indentate(level) + '<' + resolvedKey + '/' + this.tagEndChar;
+ }
+ } else if (jObj[key] instanceof Date) {
+ val += this.buildTextValNode(jObj[key], resolvedKey, '', level, matcher);
+ } else if (typeof jObj[key] !== 'object') {
+ //premitive type
+ const attr = this.isAttribute(key);
+ if (attr && !this.ignoreAttributesFn(attr, jPath)) {
+ // Resolve the attribute name through sanitizeName
+ const resolvedAttr = fxb_resolveTagName(attr, true, this.options, matcher, qNameValidator);
+ attrStr += this.buildAttrPairStr(resolvedAttr, '' + jObj[key], isCurrentStopNode);
+ } else if (!attr) {
+ //tag value
+ if (key === this.options.textNodeName) {
+ let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
+ val += this.replaceEntitiesValue(newval);
+ } else {
+ // Check if this is a stopNode before building
+ matcher.push(resolvedKey);
+ const isStopNode = this.checkStopNode(matcher);
+ matcher.pop();
+
+ if (isStopNode) {
+ // Build as raw content without encoding
+ const textValue = '' + jObj[key];
+ if (textValue === '') {
+ val += this.indentate(level) + '<' + resolvedKey + this.closeTag(resolvedKey) + this.tagEndChar;
+ } else {
+ val += this.indentate(level) + '<' + resolvedKey + '>' + textValue + '' + resolvedKey + this.tagEndChar;
+ }
+ } else {
+ val += this.buildTextValNode(jObj[key], resolvedKey, '', level, matcher);
+ }
+ }
+ }
+ } else if (Array.isArray(jObj[key])) {
+ //repeated nodes
+ const arrLen = jObj[key].length;
+ let listTagVal = "";
+ let listTagAttr = "";
+ for (let j = 0; j < arrLen; j++) {
+ const item = jObj[key][j];
+ if (typeof item === 'undefined') {
+ // supress undefined node
+ } else if (item === null) {
+ if (resolvedKey[0] === "?") val += this.indentate(level) + '<' + resolvedKey + '?' + this.tagEndChar;
+ else val += this.indentate(level) + '<' + resolvedKey + '/' + this.tagEndChar;
+ } else if (typeof item === 'object') {
+ if (this.options.oneListGroup) {
+ // Push tag to matcher before recursive call
+ matcher.push(resolvedKey);
+ const result = this.j2x(item, level + 1, matcher, qNameValidator);
+ // Pop tag from matcher after recursive call
+ matcher.pop();
+
+ listTagVal += result.val;
+ if (this.options.attributesGroupName && item.hasOwnProperty(this.options.attributesGroupName)) {
+ listTagAttr += result.attrStr
+ }
+ } else {
+ listTagVal += this.processTextOrObjNode(item, resolvedKey, level, matcher, qNameValidator)
+ }
+ } else {
+ if (this.options.oneListGroup) {
+ let textValue = this.options.tagValueProcessor(resolvedKey, item);
+ textValue = this.replaceEntitiesValue(textValue);
+ listTagVal += textValue;
+ } else {
+ // Check if this is a stopNode before building
+ matcher.push(resolvedKey);
+ const isStopNode = this.checkStopNode(matcher);
+ matcher.pop();
+
+ if (isStopNode) {
+ // Build as raw content without encoding
+ const textValue = '' + item;
+ if (textValue === '') {
+ listTagVal += this.indentate(level) + '<' + resolvedKey + this.closeTag(resolvedKey) + this.tagEndChar;
+ } else {
+ listTagVal += this.indentate(level) + '<' + resolvedKey + '>' + textValue + '' + resolvedKey + this.tagEndChar;
+ }
+ } else {
+ listTagVal += this.buildTextValNode(item, resolvedKey, '', level, matcher);
+ }
+ }
+ }
+ }
+ if (this.options.oneListGroup) {
+ listTagVal = this.buildObjectNode(listTagVal, resolvedKey, listTagAttr, level);
+ }
+ val += listTagVal;
+ } else {
+ //nested node
+ if (this.options.attributesGroupName && key === this.options.attributesGroupName) {
+ const Ks = Object.keys(jObj[key]);
+ const L = Ks.length;
+ for (let j = 0; j < L; j++) {
+ // Resolve attribute names inside attributesGroupName
+ const resolvedAttr = fxb_resolveTagName(Ks[j], true, this.options, matcher, qNameValidator);
+ attrStr += this.buildAttrPairStr(resolvedAttr, '' + jObj[key][Ks[j]], isCurrentStopNode);
+ }
+ } else {
+ val += this.processTextOrObjNode(jObj[key], resolvedKey, level, matcher, qNameValidator)
+ }
+ }
+ }
+ return { attrStr: attrStr, val: val };
+};
+
+Builder.prototype.buildAttrPairStr = function (attrName, val, isStopNode) {
+ if (!isStopNode) {
+ val = this.options.attributeValueProcessor(attrName, '' + val);
+ val = this.replaceEntitiesValue(val);
+ }
+ if (this.options.suppressBooleanAttributes && val === "true") {
+ return ' ' + attrName;
+ } else return ' ' + attrName + '="' + escapeAttribute(val) + '"';
+}
+
+function processTextOrObjNode(object, key, level, matcher, qNameValidator) {
+ // Extract attributes to pass to matcher
+ const attrValues = this.extractAttributes(object);
+
+ // Push tag to matcher before recursion WITH attributes
+ matcher.push(key, attrValues);
+
+ // Check if this entire node is a stopNode
+ const isStopNode = this.checkStopNode(matcher);
+
+ if (isStopNode) {
+ // For stopNodes, build raw content without entity encoding
+ const rawContent = this.buildRawContent(object);
+ const attrStr = this.buildAttributesForStopNode(object);
+ matcher.pop();
+ return this.buildObjectNode(rawContent, key, attrStr, level);
+ }
+
+ const result = this.j2x(object, level + 1, matcher, qNameValidator);
+ // Pop tag from matcher after recursion
+ matcher.pop();
+
+ // PI/XML-declaration tags must never emit text content — route through
+ // buildTextValNode which correctly ignores the text node for "?" tags.
+ if (key[0] === '?') {
+ return this.buildTextValNode('', key, result.attrStr, level, matcher);
+ } else if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
+ return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level, matcher);
+ } else {
+ return this.buildObjectNode(result.val, key, result.attrStr, level);
+ }
+}
+
+// Helper method to extract attributes from an object
+Builder.prototype.extractAttributes = function (obj) {
+ if (!obj || typeof obj !== 'object') return null;
+
+ const attrValues = {};
+ let hasAttrs = false;
+
+ // Check for attributesGroupName (when attributes are grouped)
+ if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
+ const attrGroup = obj[this.options.attributesGroupName];
+ for (let attrKey in attrGroup) {
+ if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
+ // Remove attribute prefix if present
+ const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
+ ? attrKey.substring(this.options.attributeNamePrefix.length)
+ : attrKey;
+ attrValues[cleanKey] = escapeAttribute(attrGroup[attrKey]);
+ hasAttrs = true;
+ }
+ } else {
+ // Look for individual attributes (prefixed with attributeNamePrefix)
+ for (let key in obj) {
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
+ const attr = this.isAttribute(key);
+ if (attr) {
+ attrValues[attr] = escapeAttribute(obj[key]);
+ hasAttrs = true;
+ }
+ }
+ }
+
+ return hasAttrs ? attrValues : null;
+};
+
+// Build raw content for stopNode without entity encoding
+Builder.prototype.buildRawContent = function (obj) {
+ if (typeof obj === 'string') {
+ return obj; // Already a string, return as-is
+ }
+
+ if (typeof obj !== 'object' || obj === null) {
+ return String(obj);
+ }
+
+ // Check if this is a stopNode data from parser: { "#text": "raw xml", "@_attr": "val" }
+ if (obj[this.options.textNodeName] !== undefined) {
+ return obj[this.options.textNodeName]; // Return raw text without encoding
+ }
+
+ // Build raw XML from nested structure
+ let content = '';
+
+ for (let key in obj) {
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
+
+ // Skip attributes
+ if (this.isAttribute(key)) continue;
+ if (this.options.attributesGroupName && key === this.options.attributesGroupName) continue;
+
+ const value = obj[key];
+
+ if (key === this.options.textNodeName) {
+ content += value; // Raw text
+ } else if (Array.isArray(value)) {
+ // Array of same tag
+ for (let item of value) {
+ if (typeof item === 'string' || typeof item === 'number') {
+ content += `<${key}>${item}${key}>`;
+ } else if (typeof item === 'object' && item !== null) {
+ const nestedContent = this.buildRawContent(item);
+ const nestedAttrs = this.buildAttributesForStopNode(item);
+ if (nestedContent === '') {
+ content += `<${key}${nestedAttrs}/>`;
+ } else {
+ content += `<${key}${nestedAttrs}>${nestedContent}${key}>`;
+ }
+ }
+ }
+ } else if (typeof value === 'object' && value !== null) {
+ // Nested object
+ const nestedContent = this.buildRawContent(value);
+ const nestedAttrs = this.buildAttributesForStopNode(value);
+ if (nestedContent === '') {
+ content += `<${key}${nestedAttrs}/>`;
+ } else {
+ content += `<${key}${nestedAttrs}>${nestedContent}${key}>`;
+ }
+ } else {
+ // Primitive value
+ content += `<${key}>${value}${key}>`;
+ }
+ }
+
+ return content;
+};
+
+// Build attribute string for stopNode (no entity encoding)
+Builder.prototype.buildAttributesForStopNode = function (obj) {
+ if (!obj || typeof obj !== 'object') return '';
+
+ let attrStr = '';
+
+ // Check for attributesGroupName (when attributes are grouped)
+ if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
+ const attrGroup = obj[this.options.attributesGroupName];
+ for (let attrKey in attrGroup) {
+ if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
+ const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
+ ? attrKey.substring(this.options.attributeNamePrefix.length)
+ : attrKey;
+ const val = attrGroup[attrKey];
+ if (val === true && this.options.suppressBooleanAttributes) {
+ attrStr += ' ' + cleanKey;
+ } else {
+ // stopNode content is raw, but the quote delimiter is always escaped
+ // so a quote in the value cannot break out of the attribute (see orderedJs2Xml attr_to_str)
+ attrStr += ' ' + cleanKey + '="' + escapeAttribute(val) + '"';
+ }
+ }
+ } else {
+ // Look for individual attributes
+ for (let key in obj) {
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
+ const attr = this.isAttribute(key);
+ if (attr) {
+ const val = obj[key];
+ if (val === true && this.options.suppressBooleanAttributes) {
+ attrStr += ' ' + attr;
+ } else {
+ // stopNode content is raw, but the quote delimiter is always escaped
+ // so a quote in the value cannot break out of the attribute (see orderedJs2Xml attr_to_str)
+ attrStr += ' ' + attr + '="' + escapeAttribute(val) + '"';
+ }
+ }
+ }
+ }
+
+ return attrStr;
+};
+
+Builder.prototype.buildObjectNode = function (val, key, attrStr, level) {
+ if (val === "") {
+ if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
+ else {
+ return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
+ }
+ } else if (key[0] === "?") {
+ // PI/XML-declaration tags never have body content — treat them like empty.
+ return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
+ } else {
+ let tagEndExp = '' + key + this.tagEndChar;
+ let piClosingChar = "";
+
+ if (key[0] === "?") {
+ piClosingChar = "?";
+ tagEndExp = "";
+ }
+
+ // attrStr is an empty string in case the attribute came as undefined or null
+ if ((attrStr || attrStr === '') && val.indexOf('<') === -1) {
+ return (this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' + val + tagEndExp);
+ } else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) {
+ return this.indentate(level) + `` + this.newLine;
+ } else {
+ return (
+ this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
+ val +
+ this.indentate(level) + tagEndExp);
+ }
+ }
+}
+
+Builder.prototype.closeTag = function (key) {
+ let closeTag = "";
+ if (this.options.unpairedTags.indexOf(key) !== -1) { //unpaired
+ if (!this.options.suppressUnpairedNode) closeTag = "/"
+ } else if (this.options.suppressEmptyNode) { //empty
+ closeTag = "/";
+ } else {
+ closeTag = `>${key}`
+ }
+ return closeTag;
+}
+
+Builder.prototype.checkStopNode = function (matcher) {
+ if (!this.stopNodeExpressions || this.stopNodeExpressions.length === 0) return false;
+
+ for (let i = 0; i < this.stopNodeExpressions.length; i++) {
+ if (matcher.matches(this.stopNodeExpressions[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function buildEmptyObjNode(val, key, attrStr, level) {
+ if (val !== '') {
+ return this.buildObjectNode(val, key, attrStr, level);
+ } else {
+ if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
+ else {
+ return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
+ }
+ }
+}
+
+Builder.prototype.buildTextValNode = function (val, key, attrStr, level, matcher) {
+ if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
+ const safeVal = safeCdata(val);
+ return this.indentate(level) + `` + this.newLine;
+ } else if (this.options.commentPropName !== false && key === this.options.commentPropName) {
+ const safeVal = safeComment(val);
+ return this.indentate(level) + `` + this.newLine;
+ } else if (key[0] === "?") {//PI tag
+ return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
+ } else {
+ // Normal processing: apply tagValueProcessor and entity replacement
+ let textValue = this.options.tagValueProcessor(key, val);
+ textValue = this.replaceEntitiesValue(textValue);
+
+ if (textValue === '') {
+ return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
+ } else {
+ return this.indentate(level) + '<' + key + attrStr + '>' +
+ textValue +
+ '' + key + this.tagEndChar;
+ }
+ }
+}
+
+Builder.prototype.replaceEntitiesValue = function (textValue) {
+ if (textValue && textValue.length > 0 && this.options.processEntities) {
+ for (let i = 0; i < this.options.entities.length; i++) {
+ const entity = this.options.entities[i];
+ textValue = textValue.replace(entity.regex, entity.val);
+ }
+ }
+ return textValue;
+}
+
+function indentate(level) {
+ return this.options.indentBy.repeat(level);
+}
+
+function isAttribute(name /*, options*/) {
+ if (name.startsWith(this.options.attributeNamePrefix) && name !== this.options.textNodeName) {
+ return name.substr(this.attrPrefixLen);
+ } else {
+ return false;
+ }
+}
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/xmlbuilder/json2xml.js
+// Re-export from fast-xml-builder for backward compatibility
+
+/* harmony default export */ const json2xml = (Builder);
+
+// If there are any named exports you also want to re-export:
+
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/util.js
+
+
+const nameStartChar = ':A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
+const nameChar = nameStartChar + '\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
+const nameRegexp = '[' + nameStartChar + '][' + nameChar + ']*';
+const regexName = new RegExp('^' + nameRegexp + '$');
+
+function getAllMatches(string, regex) {
+ const matches = [];
+ let match = regex.exec(string);
+ while (match) {
+ const allmatches = [];
+ allmatches.startIndex = regex.lastIndex - match[0].length;
+ const len = match.length;
+ for (let index = 0; index < len; index++) {
+ allmatches.push(match[index]);
+ }
+ matches.push(allmatches);
+ match = regex.exec(string);
+ }
+ return matches;
+}
+
+const isName = function (string) {
+ const match = regexName.exec(string);
+ return !(match === null || typeof match === 'undefined');
+}
+
+function isExist(v) {
+ return typeof v !== 'undefined';
+}
+
+function isEmptyObject(obj) {
+ return Object.keys(obj).length === 0;
+}
+
+function getValue(v) {
+ if (exports.isExist(v)) {
+ return v;
+ } else {
+ return '';
+ }
+}
+
+/**
+ * Dangerous property names that could lead to prototype pollution or security issues
+ */
+const DANGEROUS_PROPERTY_NAMES = [
+ // '__proto__',
+ // 'constructor',
+ // 'prototype',
+ 'hasOwnProperty',
+ 'toString',
+ 'valueOf',
+ '__defineGetter__',
+ '__defineSetter__',
+ '__lookupGetter__',
+ '__lookupSetter__'
+];
+
+const criticalProperties = ["__proto__", "constructor", "prototype"];
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/validator.js
+
+
+
+
+const validator_defaultOptions = {
+ allowBooleanAttributes: false, //A tag can have attributes without any value
+ unpairedTags: []
+};
+
+//const tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g");
+function validator_validate(xmlData, options) {
+ options = Object.assign({}, validator_defaultOptions, options);
+
+ //xmlData = xmlData.replace(/(\r\n|\n|\r)/gm,"");//make it single line
+ //xmlData = xmlData.replace(/(^\s*<\?xml.*?\?>)/g,"");//Remove XML starting tag
+ //xmlData = xmlData.replace(/()/g,"");//Remove DOCTYPE
+ const tags = [];
+ let tagFound = false;
+
+ //indicates that the root tag has been closed (aka. depth 0 has been reached)
+ let reachedRoot = false;
+
+ if (xmlData[0] === '\ufeff') {
+ // check for byte order mark (BOM)
+ xmlData = xmlData.substr(1);
+ }
+
+ for (let i = 0; i < xmlData.length; i++) {
+
+ if (xmlData[i] === '<' && xmlData[i + 1] === '?') {
+ i += 2;
+ i = readPI(xmlData, i);
+ if (i.err) return i;
+ } else if (xmlData[i] === '<') {
+ //starting of tag
+ //read until you reach to '>' avoiding any '>' in attribute value
+ let tagStartPos = i;
+ i++;
+
+ if (xmlData[i] === '!') {
+ i = readCommentAndCDATA(xmlData, i);
+ continue;
+ } else {
+ let closingTag = false;
+ if (xmlData[i] === '/') {
+ //closing tag
+ closingTag = true;
+ i++;
+ }
+ //read tagname
+ let tagName = '';
+ for (; i < xmlData.length &&
+ xmlData[i] !== '>' &&
+ xmlData[i] !== ' ' &&
+ xmlData[i] !== '\t' &&
+ xmlData[i] !== '\n' &&
+ xmlData[i] !== '\r'; i++
+ ) {
+ tagName += xmlData[i];
+ }
+ tagName = tagName.trim();
+ //console.log(tagName);
+
+ if (tagName[tagName.length - 1] === '/') {
+ //self closing tag without attributes
+ tagName = tagName.substring(0, tagName.length - 1);
+ //continue;
+ i--;
+ }
+ if (!validateTagName(tagName)) {
+ let msg;
+ if (tagName.trim().length === 0) {
+ msg = "Invalid space after '<'.";
+ } else {
+ msg = "Tag '" + tagName + "' is an invalid name.";
+ }
+ return getErrorObject('InvalidTag', msg, getLineNumberForPosition(xmlData, i));
+ }
+
+ const result = readAttributeStr(xmlData, i);
+ if (result === false) {
+ return getErrorObject('InvalidAttr', "Attributes for '" + tagName + "' have open quote.", getLineNumberForPosition(xmlData, i));
+ }
+ let attrStr = result.value;
+ i = result.index;
+
+ if (attrStr[attrStr.length - 1] === '/') {
+ //self closing tag
+ const attrStrStart = i - attrStr.length;
+ attrStr = attrStr.substring(0, attrStr.length - 1);
+ const isValid = validateAttributeString(attrStr, options);
+ if (isValid === true) {
+ tagFound = true;
+ //continue; //text may presents after self closing tag
+ } else {
+ //the result from the nested function returns the position of the error within the attribute
+ //in order to get the 'true' error line, we need to calculate the position where the attribute begins (i - attrStr.length) and then add the position within the attribute
+ //this gives us the absolute index in the entire xml, which we can use to find the line at last
+ return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line));
+ }
+ } else if (closingTag) {
+ if (!result.tagClosed) {
+ return getErrorObject('InvalidTag', "Closing tag '" + tagName + "' doesn't have proper closing.", getLineNumberForPosition(xmlData, i));
+ } else if (attrStr.trim().length > 0) {
+ return getErrorObject('InvalidTag', "Closing tag '" + tagName + "' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos));
+ } else if (tags.length === 0) {
+ return getErrorObject('InvalidTag', "Closing tag '" + tagName + "' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos));
+ } else {
+ const otg = tags.pop();
+ if (tagName !== otg.tagName) {
+ let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos);
+ return getErrorObject('InvalidTag',
+ "Expected closing tag '" + otg.tagName + "' (opened in line " + openPos.line + ", col " + openPos.col + ") instead of closing tag '" + tagName + "'.",
+ getLineNumberForPosition(xmlData, tagStartPos));
+ }
+
+ //when there are no more tags, we reached the root level.
+ if (tags.length == 0) {
+ reachedRoot = true;
+ }
+ }
+ } else {
+ const isValid = validateAttributeString(attrStr, options);
+ if (isValid !== true) {
+ //the result from the nested function returns the position of the error within the attribute
+ //in order to get the 'true' error line, we need to calculate the position where the attribute begins (i - attrStr.length) and then add the position within the attribute
+ //this gives us the absolute index in the entire xml, which we can use to find the line at last
+ return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line));
+ }
+
+ //if the root level has been reached before ...
+ if (reachedRoot === true) {
+ return getErrorObject('InvalidXml', 'Multiple possible root nodes found.', getLineNumberForPosition(xmlData, i));
+ } else if (options.unpairedTags.indexOf(tagName) !== -1) {
+ //don't push into stack
+ } else {
+ tags.push({ tagName, tagStartPos });
+ }
+ tagFound = true;
+ }
+
+ //skip tag text value
+ //It may include comments and CDATA value
+ for (i++; i < xmlData.length; i++) {
+ if (xmlData[i] === '<') {
+ if (xmlData[i + 1] === '!') {
+ //comment or CADATA
+ i++;
+ i = readCommentAndCDATA(xmlData, i);
+ continue;
+ } else if (xmlData[i + 1] === '?') {
+ i = readPI(xmlData, ++i);
+ if (i.err) return i;
+ } else {
+ break;
+ }
+ } else if (xmlData[i] === '&') {
+ const afterAmp = validateAmpersand(xmlData, i);
+ if (afterAmp == -1)
+ return getErrorObject('InvalidChar', "char '&' is not expected.", getLineNumberForPosition(xmlData, i));
+ i = afterAmp;
+ } else {
+ if (reachedRoot === true && !isWhiteSpace(xmlData[i])) {
+ return getErrorObject('InvalidXml', "Extra text at the end", getLineNumberForPosition(xmlData, i));
+ }
+ }
+ } //end of reading tag text value
+ if (xmlData[i] === '<') {
+ i--;
+ }
+ }
+ } else {
+ if (isWhiteSpace(xmlData[i])) {
+ continue;
+ }
+ return getErrorObject('InvalidChar', "char '" + xmlData[i] + "' is not expected.", getLineNumberForPosition(xmlData, i));
+ }
+ }
+
+ if (!tagFound) {
+ return getErrorObject('InvalidXml', 'Start tag expected.', 1);
+ } else if (tags.length == 1) {
+ return getErrorObject('InvalidTag', "Unclosed tag '" + tags[0].tagName + "'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos));
+ } else if (tags.length > 0) {
+ return getErrorObject('InvalidXml', "Invalid '" +
+ JSON.stringify(tags.map(t => t.tagName), null, 4).replace(/\r?\n/g, '') +
+ "' found.", { line: 1, col: 1 });
+ }
+
+ return true;
+};
+
+function isWhiteSpace(char) {
+ return char === ' ' || char === '\t' || char === '\n' || char === '\r';
+}
+/**
+ * Read Processing insstructions and skip
+ * @param {*} xmlData
+ * @param {*} i
+ */
+function readPI(xmlData, i) {
+ const start = i;
+ for (; i < xmlData.length; i++) {
+ if (xmlData[i] == '?' || xmlData[i] == ' ') {
+ //tagname
+ const tagname = xmlData.substr(start, i - start);
+ if (i > 5 && tagname === 'xml') {
+ return getErrorObject('InvalidXml', 'XML declaration allowed only at the start of the document.', getLineNumberForPosition(xmlData, i));
+ } else if (xmlData[i] == '?' && xmlData[i + 1] == '>') {
+ //check if valid attribut string
+ i++;
+ break;
+ } else {
+ continue;
+ }
+ }
+ }
+ return i;
+}
+
+function readCommentAndCDATA(xmlData, i) {
+ if (xmlData.length > i + 5 && xmlData[i + 1] === '-' && xmlData[i + 2] === '-') {
+ //comment
+ for (i += 3; i < xmlData.length; i++) {
+ if (xmlData[i] === '-' && xmlData[i + 1] === '-' && xmlData[i + 2] === '>') {
+ i += 2;
+ break;
+ }
+ }
+ } else if (
+ xmlData.length > i + 8 &&
+ xmlData[i + 1] === 'D' &&
+ xmlData[i + 2] === 'O' &&
+ xmlData[i + 3] === 'C' &&
+ xmlData[i + 4] === 'T' &&
+ xmlData[i + 5] === 'Y' &&
+ xmlData[i + 6] === 'P' &&
+ xmlData[i + 7] === 'E'
+ ) {
+ let angleBracketsCount = 1;
+ for (i += 8; i < xmlData.length; i++) {
+ if (xmlData[i] === '<') {
+ angleBracketsCount++;
+ } else if (xmlData[i] === '>') {
+ angleBracketsCount--;
+ if (angleBracketsCount === 0) {
+ break;
+ }
+ }
+ }
+ } else if (
+ xmlData.length > i + 9 &&
+ xmlData[i + 1] === '[' &&
+ xmlData[i + 2] === 'C' &&
+ xmlData[i + 3] === 'D' &&
+ xmlData[i + 4] === 'A' &&
+ xmlData[i + 5] === 'T' &&
+ xmlData[i + 6] === 'A' &&
+ xmlData[i + 7] === '['
+ ) {
+ for (i += 8; i < xmlData.length; i++) {
+ if (xmlData[i] === ']' && xmlData[i + 1] === ']' && xmlData[i + 2] === '>') {
+ i += 2;
+ break;
+ }
+ }
+ }
+
+ return i;
+}
+
+const doubleQuote = '"';
+const singleQuote = "'";
+
+/**
+ * Keep reading xmlData until '<' is found outside the attribute value.
+ * @param {string} xmlData
+ * @param {number} i
+ */
+function readAttributeStr(xmlData, i) {
+ let attrStr = '';
+ let startChar = '';
+ let tagClosed = false;
+ for (; i < xmlData.length; i++) {
+ if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) {
+ if (startChar === '') {
+ startChar = xmlData[i];
+ } else if (startChar !== xmlData[i]) {
+ //if vaue is enclosed with double quote then single quotes are allowed inside the value and vice versa
+ } else {
+ startChar = '';
+ }
+ } else if (xmlData[i] === '>') {
+ if (startChar === '') {
+ tagClosed = true;
+ break;
+ }
+ }
+ attrStr += xmlData[i];
+ }
+ if (startChar !== '') {
+ return false;
+ }
+
+ return {
+ value: attrStr,
+ index: i,
+ tagClosed: tagClosed
+ };
+}
+
+/**
+ * Select all the attributes whether valid or invalid.
+ */
+const validAttrStrRegxp = new RegExp('(\\s*)([^\\s=]+)(\\s*=)?(\\s*([\'"])(([\\s\\S])*?)\\5)?', 'g');
+
+//attr, ="sd", a="amit's", a="sd"b="saf", ab cd=""
+
+function validateAttributeString(attrStr, options) {
+ //console.log("start:"+attrStr+":end");
+
+ //if(attrStr.trim().length === 0) return true; //empty string
+
+ const matches = getAllMatches(attrStr, validAttrStrRegxp);
+ const attrNames = {};
+
+ for (let i = 0; i < matches.length; i++) {
+ if (matches[i][1].length === 0) {
+ //nospace before attribute name: a="sd"b="saf"
+ return getErrorObject('InvalidAttr', "Attribute '" + matches[i][2] + "' has no space in starting.", getPositionFromMatch(matches[i]))
+ } else if (matches[i][3] !== undefined && matches[i][4] === undefined) {
+ return getErrorObject('InvalidAttr', "Attribute '" + matches[i][2] + "' is without value.", getPositionFromMatch(matches[i]));
+ } else if (matches[i][3] === undefined && !options.allowBooleanAttributes) {
+ //independent attribute: ab
+ return getErrorObject('InvalidAttr', "boolean attribute '" + matches[i][2] + "' is not allowed.", getPositionFromMatch(matches[i]));
+ }
+ /* else if(matches[i][6] === undefined){//attribute without value: ab=
+ return { err: { code:"InvalidAttr",msg:"attribute " + matches[i][2] + " has no value assigned."}};
+ } */
+ const attrName = matches[i][2];
+ if (!validateAttrName(attrName)) {
+ return getErrorObject('InvalidAttr', "Attribute '" + attrName + "' is an invalid name.", getPositionFromMatch(matches[i]));
+ }
+ if (!Object.prototype.hasOwnProperty.call(attrNames, attrName)) {
+ //check for duplicate attribute.
+ attrNames[attrName] = 1;
+ } else {
+ return getErrorObject('InvalidAttr', "Attribute '" + attrName + "' is repeated.", getPositionFromMatch(matches[i]));
+ }
+ }
+
+ return true;
+}
+
+function validateNumberAmpersand(xmlData, i) {
+ let re = /\d/;
+ if (xmlData[i] === 'x') {
+ i++;
+ re = /[\da-fA-F]/;
+ }
+ for (; i < xmlData.length; i++) {
+ if (xmlData[i] === ';')
+ return i;
+ if (!xmlData[i].match(re))
+ break;
+ }
+ return -1;
+}
+
+function validateAmpersand(xmlData, i) {
+ // https://www.w3.org/TR/xml/#dt-charref
+ i++;
+ if (xmlData[i] === ';')
+ return -1;
+ if (xmlData[i] === '#') {
+ i++;
+ return validateNumberAmpersand(xmlData, i);
+ }
+ let count = 0;
+ for (; i < xmlData.length; i++, count++) {
+ if (xmlData[i].match(/\w/) && count < 20)
+ continue;
+ if (xmlData[i] === ';')
+ break;
+ return -1;
+ }
+ return i;
+}
+
+function getErrorObject(code, message, lineNumber) {
+ return {
+ err: {
+ code: code,
+ msg: message,
+ line: lineNumber.line || lineNumber,
+ col: lineNumber.col,
+ },
+ };
+}
+
+function validateAttrName(attrName) {
+ return isName(attrName);
+}
+
+// const startsWithXML = /^xml/i;
+
+function validateTagName(tagname) {
+ return isName(tagname) /* && !tagname.match(startsWithXML) */;
+}
+
+//this function returns the line number for the character at the given index
+function getLineNumberForPosition(xmlData, index) {
+ const lines = xmlData.substring(0, index).split(/\r?\n/);
+ return {
+ line: lines.length,
+
+ // column number is last line's length + 1, because column numbering starts at 1:
+ col: lines[lines.length - 1].length + 1
+ };
+}
+
+//this function returns the position of the first character of match within attrStr
+function getPositionFromMatch(match) {
+ return match.startIndex + match[1].length;
+}
+
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/fxp.js
+
+
+
+
+
+
+const XMLValidator = {
+ validate: validator_validate
+}
+
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js
+
+
+
+const defaultOnDangerousProperty = (name) => {
+ if (DANGEROUS_PROPERTY_NAMES.includes(name)) {
+ return "__" + name;
+ }
+ return name;
+};
+
+
+const OptionsBuilder_defaultOptions = {
+ preserveOrder: false,
+ attributeNamePrefix: '@_',
+ attributesGroupName: false,
+ textNodeName: '#text',
+ ignoreAttributes: true,
+ removeNSPrefix: false, // remove NS from tag name or attribute name if true
+ allowBooleanAttributes: false, //a tag can have attributes without any value
+ //ignoreRootElement : false,
+ parseTagValue: true,
+ parseAttributeValue: false,
+ trimValues: true, //Trim string values of tag and attributes
+ cdataPropName: false,
+ numberParseOptions: {
+ hex: true,
+ leadingZeros: true,
+ eNotation: true,
+ unicode: false
+ },
+ tagValueProcessor: function (tagName, val) {
+ return val;
+ },
+ attributeValueProcessor: function (attrName, val) {
+ return val;
+ },
+ stopNodes: [], //nested tags will not be parsed even for errors
+ alwaysCreateTextNode: false,
+ isArray: () => false,
+ commentPropName: false,
+ unpairedTags: [],
+ processEntities: true,
+ htmlEntities: false,
+ entityDecoder: null,
+ ignoreDeclaration: false,
+ ignorePiTags: false,
+ transformTagName: false,
+ transformAttributeName: false,
+ updateTag: function (tagName, jPath, attrs) {
+ return tagName
+ },
+ // skipEmptyListItem: false
+ captureMetaData: false,
+ maxNestedTags: 100,
+ strictReservedNames: true,
+ jPath: true, // if true, pass jPath string to callbacks; if false, pass matcher instance
+ onDangerousProperty: defaultOnDangerousProperty
+};
+
+
+/**
+ * Validates that a property name is safe to use
+ * @param {string} propertyName - The property name to validate
+ * @param {string} optionName - The option field name (for error message)
+ * @throws {Error} If property name is dangerous
+ */
+function validatePropertyName(propertyName, optionName) {
+ if (typeof propertyName !== 'string') {
+ return; // Only validate string property names
+ }
+
+ const normalized = propertyName.toLowerCase();
+ if (DANGEROUS_PROPERTY_NAMES.some(dangerous => normalized === dangerous.toLowerCase())) {
+ throw new Error(
+ `[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution`
+ );
+ }
+
+ if (criticalProperties.some(dangerous => normalized === dangerous.toLowerCase())) {
+ throw new Error(
+ `[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution`
+ );
+ }
+}
+
+/**
+ * Normalizes processEntities option for backward compatibility
+ * @param {boolean|object} value
+ * @returns {object} Always returns normalized object
+ */
+function normalizeProcessEntities(value, htmlEntities) {
+ // Boolean backward compatibility
+ if (typeof value === 'boolean') {
+ return {
+ enabled: value, // true or false
+ maxEntitySize: 10000,
+ maxExpansionDepth: 10000,
+ maxTotalExpansions: Infinity,
+ maxExpandedLength: 100000,
+ maxEntityCount: 1000,
+ allowedTags: null,
+ tagFilter: null,
+ appliesTo: "all",
+ };
+ }
+
+ // Object config - merge with defaults
+ if (typeof value === 'object' && value !== null) {
+ return {
+ enabled: value.enabled !== false,
+ maxEntitySize: Math.max(1, value.maxEntitySize ?? 10000),
+ maxExpansionDepth: Math.max(1, value.maxExpansionDepth ?? 10000),
+ maxTotalExpansions: Math.max(1, value.maxTotalExpansions ?? Infinity),
+ maxExpandedLength: Math.max(1, value.maxExpandedLength ?? 100000),
+ maxEntityCount: Math.max(1, value.maxEntityCount ?? 1000),
+ allowedTags: value.allowedTags ?? null,
+ tagFilter: value.tagFilter ?? null,
+ appliesTo: value.appliesTo ?? "all",
+ };
+ }
+
+ // Default to enabled with limits
+ return normalizeProcessEntities(true);
+}
+
+const buildOptions = function (options) {
+ const built = Object.assign({}, OptionsBuilder_defaultOptions, options);
+
+ // Validate property names to prevent prototype pollution
+ const propertyNameOptions = [
+ { value: built.attributeNamePrefix, name: 'attributeNamePrefix' },
+ { value: built.attributesGroupName, name: 'attributesGroupName' },
+ { value: built.textNodeName, name: 'textNodeName' },
+ { value: built.cdataPropName, name: 'cdataPropName' },
+ { value: built.commentPropName, name: 'commentPropName' }
+ ];
+
+ for (const { value, name } of propertyNameOptions) {
+ if (value) {
+ validatePropertyName(value, name);
+ }
+ }
+
+ if (built.onDangerousProperty === null) {
+ built.onDangerousProperty = defaultOnDangerousProperty;
+ }
+
+ // Always normalize processEntities for backward compatibility and validation
+ built.processEntities = normalizeProcessEntities(built.processEntities, built.htmlEntities);
+ built.unpairedTagsSet = new Set(built.unpairedTags);
+ // Convert old-style stopNodes for backward compatibility
+ if (built.stopNodes && Array.isArray(built.stopNodes)) {
+ built.stopNodes = built.stopNodes.map(node => {
+ if (typeof node === 'string' && node.startsWith('*.')) {
+ // Old syntax: *.tagname meant "tagname anywhere"
+ // Convert to new syntax: ..tagname
+ return '..' + node.substring(2);
+ }
+ return node;
+ });
+ }
+ //console.debug(built.processEntities)
+ return built;
+};
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/xmlparser/xmlNode.js
+
+
+let METADATA_SYMBOL;
+
+if (typeof Symbol !== "function") {
+ METADATA_SYMBOL = "@@xmlMetadata";
+} else {
+ METADATA_SYMBOL = Symbol("XML Node Metadata");
+}
+
+class XmlNode {
+ constructor(tagname) {
+ this.tagname = tagname;
+ this.child = []; //nested tags, text, cdata, comments in order
+ this[":@"] = Object.create(null); //attributes map
+ }
+ add(key, val) {
+ // this.child.push( {name : key, val: val, isCdata: isCdata });
+ if (key === "__proto__") key = "#__proto__";
+ this.child.push({ [key]: val });
+ }
+ addChild(node, startIndex) {
+ if (node.tagname === "__proto__") node.tagname = "#__proto__";
+ if (node[":@"] && Object.keys(node[":@"]).length > 0) {
+ this.child.push({ [node.tagname]: node.child, [":@"]: node[":@"] });
+ } else {
+ this.child.push({ [node.tagname]: node.child });
+ }
+ // if requested, add the startIndex
+ if (startIndex !== undefined) {
+ // Note: for now we just overwrite the metadata. If we had more complex metadata,
+ // we might need to do an object append here: metadata = { ...metadata, startIndex }
+ this.child[this.child.length - 1][METADATA_SYMBOL] = { startIndex };
+ }
+ }
+ /** symbol used for metadata */
+ static getMetaDataSymbol() {
+ return METADATA_SYMBOL;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
+
+
+class DocTypeReader {
+ constructor(options, xmlVersion) {
+ this.suppressValidationErr = !options;
+ this.options = options;
+ this.xmlVersion = xmlVersion || 1.0;
+ }
+
+ setXmlVersion(xmlVersion = 1.0) {
+ this.xmlVersion = xmlVersion;
+ }
+ readDocType(xmlData, i) {
+ const entities = Object.create(null);
+ let entityCount = 0;
+
+ if (xmlData[i + 3] === 'O' &&
+ xmlData[i + 4] === 'C' &&
+ xmlData[i + 5] === 'T' &&
+ xmlData[i + 6] === 'Y' &&
+ xmlData[i + 7] === 'P' &&
+ xmlData[i + 8] === 'E') {
+ i = i + 9;
+ let angleBracketsCount = 1;
+ let hasBody = false, comment = false;
+ let exp = "";
+ for (; i < xmlData.length; i++) {
+ if (xmlData[i] === '<' && !comment) { //Determine the tag type
+ if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
+ i += 7;
+ let entityName, val;
+ [entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr);
+ if (val.indexOf("&") === -1) { //Parameter entities are not supported
+ if (this.options.enabled !== false &&
+ this.options.maxEntityCount != null &&
+ entityCount >= this.options.maxEntityCount) {
+ throw new Error(
+ `Entity count (${entityCount + 1}) exceeds maximum allowed (${this.options.maxEntityCount})`
+ );
+ }
+ //const escaped = entityName.replace(/[.\-+*:]/g, '\\.');
+ //const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ entities[entityName] = val;
+ entityCount++;
+ }
+ }
+ else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) {
+ i += 8;//Not supported
+ const { index } = this.readElementExp(xmlData, i + 1);
+ i = index;
+ } else if (hasBody && hasSeq(xmlData, "!ATTLIST", i)) {
+ i += 8;//Not supported
+ // const {index} = this.readAttlistExp(xmlData,i+1);
+ // i = index;
+ } else if (hasBody && hasSeq(xmlData, "!NOTATION", i)) {
+ i += 9;//Not supported
+ const { index } = this.readNotationExp(xmlData, i + 1, this.suppressValidationErr);
+ i = index;
+ } else if (hasSeq(xmlData, "!--", i)) comment = true;
+ else throw new Error(`Invalid DOCTYPE`);
+
+ angleBracketsCount++;
+ exp = "";
+ } else if (xmlData[i] === '>') { //Read tag content
+ if (comment) {
+ if (xmlData[i - 1] === "-" && xmlData[i - 2] === "-") {
+ comment = false;
+ angleBracketsCount--;
+ }
+ } else {
+ angleBracketsCount--;
+ }
+ if (angleBracketsCount === 0) {
+ break;
+ }
+ } else if (xmlData[i] === '[') {
+ hasBody = true;
+ } else {
+ exp += xmlData[i];
+ }
+ }
+ if (angleBracketsCount !== 0) {
+ throw new Error(`Unclosed DOCTYPE`);
+ }
+ } else {
+ throw new Error(`Invalid Tag instead of DOCTYPE`);
+ }
+ return { entities, i };
+ }
+ readEntityExp(xmlData, i) {
+ //External entities are not supported
+ //
+
+ //Parameter entities are not supported
+ //
+
+ //Internal entities are supported
+ //
+
+ // Skip leading whitespace after this.options.maxEntitySize) {
+ throw new Error(
+ `Entity "${entityName}" size (${entityValue.length}) exceeds maximum allowed size (${this.options.maxEntitySize})`
+ );
+ }
+
+ i--;
+ return [entityName, entityValue, i];
+ }
+
+ readNotationExp(xmlData, i) {
+ // Skip leading whitespace after
+ //
+ //
+ //
+ //
+
+ // Skip leading whitespace after {
+ while (index < data.length && /\s/.test(data[index])) {
+ index++;
+ }
+ return index;
+};
+
+
+
+function hasSeq(data, seq, i) {
+ for (let j = 0; j < seq.length; j++) {
+ if (seq[j] !== data[i + j + 1]) return false;
+ }
+ return true;
+}
+
+function validateEntityName(name, xmlVersion) {
+ if (qName(name, { xmlVersion: xmlVersion }))
+ return name;
+ else
+ throw new Error(`Invalid entity name ${name}`);
+}
+;// CONCATENATED MODULE: ./node_modules/anynum/digitTable.js
+/**
+ * Flat lookup table: maps Unicode code point → ASCII digit (0-9).
+ * Only decimal digit characters (Unicode category Nd) are included.
+ *
+ * Strategy: Int32Array of size (maxCodePoint - minCodePoint + 1).
+ * Value 0xFF means "not a digit". Value 0-9 is the ASCII digit value.
+ * This gives O(1) lookup with no branching, no bisect, no loop.
+ *
+ * Memory: range is 0x0660 to 0x1FBF0 → ~129,936 entries × 1 byte = ~127 KB.
+ * Acceptable for a one-time init; lookup is a single array index.
+ */
+
+// All known Unicode Nd (decimal digit) script zero code points.
+// Each script has exactly 10 consecutive digits: zero+0 .. zero+9.
+const SCRIPT_ZEROS = [
+ // Basic Latin (ASCII) — included for completeness / pass-through
+ 0x0030, // 0-9
+
+ // Arabic scripts
+ 0x0660, // Arabic-Indic ٠١٢٣٤٥٦٧٨٩
+ 0x06F0, // Extended Arabic-Indic (Urdu/Persian/Sindhi) ۰۱۲۳
+
+ // Indic scripts
+ 0x0966, // Devanagari ०१२३४५६७८९
+ 0x09E6, // Bengali ০১২৩৪৫৬৭৮৯
+ 0x0A66, // Gurmukhi ੦੧੨੩੪੫੬੭੮੯
+ 0x0AE6, // Gujarati ૦૧૨૩૪૫૬૭૮૯
+ 0x0B66, // Odia ୦୧୨୩୪୫୬୭୮୯
+ 0x0BE6, // Tamil ௦௧௨௩௪௫௬௭௮௯
+ 0x0C66, // Telugu ౦౧౨౩౪౫౬౭౮౯
+ 0x0CE6, // Kannada ೦೧೨೩೪೫೬೭೮೯
+ 0x0D66, // Malayalam ൦൧൨൩൪൫൬൭൮൯
+ 0x0DE6, // Sinhala Archaic ෦෧෨෩෪෫෬෭෮෯
+
+ // Southeast Asian scripts
+ 0x0E50, // Thai ๐๑๒๓๔๕๖๗๘๙
+ 0x0ED0, // Lao ໐໑໒໓໔໕໖໗໘໙
+ 0x0F20, // Tibetan ༠༡༢༣༤༥༦༧༨༩
+ 0x1040, // Myanmar ၀၁၂၃၄၅၆၇၈၉
+ 0x1090, // Myanmar Shan ႐႑႒႓႔႕႖႗႘႙
+ 0x17E0, // Khmer ០១២៣៤៥៦៧៨៩
+ 0x1810, // Mongolian ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙
+ 0x1946, // Limbu ᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏
+ 0x19D0, // New Tai Lue ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙
+ 0x1A80, // Tai Tham Hora ᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉
+ 0x1A90, // Tai Tham Tham ᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙
+ 0x1B50, // Balinese ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙
+ 0x1BB0, // Sundanese ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹
+ 0x1C40, // Lepcha ᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉
+ 0x1C50, // Ol Chiki ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙
+
+ // Fullwidth (CJK context)
+ 0xFF10, // Fullwidth 0123456789
+
+ // Mathematical digit variants (Unicode math block)
+ 0x1D7CE, // Mathematical Bold
+ 0x1D7D8, // Mathematical Double-Struck
+ 0x1D7E2, // Mathematical Sans-Serif
+ 0x1D7EC, // Mathematical Sans-Serif Bold
+ 0x1D7F6, // Mathematical Monospace
+
+ // Other scripts
+ 0x104A0, // Osmanya 𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩
+ 0x10D30, // Hanifi Rohingya 𐴰𐴱𐴲𐴳𐴴𐴵𐴶𐴷𐴸𐴹
+ 0x11066, // Brahmi 𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯
+ 0x110F0, // Sora Sompeng 𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹
+ 0x11136, // Chakma 𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿
+ 0x111D0, // Sharada 𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙
+ 0x112F0, // Khudawadi 𑋰𑋱𑋲𑋳𑋴𑋵𑋶𑋷𑋸𑋹
+ 0x11450, // Newa 𑑐𑑑𑑒𑑓𑑔𑑕𑑖𑑗𑑘𑑙
+ 0x114D0, // Tirhuta 𑓐𑓑𑓒𑓓𑓔𑓕𑓖𑓗𑓘𑓙
+ 0x11650, // Modi 𑙐𑙑𑙒𑙓𑙔𑙕𑙖𑙗𑙘𑙙
+ 0x116C0, // Takri 𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉
+ 0x11730, // Ahom 𑜰𑜱𑜲𑜳𑜴𑜵𑜶𑜷𑜸𑜹
+ 0x118E0, // Warang Citi 𑣠𑣡𑣢𑣣𑣤𑣥𑣦𑣧𑣨𑣩
+ 0x11950, // Dives Akuru 𑥐𑥑𑥒𑥓𑥔𑥕𑥖𑥗𑥘𑥙
+ 0x11BF0, // Khitan Small Script
+ 0x11C50, // Bhaiksuki 𑱐𑱑𑱒𑱓𑱔𑱕𑱖𑱗𑱘𑱙
+ 0x11D50, // Masaram Gondi 𑵐𑵑𑵒𑵓𑵔𑵕𑵖𑵗𑵘𑵙
+ 0x11DA0, // Gunjala Gondi 𑶠𑶡𑶢𑶣𑶤𑶥𑶦𑶧𑶨𑶩
+ 0x11F50, // Kawi 𑽐𑽑𑽒𑽓𑽔𑽕𑽖𑽗𑽘𑽙
+ 0x16A60, // Mro 𖩠𖩡𖩢𖩣𖩤𖩥𖩦𖩧𖩨𖩩
+ 0x16AC0, // Tangsa 𖫀𖫁𖫂𖫃𖫄𖫅𖫆𖫇𖫈𖫉
+ 0x16B50, // Pahawh Hmong 𖭐𖭑𖭒𖭓𖭔𖭕𖭖𖭗𖭘𖭙
+ 0x1E140, // Nyiakeng Puachue Hmong 𞅀𞅁𞅂𞅃𞅄𞅅𞅆𞅇𞅈𞅉
+ 0x1E2F0, // Wancho 𞋰𞋱𞋲𞋳𞋴𞋵𞋶𞋷𞋸𞋹
+ 0x1E4F0, // Nag Mundari 𞓰𞓱𞓲𞓳𞓴𞓵𞓶𞓷𞓸𞓹
+ 0x1E950, // Adlam 𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙
+ 0x1FBF0, // Segmented digit symbols 🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹
+];
+
+// Build a sparse Map for scripts above 0xFFFF (surrogate-pair range).
+// These can't go into a flat Uint8Array indexed by code point efficiently.
+const NOT_DIGIT = 0xFF;
+const HIGH_MAP = new Map(); // codePoint → digit value (0-9)
+
+const LOW_MAX = 0xFFFF;
+const LOW_MIN = 0x0660; // first non-ASCII digit script
+
+// Flat Uint8Array covering 0x0660 .. 0xFFFF
+const TABLE_OFFSET = LOW_MIN;
+const TABLE_SIZE = LOW_MAX - LOW_MIN + 1;
+const TABLE = new Uint8Array(TABLE_SIZE).fill(NOT_DIGIT);
+
+for (const zero of SCRIPT_ZEROS) {
+ for (let d = 0; d < 10; d++) {
+ const cp = zero + d;
+ if (cp <= LOW_MAX) {
+ TABLE[cp - TABLE_OFFSET] = d;
+ } else {
+ HIGH_MAP.set(cp, d);
+ }
+ }
+}
+
+
+
+;// CONCATENATED MODULE: ./node_modules/anynum/anynum.js
+
+
+
+
+const CHAR_0 = 48; // '0'.charCodeAt(0)
+const CHAR_9 = 57; // '9'.charCodeAt(0)
+const CHAR_MINUS = 45; // '-'.charCodeAt(0)
+
+// Unicode minus/hyphen variants worth normalizing to ASCII '-' in numeric context:
+// U+2212 MINUS SIGN − (mathematically correct minus)
+// U+FF0D FULLWIDTH HYPHEN-MINUS - (Japanese fullwidth context)
+// U+FE63 SMALL HYPHEN-MINUS ﹣ (small form variant)
+//
+// NOT normalized (deliberate):
+// U+2013 EN DASH – (punctuation, not a numeric sign)
+// U+2014 EM DASH — (punctuation)
+// U+2010 HYPHEN ‐ (typographic hyphen)
+//
+// Rationale: only characters a human or locale formatter would plausibly use
+// as a numeric minus sign are normalized. Dashes used for punctuation are left
+// alone to avoid mangling non-numeric strings.
+const MINUS_SET = new Set([0x2212, 0xFF0D, 0xFE63]);
+
+/**
+ * Normalize all Unicode decimal digit characters in a string to ASCII (0-9),
+ * and normalize Unicode minus variants to ASCII '-' (U+002D).
+ *
+ * Non-digit, non-minus characters are passed through unchanged.
+ *
+ * Performance design:
+ * - Fast path: if the string has no convertible characters, return it unchanged
+ * (zero allocation).
+ * - BMP digits (0x0660..0xFFFF excl. surrogates): flat Uint8Array lookup (O(1)).
+ * - Supplementary plane digits (> 0xFFFF, encoded as surrogate pairs): Map lookup.
+ * - Minus variants: checked inline with a small fixed Set.
+ *
+ * @param {string} str
+ * @returns {string}
+ */
+function anynum(str) {
+ if (typeof str !== 'string') return str;
+
+ const len = str.length;
+ if (len === 0) return str;
+
+ // Scan for first character needing conversion.
+ // If none found, return original string (zero allocation).
+ let firstHit = -1;
+
+ for (let i = 0; i < len; i++) {
+ const cc = str.charCodeAt(i);
+
+ // ASCII digit or ASCII minus — already normalized, skip fast
+ if ((cc >= CHAR_0 && cc <= CHAR_9) || cc === CHAR_MINUS) continue;
+
+ // Below first unicode digit script — check minus variants only
+ if (cc < TABLE_OFFSET) {
+ if (MINUS_SET.has(cc)) { firstHit = i; break; }
+ continue;
+ }
+
+ // Surrogate pairs live in BMP range 0xD800-0xDFFF — check before TABLE
+ if (cc >= 0xD800 && cc <= 0xDBFF) {
+ if (i + 1 < len) {
+ const low = str.charCodeAt(i + 1);
+ if (low >= 0xDC00 && low <= 0xDFFF) {
+ const cp = 0x10000 + ((cc - 0xD800) << 10) + (low - 0xDC00);
+ if (HIGH_MAP.has(cp)) { firstHit = i; break; }
+ }
+ }
+ continue;
+ }
+
+ // BMP non-surrogate: flat table lookup; also check minus variants in this range
+ if (TABLE[cc - TABLE_OFFSET] !== NOT_DIGIT || MINUS_SET.has(cc)) {
+ firstHit = i;
+ break;
+ }
+ }
+
+ // Nothing to replace — return original, zero allocation
+ if (firstHit === -1) return str;
+
+ // Build result: copy unchanged prefix, then convert from firstHit onward
+ const chars = [];
+
+ if (firstHit > 0) chars.push(str.slice(0, firstHit));
+
+ for (let i = firstHit; i < len; i++) {
+ const cc = str.charCodeAt(i);
+
+ // ASCII digit or ASCII minus — pass through
+ if ((cc >= CHAR_0 && cc <= CHAR_9) || cc === CHAR_MINUS) {
+ chars.push(str[i]);
+ continue;
+ }
+
+ // Below TABLE_OFFSET — check minus variants, else pass through
+ if (cc < TABLE_OFFSET) {
+ chars.push(MINUS_SET.has(cc) ? '-' : str[i]);
+ continue;
+ }
+
+ // Surrogate pairs
+ if (cc >= 0xD800 && cc <= 0xDBFF) {
+ if (i + 1 < len) {
+ const low = str.charCodeAt(i + 1);
+ if (low >= 0xDC00 && low <= 0xDFFF) {
+ const cp = 0x10000 + ((cc - 0xD800) << 10) + (low - 0xDC00);
+ const d = HIGH_MAP.get(cp);
+ if (d !== undefined) {
+ chars.push(String.fromCharCode(d + 48));
+ i++; // consume low surrogate
+ continue;
+ }
+ }
+ }
+ chars.push(str[i]);
+ continue;
+ }
+
+ // BMP non-surrogate: flat table lookup + minus variants
+ if (MINUS_SET.has(cc)) {
+ chars.push('-');
+ continue;
+ }
+ const d = TABLE[cc - TABLE_OFFSET];
+ chars.push(d !== NOT_DIGIT ? String.fromCharCode(d + 48) : str[i]);
+ }
+
+ return chars.join('');
+}
+
+
+/* harmony default export */ const anynum_anynum = (anynum);
+;// CONCATENATED MODULE: ./node_modules/strnum/strnum.js
+const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
+const binRegex = /^0b[01]+$/;
+const octRegex = /^0o[0-7]+$/;
+const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
+
+
+
+const consider = {
+ hex: true,
+ binary: false,
+ octal: false,
+ leadingZeros: true,
+ decimalPoint: "\.",
+ eNotation: true,
+ //skipLike: /regex/,
+ infinity: "original", // "null", "infinity" (Infinity type), "string" ("Infinity" (the string literal))
+ unicode: false,
+};
+
+function toNumber(str, options = {}) {
+ options = Object.assign({}, consider, options);
+ if (!str || typeof str !== "string") return str;
+
+ let trimmedStr = str.trim();
+
+ if (trimmedStr.length === 0) return str;
+ else if (options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str;
+ else if (trimmedStr === "0") return 0;
+
+ if (options.unicode) {
+ trimmedStr = anynum_anynum(trimmedStr);
+ if (trimmedStr === "0") return 0; // re-check after normalization
+ }
+ if (options.hex && hexRegex.test(trimmedStr)) {
+ return parse_int(trimmedStr, 16);
+ } else if (options.binary && binRegex.test(trimmedStr)) {
+ return parse_int(trimmedStr, 2);
+ } else if (options.octal && octRegex.test(trimmedStr)) {
+ return parse_int(trimmedStr, 8);
+ } else if (!isFinite(trimmedStr)) { //Infinity
+ return handleInfinity(str, Number(trimmedStr), options);
+ } else if (trimmedStr.includes('e') || trimmedStr.includes('E')) { //eNotation
+ return resolveEnotation(str, trimmedStr, options);
+ } else {
+ //separate negative sign, leading zeros, and rest number
+ const match = numRegex.exec(trimmedStr);
+ // +00.123 => [ , '+', '00', '.123', ..
+ if (match) {
+ const sign = match[1] || "";
+ const leadingZeros = match[2];
+ let numTrimmedByZeros = trimZeros(match[3]); //complete num without leading zeros
+ const decimalAdjacentToLeadingZeros = sign ? // 0., -00., 000.
+ str[leadingZeros.length + 1] === "."
+ : str[leadingZeros.length] === ".";
+
+ //trim ending zeros for floating number
+ if (!options.leadingZeros //leading zeros are not allowed
+ && (leadingZeros.length > 1
+ || (leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros))) {
+ // 00, 00.3, +03.24, 03, 03.24
+ return str;
+ }
+ else {//no leading zeros or leading zeros are allowed
+ const num = Number(trimmedStr);
+ const parsedStr = String(num);
+
+ if (num === 0) return num;
+ if (parsedStr.search(/[eE]/) !== -1) { //given number is long and parsed to eNotation
+ if (options.eNotation) return num;
+ else return str;
+ } else if (trimmedStr.indexOf(".") !== -1) { //floating number
+ if (parsedStr === "0") return num; //0.0
+ else if (parsedStr === numTrimmedByZeros) return num; //0.456. 0.79000
+ else if (parsedStr === `${sign}${numTrimmedByZeros}`) return num;
+ else return str;
+ }
+
+ let n = leadingZeros ? numTrimmedByZeros : trimmedStr;
+ if (leadingZeros) {
+ // -009 => -9
+ return (n === parsedStr) || (sign + n === parsedStr) ? num : str
+ } else {
+ // +9
+ return (n === parsedStr) || (n === sign + parsedStr) ? num : str
+ }
+ }
+ } else { //non-numeric string
+ return str;
+ }
+ }
+}
+
+const eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;
+function resolveEnotation(str, trimmedStr, options) {
+ if (!options.eNotation) return str;
+ const notation = trimmedStr.match(eNotationRegx);
+ if (notation) {
+ let sign = notation[1] || "";
+ const eChar = notation[3].indexOf("e") === -1 ? "E" : "e";
+ const leadingZeros = notation[2];
+ const eAdjacentToLeadingZeros = sign ? // 0E.
+ str[leadingZeros.length + 1] === eChar
+ : str[leadingZeros.length] === eChar;
+
+ if (leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str;
+ else if (leadingZeros.length === 1
+ && (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)) {
+ return Number(trimmedStr);
+ } else if (leadingZeros.length > 0) {
+ // Has leading zeros — only accept if leadingZeros option allows it
+ if (options.leadingZeros && !eAdjacentToLeadingZeros) {
+ trimmedStr = (notation[1] || "") + notation[3];
+ return Number(trimmedStr);
+ } else return str;
+ } else {
+ // No leading zeros — always valid e-notation, parse it
+ return Number(trimmedStr);
+ }
+ } else {
+ return str;
+ }
+}
+
+/**
+ *
+ * @param {string} numStr without leading zeros
+ * @returns
+ */
+function trimZeros(numStr) {
+ if (numStr && numStr.indexOf(".") !== -1) {//float
+ numStr = numStr.replace(/0+$/, ""); //remove ending zeros
+ if (numStr === ".") numStr = "0";
+ else if (numStr[0] === ".") numStr = "0" + numStr;
+ else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1);
+ return numStr;
+ }
+ return numStr;
+}
+
+function parse_int(numStr, base) {
+ const str = numStr.trim();
+ if (base === 2 || base === 8) numStr = str.substring(2);
+
+ if (parseInt) return parseInt(numStr, base);
+ else if (Number.parseInt) return Number.parseInt(numStr, base);
+ else if (window && window.parseInt) return window.parseInt(numStr, base);
+ else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported");
+}
+
+/**
+ * Handle infinite values based on user option
+ * @param {string} str - original input string
+ * @param {number} num - parsed number (Infinity or -Infinity)
+ * @param {object} options - user options
+ * @returns {string|number|null} based on infinity option
+ */
+function handleInfinity(str, num, options) {
+ const isPositive = num === Infinity;
+
+ switch (options.infinity.toLowerCase()) {
+ case "null":
+ return null;
+ case "infinity":
+ return num; // Return Infinity or -Infinity
+ case "string":
+ return isPositive ? "Infinity" : "-Infinity";
+ case "original":
+ default:
+ return str; // Return original string like "1e1000"
+ }
+}
+;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/ignoreAttributes.js
+function ignoreAttributes_getIgnoreAttributesFn(ignoreAttributes) {
+ if (typeof ignoreAttributes === 'function') {
+ return ignoreAttributes
+ }
+ if (Array.isArray(ignoreAttributes)) {
+ return (attrName) => {
+ for (const pattern of ignoreAttributes) {
+ if (typeof pattern === 'string' && attrName === pattern) {
+ return true
+ }
+ if (pattern instanceof RegExp && pattern.test(attrName)) {
+ return true
+ }
+ }
+ }
+ }
+ return () => false
+}
+;// CONCATENATED MODULE: ./node_modules/path-expression-matcher/src/ExpressionSet.js
+/**
+ * ExpressionSet - An indexed collection of Expressions for efficient bulk matching
+ *
+ * Instead of iterating all expressions on every tag, ExpressionSet pre-indexes
+ * them at insertion time by depth and terminal tag name. At match time, only
+ * the relevant bucket is evaluated — typically reducing checks from O(E) to O(1)
+ * lookup plus O(small bucket) matches.
+ *
+ * Three buckets are maintained:
+ * - `_byDepthAndTag` — exact depth + exact tag name (tightest, used first)
+ * - `_wildcardByDepth` — exact depth + wildcard tag `*` (depth-matched only)
+ * - `_deepWildcards` — expressions containing `..` (cannot be depth-indexed)
+ *
+ * @example
+ * import { Expression, ExpressionSet } from 'fast-xml-tagger';
+ *
+ * // Build once at config time
+ * const stopNodes = new ExpressionSet();
+ * stopNodes.add(new Expression('root.users.user'));
+ * stopNodes.add(new Expression('root.config.setting'));
+ * stopNodes.add(new Expression('..script'));
+ *
+ * // Query on every tag — hot path
+ * if (stopNodes.matchesAny(matcher)) { ... }
+ */
+class ExpressionSet {
+ constructor() {
+ /** @type {Map} depth:tag → expressions */
+ this._byDepthAndTag = new Map();
+
+ /** @type {Map} depth → wildcard-tag expressions */
+ this._wildcardByDepth = new Map();
+
+ /** @type {import('./Expression.js').default[]} expressions containing deep wildcard (..) */
+ this._deepWildcards = [];
+
+ /** @type {Map} terminalTag → deep wildcard expressions */
+ this._deepByTerminalTag = new Map();
+
+ /** @type {Set} pattern strings already added — used for deduplication */
+ this._patterns = new Set();
+
+ /** @type {boolean} whether the set is sealed against further additions */
+ this._sealed = false;
+ }
+
+ /**
+ * Add an Expression to the set.
+ * Duplicate patterns (same pattern string) are silently ignored.
+ *
+ * @param {import('./Expression.js').default} expression - A pre-constructed Expression instance
+ * @returns {this} for chaining
+ * @throws {TypeError} if called after seal()
+ *
+ * @example
+ * set.add(new Expression('root.users.user'));
+ * set.add(new Expression('..script'));
+ */
+ add(expression) {
+ if (this._sealed) {
+ throw new TypeError(
+ 'ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.'
+ );
+ }
+
+ // Deduplicate by pattern string
+ if (this._patterns.has(expression.pattern)) return this;
+ this._patterns.add(expression.pattern);
+
+ if (expression.hasDeepWildcard()) {
+ const lastSeg = expression.segments[expression.segments.length - 1];
+ if (lastSeg && lastSeg.type !== 'deep-wildcard' && lastSeg.tag !== '*') {
+ const tag = lastSeg.tag;
+ if (!this._deepByTerminalTag.has(tag)) this._deepByTerminalTag.set(tag, []);
+ this._deepByTerminalTag.get(tag).push(expression);
+ } else {
+ this._deepWildcards.push(expression);
+ }
+ return this;
+ }
+
+ const depth = expression.length;
+ const lastSeg = expression.segments[expression.segments.length - 1];
+ const tag = lastSeg?.tag;
+
+ if (!tag || tag === '*') {
+ // Can index by depth but not by tag
+ if (!this._wildcardByDepth.has(depth)) this._wildcardByDepth.set(depth, []);
+ this._wildcardByDepth.get(depth).push(expression);
+ } else {
+ // Tightest bucket: depth + tag
+ const key = `${depth}:${tag}`;
+ if (!this._byDepthAndTag.has(key)) this._byDepthAndTag.set(key, []);
+ this._byDepthAndTag.get(key).push(expression);
+ }
+
+ return this;
+ }
+
+ /**
+ * Add multiple expressions at once.
+ *
+ * @param {import('./Expression.js').default[]} expressions - Array of Expression instances
+ * @returns {this} for chaining
+ *
+ * @example
+ * set.addAll([
+ * new Expression('root.users.user'),
+ * new Expression('root.config.setting'),
+ * ]);
+ */
+ addAll(expressions) {
+ for (const expr of expressions) this.add(expr);
+ return this;
+ }
+
+ /**
+ * Check whether a pattern string is already present in the set.
+ *
+ * @param {import('./Expression.js').default} expression
+ * @returns {boolean}
+ */
+ has(expression) {
+ return this._patterns.has(expression.pattern);
+ }
+
+ /**
+ * Number of expressions in the set.
+ * @type {number}
+ */
+ get size() {
+ return this._patterns.size;
+ }
+
+ /**
+ * Seal the set against further modifications.
+ * Useful to prevent accidental mutations after config is built.
+ * Calling add() or addAll() on a sealed set throws a TypeError.
+ *
+ * @returns {this}
+ */
+ seal() {
+ this._sealed = true;
+ return this;
+ }
+
+ /**
+ * Whether the set has been sealed.
+ * @type {boolean}
+ */
+ get isSealed() {
+ return this._sealed;
+ }
+
+ /**
+ * Test whether the matcher's current path matches any expression in the set.
+ *
+ * Evaluation order (cheapest → most expensive):
+ * 1. Exact depth + tag bucket — O(1) lookup, typically 0–2 expressions
+ * 2. Depth-only wildcard bucket — O(1) lookup, rare
+ * 3. Deep-wildcard list — always checked, but usually small
+ *
+ * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)
+ * @returns {boolean} true if any expression matches the current path
+ *
+ * @example
+ * if (stopNodes.matchesAny(matcher)) {
+ * // handle stop node
+ * }
+ */
+ matchesAny(matcher) {
+ return this.findMatch(matcher) !== null;
+ }
+ /**
+ * Find and return the first Expression that matches the matcher's current path.
+ *
+ * Uses the same evaluation order as matchesAny (cheapest → most expensive):
+ * 1. Exact depth + tag bucket
+ * 2. Depth-only wildcard bucket
+ * 3. Deep-wildcard list
+ *
+ * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)
+ * @returns {import('./Expression.js').default | null} the first matching Expression, or null
+ *
+ * @example
+ * const expr = stopNodes.findMatch(matcher);
+ * if (expr) {
+ * // access expr.config, expr.pattern, etc.
+ * }
+ */
+ findMatch(matcher) {
+ const depth = matcher.getDepth();
+ const tag = matcher.getCurrentTag();
+
+ // 1. Tightest bucket — most expressions live here
+ const exactKey = `${depth}:${tag}`;
+ const exactBucket = this._byDepthAndTag.get(exactKey);
+ if (exactBucket) {
+ for (let i = 0; i < exactBucket.length; i++) {
+ if (matcher.matches(exactBucket[i])) return exactBucket[i];
+ }
+ }
+
+ // 2. Depth-matched wildcard-tag expressions
+ const wildcardBucket = this._wildcardByDepth.get(depth);
+ if (wildcardBucket) {
+ for (let i = 0; i < wildcardBucket.length; i++) {
+ if (matcher.matches(wildcardBucket[i])) return wildcardBucket[i];
+ }
+ }
+
+ // 3. Deep wildcards — indexed by terminal tag, then unindexed fallback
+ const deepBucket = this._deepByTerminalTag.get(tag);
+ if (deepBucket) {
+ for (let i = 0; i < deepBucket.length; i++) {
+ if (matcher.matches(deepBucket[i])) return deepBucket[i];
+ }
+ }
+ for (let i = 0; i < this._deepWildcards.length; i++) {
+ if (matcher.matches(this._deepWildcards[i])) return this._deepWildcards[i];
+ }
+
+ return null;
+ }
+}
+
+;// CONCATENATED MODULE: ./node_modules/@nodable/entities/src/entities.js
+// ---------------------------------------------------------------------------
+// Complete HTML5 named entity reference
+// Organized by logical categories for easy maintenance and selective importing
+// ---------------------------------------------------------------------------
+
+/**
+ * Basic Latin & Special Characters
+ * @type {Record}
+ */
+const BASIC_LATIN = {
+ amp: '&',
+ AMP: '&',
+ lt: '<',
+ LT: '<',
+ gt: '>',
+ GT: '>',
+ quot: '"',
+ QUOT: '"',
+ apos: "'",
+ lsquo: '‘',
+ rsquo: '’',
+ ldquo: '“',
+ rdquo: '”',
+ lsquor: '‚',
+ rsquor: '’',
+ ldquor: '„',
+ bdquo: '„',
+ comma: ',',
+ period: '.',
+ colon: ':',
+ semi: ';',
+ excl: '!',
+ quest: '?',
+ num: '#',
+ dollar: '$',
+ percent: '%',
+ ast: '*',
+ commat: '@',
+ lowbar: '_',
+ verbar: '|',
+ vert: '|',
+ sol: '/',
+ bsol: '\\',
+ lbrace: '{',
+ rbrace: '}',
+ lbrack: '[',
+ rbrack: ']',
+ lpar: '(',
+ rpar: ')',
+ nbsp: '\u00a0',
+ iexcl: '¡',
+ cent: '¢',
+ pound: '£',
+ curren: '¤',
+ yen: '¥',
+ brvbar: '¦',
+ sect: '§',
+ uml: '¨',
+ copy: '©',
+ COPY: '©',
+ ordf: 'ª',
+ laquo: '«',
+ not: '¬',
+ shy: '\u00ad',
+ reg: '®',
+ REG: '®',
+ macr: '¯',
+ deg: '°',
+ plusmn: '±',
+ sup2: '²',
+ sup3: '³',
+ acute: '´',
+ micro: 'µ',
+ para: '¶',
+ middot: '·',
+ cedil: '¸',
+ sup1: '¹',
+ ordm: 'º',
+ raquo: '»',
+ frac14: '¼',
+ frac12: '½',
+ half: '½',
+ frac34: '¾',
+ iquest: '¿',
+ times: '×',
+ div: '÷',
+ divide: '÷',
+};
+
+/**
+ * Latin Extended & Accented Letters (A-Z)
+ * @type {Record}
+ */
+const LATIN_ACCENTS = {
+ Agrave: 'À',
+ agrave: 'à',
+ Aacute: 'Á',
+ aacute: 'á',
+ Acirc: 'Â',
+ acirc: 'â',
+ Atilde: 'Ã',
+ atilde: 'ã',
+ Auml: 'Ä',
+ auml: 'ä',
+ Aring: 'Å',
+ aring: 'å',
+ AElig: 'Æ',
+ aelig: 'æ',
+ Ccedil: 'Ç',
+ ccedil: 'ç',
+ Egrave: 'È',
+ egrave: 'è',
+ Eacute: 'É',
+ eacute: 'é',
+ Ecirc: 'Ê',
+ ecirc: 'ê',
+ Euml: 'Ë',
+ euml: 'ë',
+ Igrave: 'Ì',
+ igrave: 'ì',
+ Iacute: 'Í',
+ iacute: 'í',
+ Icirc: 'Î',
+ icirc: 'î',
+ Iuml: 'Ï',
+ iuml: 'ï',
+ ETH: 'Ð',
+ eth: 'ð',
+ Ntilde: 'Ñ',
+ ntilde: 'ñ',
+ Ograve: 'Ò',
+ ograve: 'ò',
+ Oacute: 'Ó',
+ oacute: 'ó',
+ Ocirc: 'Ô',
+ ocirc: 'ô',
+ Otilde: 'Õ',
+ otilde: 'õ',
+ Ouml: 'Ö',
+ ouml: 'ö',
+ Oslash: 'Ø',
+ oslash: 'ø',
+ Ugrave: 'Ù',
+ ugrave: 'ù',
+ Uacute: 'Ú',
+ uacute: 'ú',
+ Ucirc: 'Û',
+ ucirc: 'û',
+ Uuml: 'Ü',
+ uuml: 'ü',
+ Yacute: 'Ý',
+ yacute: 'ý',
+ THORN: 'Þ',
+ thorn: 'þ',
+ szlig: 'ß',
+ yuml: 'ÿ',
+ Yuml: 'Ÿ',
+};
+
+/**
+ * Latin Extended (Letters with diacritics)
+ * @type {Record}
+ */
+const LATIN_EXTENDED = {
+ Amacr: 'Ā',
+ amacr: 'ā',
+ Abreve: 'Ă',
+ abreve: 'ă',
+ Aogon: 'Ą',
+ aogon: 'ą',
+ Cacute: 'Ć',
+ cacute: 'ć',
+ Ccirc: 'Ĉ',
+ ccirc: 'ĉ',
+ Cdot: 'Ċ',
+ cdot: 'ċ',
+ Ccaron: 'Č',
+ ccaron: 'č',
+ Dcaron: 'Ď',
+ dcaron: 'ď',
+ Dstrok: 'Đ',
+ dstrok: 'đ',
+ Emacr: 'Ē',
+ emacr: 'ē',
+ Ecaron: 'Ě',
+ ecaron: 'ě',
+ Edot: 'Ė',
+ edot: 'ė',
+ Eogon: 'Ę',
+ eogon: 'ę',
+ Gcirc: 'Ĝ',
+ gcirc: 'ĝ',
+ Gbreve: 'Ğ',
+ gbreve: 'ğ',
+ Gdot: 'Ġ',
+ gdot: 'ġ',
+ Gcedil: 'Ģ',
+ Hcirc: 'Ĥ',
+ hcirc: 'ĥ',
+ Hstrok: 'Ħ',
+ hstrok: 'ħ',
+ Itilde: 'Ĩ',
+ itilde: 'ĩ',
+ Imacr: 'Ī',
+ imacr: 'ī',
+ Iogon: 'Į',
+ iogon: 'į',
+ Idot: 'İ',
+ IJlig: 'IJ',
+ ijlig: 'ij',
+ Jcirc: 'Ĵ',
+ jcirc: 'ĵ',
+ Kcedil: 'Ķ',
+ kcedil: 'ķ',
+ kgreen: 'ĸ',
+ Lacute: 'Ĺ',
+ lacute: 'ĺ',
+ Lcedil: 'Ļ',
+ lcedil: 'ļ',
+ Lcaron: 'Ľ',
+ lcaron: 'ľ',
+ Lmidot: 'Ŀ',
+ lmidot: 'ŀ',
+ Lstrok: 'Ł',
+ lstrok: 'ł',
+ Nacute: 'Ń',
+ nacute: 'ń',
+ Ncaron: 'Ň',
+ ncaron: 'ň',
+ Ncedil: 'Ņ',
+ ncedil: 'ņ',
+ ENG: 'Ŋ',
+ eng: 'ŋ',
+ Omacr: 'Ō',
+ omacr: 'ō',
+ Odblac: 'Ő',
+ odblac: 'ő',
+ OElig: 'Œ',
+ oelig: 'œ',
+ Racute: 'Ŕ',
+ racute: 'ŕ',
+ Rcaron: 'Ř',
+ rcaron: 'ř',
+ Rcedil: 'Ŗ',
+ rcedil: 'ŗ',
+ Sacute: 'Ś',
+ sacute: 'ś',
+ Scirc: 'Ŝ',
+ scirc: 'ŝ',
+ Scedil: 'Ş',
+ scedil: 'ş',
+ Scaron: 'Š',
+ scaron: 'š',
+ Tcedil: 'Ţ',
+ tcedil: 'ţ',
+ Tcaron: 'Ť',
+ tcaron: 'ť',
+ Tstrok: 'Ŧ',
+ tstrok: 'ŧ',
+ Utilde: 'Ũ',
+ utilde: 'ũ',
+ Umacr: 'Ū',
+ umacr: 'ū',
+ Ubreve: 'Ŭ',
+ ubreve: 'ŭ',
+ Uring: 'Ů',
+ uring: 'ů',
+ Udblac: 'Ű',
+ udblac: 'ű',
+ Uogon: 'Ų',
+ uogon: 'ų',
+ Wcirc: 'Ŵ',
+ wcirc: 'ŵ',
+ Ycirc: 'Ŷ',
+ ycirc: 'ŷ',
+ Zacute: 'Ź',
+ zacute: 'ź',
+ Zdot: 'Ż',
+ zdot: 'ż',
+ Zcaron: 'Ž',
+ zcaron: 'ž',
+};
+
+/**
+ * Greek Letters
+ * @type {Record