diff --git a/.github/workflows/__shared-ci.yml b/.github/workflows/__shared-ci.yml index a164873..873a59a 100644 --- a/.github/workflows/__shared-ci.yml +++ b/.github/workflows/__shared-ci.yml @@ -6,6 +6,21 @@ on: permissions: {} jobs: + test-release: + name: Test release preparation and recovery + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: $/actions/setup-node + with: + working-directory: tests/release + - run: npm test + working-directory: tests/release + linter: uses: hoverkraft-tech/ci-github-common/.github/workflows/linter.yml@44f6108cef0e9884ea7735f3d62932c2310745d4 # 0.39.1 permissions: @@ -65,6 +80,7 @@ jobs: needs: linter uses: $/.github/workflows/__test-workflow-continuous-integration.yml permissions: + actions: read attestations: write contents: read packages: write diff --git a/.github/workflows/__test-workflow-continuous-integration.yml b/.github/workflows/__test-workflow-continuous-integration.yml index eff95a0..60d909a 100644 --- a/.github/workflows/__test-workflow-continuous-integration.yml +++ b/.github/workflows/__test-workflow-continuous-integration.yml @@ -10,6 +10,7 @@ jobs: name: Act - Run the continuous integration workflow (without container) uses: $/.github/workflows/continuous-integration.yml permissions: + actions: read contents: read id-token: write packages: read @@ -17,6 +18,7 @@ jobs: security-events: write with: working-directory: tests/npm + packages: '[{"name":"test-for-ci-with-npm","version":"0.1.0","directory":".","slug":"test-for-ci-with-npm"}]' code-ql: | { "languages": "javascript-typescript", @@ -31,6 +33,9 @@ jobs: name: Assert - Ensure build artifact has been uploaded (without container) runs-on: ubuntu-latest needs: act-without-container + permissions: + actions: read + contents: read steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -43,11 +48,26 @@ jobs: - name: Check the build artifacts run: test -f tests/npm/dist/test.txt + - name: Download the packaged CI output + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + artifact-ids: ${{ fromJSON(needs.act-without-container.outputs.package-artifacts)[0].artifact-id }} + path: ${{ runner.temp }}/ci-package + skip-decompress: true + + - name: Verify the tarball contains the tested build output + env: + ARTIFACT_NAME: ${{ fromJSON(needs.act-without-container.outputs.package-artifacts)[0].artifact-name }} + run: | + tar -xOf "$RUNNER_TEMP/ci-package/$ARTIFACT_NAME" package/dist/test.txt > "$RUNNER_TEMP/packaged-build.txt" + cmp tests/npm/dist/test.txt "$RUNNER_TEMP/packaged-build.txt" + act-without-container-and-github-reports: # jscpd:ignore-start name: Act - Run the continuous integration workflow (without container and GitHub reports) uses: $/.github/workflows/continuous-integration.yml permissions: + actions: read contents: read id-token: write packages: read @@ -94,6 +114,7 @@ jobs: uses: $/.github/workflows/continuous-integration.yml needs: arrange-with-container permissions: + actions: read contents: read id-token: write packages: read @@ -130,6 +151,7 @@ jobs: uses: $/.github/workflows/continuous-integration.yml needs: arrange-with-container permissions: + actions: read contents: read id-token: write packages: read diff --git a/.github/workflows/continuous-integration.md b/.github/workflows/continuous-integration.md index 89a49e8..71cd33d 100644 --- a/.github/workflows/continuous-integration.md +++ b/.github/workflows/continuous-integration.md @@ -3,7 +3,7 @@ # GitHub Reusable Workflow: Node.js Continuous Integration
- Node.js Continuous Integration + Node.js Continuous Integration
--- @@ -16,7 +16,6 @@ [![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) [![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) -![GitHub Verified Creator](https://img.shields.io/badge/GitHub-Verified%20Creator-4493F8?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJyZ2IoNjgsIDE0NywgMjQ4KSI+CiAgPHBhdGggZD0ibTkuNTg1LjUyLjkyOS42OGMuMTUzLjExMi4zMzEuMTg2LjUxOC4yMTVsMS4xMzguMTc1YTIuNjc4IDIuNjc4IDAgMCAxIDIuMjQgMi4yNGwuMTc0IDEuMTM5Yy4wMjkuMTg3LjEwMy4zNjUuMjE1LjUxOGwuNjguOTI4YTIuNjc3IDIuNjc3IDAgMCAxIDAgMy4xN2wtLjY4LjkyOGExLjE3NCAxLjE3NCAwIDAgMC0uMjE1LjUxOGwtLjE3NSAxLjEzOGEyLjY3OCAyLjY3OCAwIDAgMS0yLjI0MSAyLjI0MWwtMS4xMzguMTc1YTEuMTcgMS4xNyAwIDAgMC0uNTE4LjIxNWwtLjkyOC42OGEyLjY3NyAyLjY3NyAwIDAgMS0zLjE3IDBsLS45MjgtLjY4YTEuMTc0IDEuMTc0IDAgMCAwLS41MTgtLjIxNUwzLjgzIDE0LjQxYTIuNjc4IDIuNjc4IDAgMCAxLTIuMjQtMi4yNGwtLjE3NS0xLjEzOGExLjE3IDEuMTcgMCAwIDAtLjIxNS0uNTE4bC0uNjgtLjkyOGEyLjY3NyAyLjY3NyAwIDAgMSAwLTMuMTdsLjY4LS45MjhjLjExMi0uMTUzLjE4Ni0uMzMxLjIxNS0uNTE4bC4xNzUtMS4xNGEyLjY3OCAyLjY3OCAwIDAgMSAyLjI0LTIuMjRsMS4xMzktLjE3NWMuMTg3LS4wMjkuMzY1LS4xMDMuNTE4LS4yMTVsLjkyOC0uNjhhMi42NzcgMi42NzcgMCAwIDEgMy4xNyAwWk03LjMwMyAxLjcyOGwtLjkyNy42OGEyLjY3IDIuNjcgMCAwIDEtMS4xOC40ODlsLTEuMTM3LjE3NGExLjE3OSAxLjE3OSAwIDAgMC0uOTg3Ljk4N2wtLjE3NCAxLjEzNmEyLjY3NyAyLjY3NyAwIDAgMS0uNDg5IDEuMThsLS42OC45MjhhMS4xOCAxLjE4IDAgMCAwIDAgMS4zOTRsLjY4LjkyN2MuMjU2LjM0OC40MjQuNzUzLjQ4OSAxLjE4bC4xNzQgMS4xMzdjLjA3OC41MDkuNDc4LjkwOS45ODcuOTg3bDEuMTM2LjE3NGEyLjY3IDIuNjcgMCAwIDEgMS4xOC40ODlsLjkyOC42OGMuNDE0LjMwNS45NzkuMzA1IDEuMzk0IDBsLjkyNy0uNjhhMi42NyAyLjY3IDAgMCAxIDEuMTgtLjQ4OWwxLjEzNy0uMTc0YTEuMTggMS4xOCAwIDAgMCAuOTg3LS45ODdsLjE3NC0xLjEzNmEyLjY3IDIuNjcgMCAwIDEgLjQ4OS0xLjE4bC42OC0uOTI4YTEuMTc2IDEuMTc2IDAgMCAwIDAtMS4zOTRsLS42OC0uOTI3YTIuNjg2IDIuNjg2IDAgMCAxLS40ODktMS4xOGwtLjE3NC0xLjEzN2ExLjE3OSAxLjE3OSAwIDAgMC0uOTg3LS45ODdsLTEuMTM2LS4xNzRhMi42NzcgMi42NzcgMCAwIDEtMS4xOC0uNDg5bC0uOTI4LS42OGExLjE3NiAxLjE3NiAwIDAgMC0xLjM5NCAwWk0xMS4yOCA2Ljc4bC0zLjc1IDMuNzVhLjc1Ljc1IDAgMCAxLTEuMDYgMEw0LjcyIDguNzhhLjc1MS43NTEgMCAwIDEgLjAxOC0xLjA0Mi43NTEuNzUxIDAgMCAxIDEuMDQyLS4wMThMNyA4Ljk0bDMuMjItMy4yMmEuNzUxLjc1MSAwIDAgMSAxLjA0Mi4wMTguNzUxLjc1MSAwIDAgMSAuMDE4IDEuMDQyWiI+PC9wYXRoPgo8L3N2Zz4K) @@ -34,9 +33,11 @@ Workflow to performs continuous integration steps against a Node.js project: - Linting - Build - Test +- Optional npm packaging for publication from the same commit ### Permissions +- **`actions`**: `read` - **`contents`**: `read` - **`id-token`**: `write` - **`packages`**: `read` @@ -253,6 +254,10 @@ jobs: | | | | | | | | Example: | | | | | |
{
 "commands": [
 "build",
 "generate-artifacts"
 ],
 "env": {
 "CUSTOM_ENV_VAR": "value"
 },
 "artifact": [
 "dist/",
 "packages/package-a/build/"
 ]
}
| | | | +| **`packages`** | Optional JSON package list from prepare-release, with name, version, directory and slug. | **false** | **string** | - | +| | Packages the build output after checks pass and returns immutable tarball artifact IDs. | | | | +| | Requires checks, a build artifact, GitHub-hosted Ubuntu runners and no container. | | | | +| | Leave empty for ordinary CI without release packaging. | | | | | **`checks`** | Optional flag to enable check steps. | **false** | **boolean** | `true` | | **`lint`** | Whether to enable linting. | **false** | **string** | `true` | | | Set to `null` or empty to disable. | | | | @@ -395,9 +400,10 @@ When specified, steps will execute inside this container instead of checking out ## Outputs -| **Output** | **Description** | -| ----------------------- | --------------------------------------------------------- | -| **`build-artifact-id`** | ID of the build artifact) uploaded during the build step. | +| **Output** | **Description** | +| ----------------------- | ------------------------------------------------------------------------------------------------------- | +| **`package-artifacts`** | JSON package artifact list for the release workflow in this same run. Empty when packaging is disabled. | +| **`build-artifact-id`** | ID of the build artifact) uploaded during the build step. | diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index a46535d..1b07286 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -4,6 +4,7 @@ # - Linting # - Build # - Test +# - Optional npm packaging for publication from the same commit name: Node.js Continuous Integration @@ -46,6 +47,14 @@ on: type: string required: false default: "build" + packages: + description: | + Optional JSON package list from prepare-release, with name, version, directory and slug. + Packages the build output after checks pass and returns immutable tarball artifact IDs. + Requires checks, a build artifact, GitHub-hosted Ubuntu runners and no container. + Leave empty for ordinary CI without release packaging. + type: string + default: "" checks: description: "Optional flag to enable check steps." type: boolean @@ -188,6 +197,9 @@ on: Defaults to `GITHUB_TOKEN` if not provided. required: false outputs: + package-artifacts: + description: JSON package artifact list for the release workflow in this same run. Empty when packaging is disabled. + value: ${{ jobs.package-artifacts.outputs.packages }} build-artifact-id: description: "ID of the build artifact) uploaded during the build step." value: ${{ jobs.build.outputs.artifact-id }} @@ -208,6 +220,18 @@ jobs: container-username: ${{ steps.parse.outputs.container-username }} path-mapping: ${{ steps.parse.outputs.path-mapping }} steps: + - name: Validate packaging configuration + if: inputs.packages != '' + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + CHECKS: ${{ inputs.checks }} + CONTAINER: ${{ inputs.container }} + RUNS_ON: ${{ inputs.runs-on }} + with: + script: | + if (process.env.CHECKS !== 'true' || process.env.CONTAINER || JSON.stringify(JSON.parse(process.env.RUNS_ON)) !== '["ubuntu-latest"]') { + core.setFailed('Release packaging requires checks, runs-on: ["ubuntu-latest"] and no container.'); + } - id: parse uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: @@ -606,3 +630,46 @@ jobs: report-file: ${{ steps.prepare-test-options.outputs.report-file }} path-mapping: ${{ needs.prepare.outputs.path-mapping || '' }} github-token: ${{ secrets.github-token || github.token }} + + package: + name: 📦 Package ${{ matrix.package.name }} + needs: [prepare, setup, build, lint, test, code-ql, dependency-review] + if: >- + ${{ !cancelled() && inputs.packages != '' && needs.build.result == 'success' + && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} + runs-on: ubuntu-latest + permissions: + contents: read + packages: read + actions: read + strategy: + fail-fast: false + matrix: + package: ${{ fromJSON(inputs.packages) }} + steps: + - name: Require build output + env: + BUILD_ARTIFACT_ID: ${{ needs.build.outputs.artifact-id }} + run: test -n "$BUILD_ARTIFACT_ID" + - uses: $/actions/package + with: + working-directory: ${{ inputs.working-directory }} + package-directory: ${{ matrix.package.directory }} + build-artifact-id: ${{ needs.build.outputs.artifact-id }} + build-artifact-path: / + artifact-name: npm-${{ matrix.package.slug }}-${{ github.run_id }}-${{ github.run_attempt }} + + package-artifacts: + name: 📦 Collect package artifact IDs + needs: package + if: ${{ !cancelled() && needs.package.result == 'success' }} + runs-on: ubuntu-latest + permissions: + actions: read + outputs: + packages: ${{ steps.artifacts.outputs.packages }} + steps: + - id: artifacts + uses: $/actions/package-artifacts + with: + packages: ${{ inputs.packages }} diff --git a/.github/workflows/prepare-release.md b/.github/workflows/prepare-release.md new file mode 100644 index 0000000..2a5bd43 --- /dev/null +++ b/.github/workflows/prepare-release.md @@ -0,0 +1,96 @@ + + +# GitHub Reusable Workflow: Prepare Node.js Release + +
+ Prepare Node.js Release +
+ +--- + + + + +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Prepare a Node.js release version and changelog without building or publishing. +Dispatches the calling workflow at the prepared tag; that run can invoke CI and publication. +See [the release guide](../../docs/usage/releases.md). + +### Permissions + +- **`actions`**: `write` +- **`contents`**: `write` +- **`pull-requests`**: `read` + + + + +## Inputs + +### Workflow Call Inputs + +| **Input** | **Description** | **Required** | **Type** | **Default** | +| ----------------------- | ---------------------------------------------------------------------------------------------------------- | ------------ | ---------- | ----------- | +| **`versioning`** | Tool applying the HoverKraft release plan, npm for a single package or lerna for fixed-version workspaces. | **false** | **string** | `npm` | +| **`working-directory`** | Project directory relative to the caller repository root. | **false** | **string** | `.` | +| **`environment`** | GitHub environment permitting release preparation on the default branch and release tags. | **false** | **string** | `release` | + + + + +## Secrets + +| **Secret** | **Description** | **Required** | +| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------ | +| **`github-token`** | Optional token for pushing release commits and dispatching the caller at the tag. Its identity must be permitted by branch and tag rules. | **false** | + + + + +## Outputs + +| **Output** | **Description** | +| -------------- | -------------------------------------------------------------------------------------------------- | +| **`status`** | no-changes, dispatched, released or ready. Only ready should start CI and publication in this run. | +| **`tag`** | Prepared release tag. | +| **`packages`** | JSON package list for the CI workflow's packages input. Available when status is ready. | + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft-tech + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml new file mode 100644 index 0000000..d1428ea --- /dev/null +++ b/.github/workflows/prepare-release.yml @@ -0,0 +1,63 @@ +# Prepare a Node.js release version and changelog without building or publishing. +# Dispatches the calling workflow at the prepared tag; that run can invoke CI and publication. +# See [the release guide](../../docs/usage/releases.md). +name: Prepare Node.js Release + +on: + workflow_call: + inputs: + versioning: + description: Tool applying the HoverKraft release plan, npm for a single package or lerna for fixed-version workspaces. + type: string + default: npm + working-directory: + description: Project directory relative to the caller repository root. + type: string + default: . + environment: + description: GitHub environment permitting release preparation on the default branch and release tags. + type: string + default: release + secrets: + github-token: + description: Optional token for pushing release commits and dispatching the caller at the tag. Its identity must be permitted by branch and tag rules. + required: false + outputs: + status: + description: no-changes, dispatched, released or ready. Only ready should start CI and publication in this run. + value: ${{ jobs.prepare.outputs.status }} + tag: + description: Prepared release tag. + value: ${{ jobs.prepare.outputs.tag }} + packages: + description: JSON package list for the CI workflow's packages input. Available when status is ready. + value: ${{ jobs.prepare.outputs.packages }} + +permissions: {} + +concurrency: + group: node-release-prepare-${{ github.repository }}-${{ inputs.working-directory }} + cancel-in-progress: false + +jobs: + prepare: + name: Prepare release + runs-on: ubuntu-latest + timeout-minutes: 20 + environment: ${{ inputs.environment }} + permissions: + actions: write + contents: write + pull-requests: read + outputs: + status: ${{ steps.prepare.outputs.status }} + tag: ${{ steps.prepare.outputs.tag }} + packages: ${{ steps.prepare.outputs.packages }} + published: ${{ steps.prepare.outputs.published }} + steps: + - id: prepare + uses: $/actions/release/prepare + with: + versioning: ${{ inputs.versioning }} + working-directory: ${{ inputs.working-directory }} + github-token: ${{ secrets.github-token || github.token }} diff --git a/.github/workflows/release.md b/.github/workflows/release.md index 267919b..cb7c1f6 100644 --- a/.github/workflows/release.md +++ b/.github/workflows/release.md @@ -1,261 +1,98 @@ -# Release a Node.js package - -Publish a package to npm and attach the same tarball to a GitHub release: - -**Plan version → Run CI → Package build output → Publish to npm → Create GitHub release** - -The workflow below releases a single package from the repository root using stable versions such as `1.2.3`. -It sets the version during packaging. If your build reads the package version or you commit version changes, -use [Commit the version before building](#commit-the-version-before-building). - -## Set up - -1. Configure [release labels and version rules](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/prepare-release.md). - These determine the version and release notes. -2. Check the package's `package.json`: set `name`, `files`, and `repository.url`, and ensure `private` is not `true`. -3. Configure [npm trusted publishing](../../actions/publish/README.md#npm-trusted-publishing) for your repository and workflow filename, `release.yml`. - The example uses GitHub-hosted runners and `id-token: write`; no npm token is needed. - For a new npm package, publish its first version before configuring the trusted publisher. -4. Save the workflow below as `.github/workflows/release.yml` in your project. Before running it: - - Replace every `` with the **same `ci-github-nodejs` commit containing `actions/publish`**. - The `ci-github-publish` actions are already pinned to `1.0.3`. - - Set the `build`, `lint:ci`, and `test:ci` script names and the `dist/` output path to match your project. - See [CI options](continuous-integration.md) if you need a different setup. - -## Workflow - -```yaml -name: Release - -on: - schedule: - - cron: "25 8 * * 1" - workflow_dispatch: - inputs: - force: - description: Release even when no relevant changes are detected - type: boolean - required: false - default: false - -permissions: {} - -concurrency: - group: release-${{ github.repository }} - cancel-in-progress: false - -jobs: - plan: - if: github.ref_name == github.event.repository.default_branch - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - outputs: - should-release: ${{ steps.plan.outputs.has-changes == 'true' || (github.event_name == 'workflow_dispatch' && inputs.force) }} - tag: ${{ steps.plan.outputs.tag }} - version: ${{ steps.version.outputs.version }} - steps: - - name: Plan release - id: plan - uses: hoverkraft-tech/ci-github-publish/actions/release/plan@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 - - - id: version - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - RELEASE_TAG: ${{ steps.plan.outputs.tag }} - with: - script: | - // This example uses tags such as v1.2.3 or 1.2.3. - const version = process.env.RELEASE_TAG.replace(/^v/, ''); - if (!/^\d+\.\d+\.\d+$/.test(version)) { - return core.setFailed('Expected a stable SemVer tag; adapt the mapping for prereleases or monorepos'); - } - core.setOutput('version', version); - - ci: - needs: plan - if: needs.plan.outputs.should-release == 'true' - uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@ - permissions: - contents: read - packages: read - pull-requests: write - id-token: write - security-events: write - with: - build: '{"commands":["build"],"artifact":{"paths":["dist/"]}}' - lint: '{"command":"lint:ci"}' - test: '{"command":"test:ci"}' - - release: - needs: [plan, ci] - if: needs.plan.outputs.should-release == 'true' - runs-on: ubuntu-latest - permissions: - actions: read - contents: write - pull-requests: read - id-token: write - steps: - - name: Package build output - id: package - uses: hoverkraft-tech/ci-github-nodejs/actions/package@ - with: - version: ${{ needs.plan.outputs.version }} - build-artifact-id: ${{ needs.ci.outputs.build-artifact-id }} - # The reusable CI workflow preserves absolute paths in build artifacts. - build-artifact-path: / - - # Add any package smoke tests before publishing. - - name: Check package publishing - uses: hoverkraft-tech/ci-github-nodejs/actions/publish@ - with: - package-tarball-artifact-id: ${{ steps.package.outputs.package-tarball-artifact-id }} - dry-run: "true" - provenance: "false" - - # Wrap the raw .tgz in a ZIP artifact for release/create. - - id: release-assets - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - with: - name: release-assets - path: ${{ steps.package.outputs.package-tarball-path }} - if-no-files-found: error - - - id: publish-package - name: Publish package - uses: hoverkraft-tech/ci-github-nodejs/actions/publish@ - with: - package-tarball-artifact-id: ${{ steps.package.outputs.package-tarball-artifact-id }} - tag: latest - - - name: Create GitHub release - uses: hoverkraft-tech/ci-github-publish/actions/release/create@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 - with: - tag: ${{ needs.plan.outputs.tag }} - target-sha: ${{ github.sha }} - release-artifact-id: ${{ steps.release-assets.outputs.artifact-id }} - publish: "true" -``` - -[Package](../../actions/package/README.md) checks out the source, installs dependencies, restores the CI build output, -and creates the tarball. [Publish](../../actions/publish/README.md) publishes that tarball. -The package version is changed locally; it is not committed. GitHub's source archive therefore keeps the version from the source commit. -If `package.json` already contains the planned version, omit the Package action's `version` input. - -## Generate the changelog - -`release/create` generates the GitHub release notes with Release Drafter from the merged pull requests since the previous matching release. -No separate changelog command is needed for the workflow above. `release/plan` calculates the version without creating a release. - -Use the [prepare-release workflow](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/prepare-release.md) -to label pull requests from their Conventional Commit titles. Its default rules select a major version for breaking changes, -a minor version for features, and a patch version for other changes. Check the labels before merging. -To customize categories, version rules, or the release-note template, add `.github/release-config.yml`. -For monorepos, use the same `working-directory` and `include-paths` values in `release/plan` and `release/create`; -an existing repository configuration takes precedence over those generated defaults. - -### Add an AI summary - -Store the provider credential as the `OPENAI_API_KEY` Actions secret, then add these entries to the **Create GitHub release** step. -Merge `changelog-summary` into its existing `with` mapping: - -```yaml -env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} -with: - changelog-summary: | - { - "llmAuth": ${{ toJSON(env.OPENAI_API_KEY) }}, - "llmProvider": "openai" - } -``` - -The action drafts the changelog, generates a release summary and breaking-change section, and prepends them to the full changelog before publishing. -The summary also uses GitHub evidence, so keep `contents: write` and `pull-requests: read` on the release job. -Use `toJSON` to encode the credential safely. Omit `changelog-summary` to publish the generated notes without an AI summary. -See [summarizer inputs](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/actions/release/summarize-changelog/README.md) -for `llmModel`, `llmConfig`, and custom summary templates. - -To review the notes before publication, set `publish: "false"`, review the draft, then publish it with `release/update`. -If summary generation fails, the action does not publish the GitHub release. The npm package may already be published; -follow [Recover a failed release](#recover-a-failed-release) instead of rerunning npm publication. - -### Keep a changelog in the repository - -Release notes are stored in the GitHub release body; these actions do not write or commit `CHANGELOG.md`. -If the source archive or npm tarball must contain it, generate and review the changelog on the release branch, -commit it with the version update, and build from that merged commit as described in [Commit the version before building](#commit-the-version-before-building). -Keep the planned tag fixed through preparation and publication. - -## Run a release - -In **Actions → Release → Run workflow**, select the default branch. The workflow also runs every Monday at 08:25 UTC. -Releases are serialized so two runs cannot publish the same package concurrently. - -| Situation | Result | -| ---------------------------------------------- | ---------------------------------------------------------------------------------- | -| Relevant changes since the last GitHub release | Plan the next version, run CI, and release. | -| No relevant changes | Skip CI and publishing successfully. | -| Manual run with `force` checked | Release the planned version even without changes; CI must still pass. | -| No previous matching GitHub release | Plan the first GitHub release. Registry authentication must already be configured. | - -The dry run checks the tarball with `npm publish --dry-run`. It does not verify registry credentials or trusted publishing access. -For a first trial without publishing, keep the dry-run step and remove the **Publish package** and **Create GitHub release** steps. - -## Commit the version before building - -Use this when the build embeds the version or the released source must include updated version files or a changelog: - -1. Plan the version with `release/plan`, using the same no-change and `force` rules as the workflow above. -2. Update the version on a release branch, for example with `npm version 1.2.3 --no-git-tag-version`. - Commit the package manifest, lockfile, changelog, and any generated version files through a pull request. -3. After merging, run CI and packaging **from the merged commit**. Omit the Package action's `version` input; the version is already in `package.json`. -4. Publish the tarball, then create the GitHub release with the planned `tag` and merged commit as `target-sha`. - -Keep the planned tag throughout this process; do not calculate another version after merging. -If you use a second workflow for publication, read the committed version instead of calling `release/plan` again, -and skip it when that version is already released. - -The Package action performs its own checkout of the workflow's source ref. -Checking out the merged commit in an earlier step does not change that ref: start the packaging workflow at the merged commit. -See the [release preparation example](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/release.md#example-3-validate-source-update-files-create-release-artifacts-and-release) -for automating the pull request and merge. - -## Other setups - -- **GitHub Packages or registry tokens:** use the [authentication examples](../../actions/publish/README.md#registry-tokens-and-github-packages). - The `github-token` input only authenticates artifact downloads; registry credentials use `NODE_AUTH_TOKEN`. -- **Prereleases:** set `prerelease: "true"` on `release/plan` and `release/create`, and `tag: next` on both Publish steps. - Update the version conversion to accept your full prerelease version, such as `1.2.3-rc.1`. - The npm distribution tag (`next`) is separate from the Git release tag (`v1.2.3-rc.1`). -- **Monorepos:** scope CI and both release actions with `working-directory`. - For Package, set `working-directory` to the dependency installation root and `package-directory` to the package's relative path. - Convert prefixed Git tags such as `my-package/v1.2.3` to npm versions, and use a separate concurrency group and artifact name per package. -- **Drafts and signing:** create a draft with `publish: "false"`, then use `release/update` to attach assets and publish after npm publication succeeds. - See the [draft release example](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/release.md#example-2-validate-source-create-release-artifacts-and-release). - Use `release/delete` with `draft-only: "true"` to clean up a temporary draft on failure **only if the npm package has not been published**. + -## Recover a failed release +# GitHub Reusable Workflow: Node.js Release -Check the registry before retrying: an npm package version cannot be overwritten, and a failed run may still have published it. +
+ Node.js Release +
-| Where it failed | What to do | -| ------------------------------------------------- | ------------------------------------------------------------------------ | -| Before npm publication | Fix the failure and rerun the workflow. | -| npm published, but GitHub release creation failed | Run only release creation with the original tag, source SHA, and assets. | -| npm published, but a draft was not finalized | Keep the draft and retry `release/update`. | - -After npm publication, do not rerun the whole release job or plan a new version to finish the same release. -Deleting a draft does not undo npm publication. - -## Migrate from the reusable release workflow - -Replace calls to `ci-github-nodejs/.github/workflows/release.yml` with a job that uses [the Publish action](../../actions/publish/README.md#usage): +--- -- Move `runs-on` and permissions to the caller job. -- Move the publishing inputs to the action step, quoting `provenance` and `dry-run` as `"true"` or `"false"`. -- Move the optional `github-token` secret to the action's `github-token` input. + + -Use the workflow above when you also need version planning, CI, and a GitHub release. +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Publish CI-produced npm tarballs and finalize a GitHub release without rebuilding. +Call after successful CI on the prepared tag, passing its package-artifacts output. +See [the release guide](../../docs/usage/releases.md) for preparation, CI and recovery. + +### Permissions + +- **`actions`**: `read` +- **`contents`**: `write` +- **`id-token`**: `write` +- **`pull-requests`**: `read` + + + + +## Inputs + +### Workflow Call Inputs + +| **Input** | **Description** | **Required** | **Type** | **Default** | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------ | ----------- | ----------- | +| **`package-artifacts`** | JSON package artifact list from successful CI in this same workflow run and at this release tag's commit. | **true** | **string** | - | +| **`working-directory`** | Project directory relative to the caller repository root, matching release preparation and CI. | **false** | **string** | `.` | +| **`ai-summary`** | Generate an OpenAI summary before npm publication. Requires OPENAI_API_KEY; failures stop publication. | **false** | **boolean** | `false` | +| **`environment`** | GitHub environment for AI and npm publishing. Configure npm trusted publishing for this environment and the calling workflow. | **false** | **string** | `release` | + + + + +## Secrets + +| **Secret** | **Description** | **Required** | +| -------------------- | ---------------------------------------------------- | ------------ | +| **`OPENAI_API_KEY`** | OpenAI API key, required when ai-summary is enabled. | **false** | + + + + +## Outputs + +| **Output** | **Description** | +| ----------------- | ------------------------------------------------------------------- | +| **`status`** | published after all npm packages and GitHub release assets succeed. | +| **`tag`** | Published release tag. | +| **`release-url`** | Published GitHub release URL. | + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft-tech + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f56a257 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,175 @@ +# Publish CI-produced npm tarballs and finalize a GitHub release without rebuilding. +# Call after successful CI on the prepared tag, passing its package-artifacts output. +# See [the release guide](../../docs/usage/releases.md) for preparation, CI and recovery. +name: Node.js Release + +on: + workflow_call: + inputs: + package-artifacts: + description: JSON package artifact list from successful CI in this same workflow run and at this release tag's commit. + type: string + required: true + working-directory: + description: Project directory relative to the caller repository root, matching release preparation and CI. + type: string + default: . + ai-summary: + description: Generate an OpenAI summary before npm publication. Requires OPENAI_API_KEY; failures stop publication. + type: boolean + default: false + environment: + description: GitHub environment for AI and npm publishing. Configure npm trusted publishing for this environment and the calling workflow. + type: string + default: release + secrets: + OPENAI_API_KEY: + description: OpenAI API key, required when ai-summary is enabled. + required: false + outputs: + status: + description: published after all npm packages and GitHub release assets succeed. + value: ${{ jobs.publish.outputs.status }} + tag: + description: Published release tag. + value: ${{ jobs.verify.outputs.tag }} + release-url: + description: Published GitHub release URL. + value: ${{ jobs.publish.outputs.url }} + +permissions: {} + +concurrency: + group: node-release-publish-${{ github.repository }}-${{ inputs.working-directory }} + cancel-in-progress: false + +jobs: + verify: + name: Verify CI artifacts + runs-on: ubuntu-latest + timeout-minutes: 10 + environment: ${{ inputs.environment }} + permissions: + actions: read + contents: read + outputs: + tag: ${{ steps.verify.outputs.tag }} + packages: ${{ steps.verify.outputs.packages }} + published: ${{ steps.verify.outputs.published }} + steps: + - name: Validate AI configuration + if: inputs.ai-summary + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: | + if [ -z "$OPENAI_API_KEY" ]; then + echo "OPENAI_API_KEY is required when ai-summary is enabled." >&2 + exit 1 + fi + - id: verify + uses: $/actions/release/verify + with: + package-artifacts: ${{ inputs.package-artifacts }} + working-directory: ${{ inputs.working-directory }} + + draft: + name: Draft release notes + needs: verify + runs-on: ubuntu-latest + timeout-minutes: 20 + environment: ${{ inputs.environment }} + permissions: + contents: write + pull-requests: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Create draft and optional AI summary + if: needs.verify.outputs.published != 'true' + uses: hoverkraft-tech/ci-github-publish/actions/release/create@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + with: + tag: ${{ needs.verify.outputs.tag }} + target-sha: ${{ github.sha }} + working-directory: ${{ inputs.working-directory != '.' && inputs.working-directory || '' }} + publish: "false" + changelog-summary: ${{ inputs.ai-summary && format('{{"llmAuth":{0},"llmProvider":"openai"}}', toJSON(env.OPENAI_API_KEY)) || '' }} + + packages: + name: Publish ${{ matrix.package.name }} + needs: [verify, draft] + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: ${{ inputs.environment }} + permissions: + actions: read + contents: read + id-token: write + strategy: + fail-fast: false + matrix: + package: ${{ fromJSON(needs.verify.outputs.packages) }} + steps: + - name: Download the CI package tarball + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + artifact-ids: ${{ matrix.package.artifact-id }} + path: ${{ runner.temp }}/ci-package + skip-decompress: true + - id: registry + uses: $/actions/release/restore-package + with: + name: ${{ matrix.package.name }} + version: ${{ matrix.package.version }} + tarball-path: ${{ runner.temp }}/ci-package/${{ matrix.package.artifact-name }} + - name: Validate publication + uses: $/actions/publish + with: + package-tarball-artifact-id: ${{ matrix.package.artifact-id }} + dry-run: "true" + provenance: "false" + - name: Publish missing npm version + if: steps.registry.outputs.published != 'true' + uses: $/actions/publish + with: + package-tarball-artifact-id: ${{ matrix.package.artifact-id }} + tag: latest + - name: Prepare release asset + env: + PACKAGE_TARBALL: ${{ runner.temp }}/ci-package/${{ matrix.package.artifact-name }} + ASSET_NAME: ${{ matrix.package.slug }}-${{ matrix.package.version }}.tgz + run: | + mkdir -p "$RUNNER_TEMP/release-assets" + cp "$PACKAGE_TARBALL" "$RUNNER_TEMP/release-assets/$ASSET_NAME" + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: release-assets-${{ matrix.package.slug }} + path: ${{ runner.temp }}/release-assets/*.tgz + overwrite: true + if-no-files-found: error + + publish: + name: Publish GitHub release + needs: [verify, packages] + runs-on: ubuntu-latest + timeout-minutes: 15 + environment: ${{ inputs.environment }} + permissions: + contents: write + actions: read + outputs: + url: ${{ steps.finalize.outputs.url }} + status: ${{ steps.finalize.outcome == 'success' && 'published' || '' }} + steps: + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + pattern: release-assets-* + merge-multiple: true + path: ${{ runner.temp }}/release-assets + - id: finalize + uses: $/actions/release/finalize + with: + tag: ${{ needs.verify.outputs.tag }} + asset-directory: ${{ runner.temp }}/release-assets diff --git a/README.md b/README.md index 007f1a3..01ce3ff 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,12 @@ _Actions for continuous integration steps: build, lint, and test._ #### - [Publish](actions/publish/README.md) +### Release Actions + +- [Prepare a release](actions/release/prepare/README.md) +- [Restore a published package](actions/release/restore-package/README.md) +- [Finalize a release](actions/release/finalize/README.md) + ### Dependencies _Actions dedicated to caching and validating Node.js dependencies._ @@ -63,7 +69,10 @@ _Actions focused on discovering and preparing the Node.js environment._ ### Release -- [Release](.github/workflows/release.md) — guide to Node.js project releases using `ci-github-publish` release actions and the package/publish actions. +- [Release packages](docs/usage/releases.md) — single-package and Lerna releases with preparation, CI and publication. +- [Preparation workflow reference](.github/workflows/prepare-release.md) — version planning and tagged source. +- [Release workflow reference](.github/workflows/release.md) — inputs, secrets and outputs. +- [Custom release pipelines](docs/usage/custom-releases.md) — compose the package, publish and GitHub release actions. ## Contributing diff --git a/actions/package-artifacts/PackageArtifacts.js b/actions/package-artifacts/PackageArtifacts.js new file mode 100644 index 0000000..7fa3c96 --- /dev/null +++ b/actions/package-artifacts/PackageArtifacts.js @@ -0,0 +1,104 @@ +const path = require("node:path"); + +class PackageArtifacts { + constructor({ github, context }) { + this.github = github; + this.context = context; + } + + parse(input) { + const packages = JSON.parse(input); + if (!Array.isArray(packages) || !packages.length || packages.length > 256) + throw new Error( + "Expected a nonempty package array with at most 256 entries.", + ); + for (const item of packages) { + if ( + !item || + typeof item.name !== "string" || + !/^(?:@[a-z0-9-]+\/)?[a-z0-9][a-z0-9._-]*$/.test(item.name) || + item.slug !== item.name.replace(/^@/, "").replace("/", "-") || + typeof item.version !== "string" || + !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(item.version) || + typeof item.directory !== "string" || + !item.directory || + path.isAbsolute(item.directory) || + item.directory.split(/[\\/]/).includes("..") + ) + throw new Error( + "Expected valid package names, slugs, stable versions and relative directories.", + ); + } + if (new Set(packages.map((item) => item.slug)).size !== packages.length) + throw new Error("Package slugs must be unique."); + return packages; + } + + matches(artifact, item) { + const prefix = `npm-${item.slug}-${this.context.runId}-`; + return ( + artifact.name.startsWith(prefix) && + /^[1-9]\d*\.tgz$/.test(artifact.name.slice(prefix.length)) + ); + } + + validateArtifact(artifact, item) { + if ( + !this.matches(artifact, item) || + artifact.expired || + artifact.workflow_run?.id !== this.context.runId + ) + throw new Error( + `Package ${item.name} must use an unexpired CI artifact from this run.`, + ); + } + + async collect(input) { + const packages = this.parse(input); + const artifacts = await this.github.paginate( + this.github.rest.actions.listWorkflowRunArtifacts, + { + ...this.context.repo, + run_id: this.context.runId, + per_page: 100, + }, + ); + return packages.map((item) => { + // Successful matrix jobs from earlier attempts remain valid on a failed-job rerun. + const artifact = artifacts + .filter((candidate) => this.matches(candidate, item)) + .sort((a, b) => b.id - a.id)[0]; + if (!artifact) throw new Error(`No CI tarball found for ${item.name}.`); + this.validateArtifact(artifact, item); + return { + ...item, + "artifact-id": artifact.id, + "artifact-name": artifact.name, + }; + }); + } + + async verify(input, version) { + const packages = this.parse(input); + for (const item of packages) { + if (item.version !== version) + throw new Error( + "CI package version must match the prepared release tag.", + ); + if (!Number.isSafeInteger(item["artifact-id"]) || item["artifact-id"] < 1) + throw new Error("Expected a positive CI artifact ID."); + const { data: artifact } = await this.github.rest.actions.getArtifact({ + ...this.context.repo, + artifact_id: item["artifact-id"], + }); + this.validateArtifact(artifact, item); + if (artifact.workflow_run.head_sha !== this.context.sha) + throw new Error("CI artifact must come from this prepared commit."); + if (item["artifact-name"] !== artifact.name) + throw new Error("CI artifact filename does not match its ID."); + } + return packages; + } +} + +module.exports = { PackageArtifacts }; diff --git a/actions/package-artifacts/README.md b/actions/package-artifacts/README.md new file mode 100644 index 0000000..d44d220 --- /dev/null +++ b/actions/package-artifacts/README.md @@ -0,0 +1,76 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItcGFja2FnZSIgY29sb3I9ImJsdWUiPjxsaW5lIHgxPSIxNi41IiB5MT0iOS40IiB4Mj0iNy41IiB5Mj0iNC4yMSI+PC9saW5lPjxwYXRoIGQ9Ik0yMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzNsNyA0YTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNnoiPjwvcGF0aD48cG9seWxpbmUgcG9pbnRzPSIzLjI3IDYuOTYgMTIgMTIuMDEgMjAuNzMgNi45NiI+PC9wb2x5bGluZT48bGluZSB4MT0iMTIiIHkxPSIyMi4wOCIgeDI9IjEyIiB5Mj0iMTIiPjwvbGluZT48L3N2Zz4=) GitHub Action: Collect npm package artifacts + +
+ Collect npm package artifacts +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-collect--npm--package--artifacts-blue?logo=github-actions)](https://github.com/marketplace/actions/collect-npm-package-artifacts) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Collect immutable tarball artifact IDs after CI packaging, including successful matrix jobs from earlier attempts of the same run. + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| -------------- | -------------------------------------------------------------------------------------- | ------------ | ----------- | +| **`packages`** | JSON list of packages with name, version, directory and slug from release preparation. | **true** | - | + + + + + + +## Outputs + +| **Output** | **Description** | +| -------------- | ----------------------------------------------------------------------------------------- | +| **`packages`** | JSON package list with artifact-id and artifact-name, verified against this workflow run. | + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/actions/package-artifacts/action.yml b/actions/package-artifacts/action.yml new file mode 100644 index 0000000..9e98dcc --- /dev/null +++ b/actions/package-artifacts/action.yml @@ -0,0 +1,26 @@ +name: Collect npm package artifacts +description: Collect immutable tarball artifact IDs after CI packaging, including successful matrix jobs from earlier attempts of the same run. +author: hoverkraft +branding: + icon: package + color: blue +inputs: + packages: + description: JSON list of packages with name, version, directory and slug from release preparation. + required: true +outputs: + packages: + description: JSON package list with artifact-id and artifact-name, verified against this workflow run. + value: ${{ steps.collect.outputs.packages }} +runs: + using: composite + steps: + - id: collect + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + ACTION_PATH: ${{ github.action_path }} + PACKAGES: ${{ inputs.packages }} + with: + script: | + const { PackageArtifacts } = require(`${process.env.ACTION_PATH}/PackageArtifacts.js`); + core.setOutput('packages', await new PackageArtifacts({ github, context }).collect(process.env.PACKAGES)); diff --git a/actions/release/ReleaseArtifacts.js b/actions/release/ReleaseArtifacts.js new file mode 100644 index 0000000..a102ef1 --- /dev/null +++ b/actions/release/ReleaseArtifacts.js @@ -0,0 +1,110 @@ +const { createHash } = require("node:crypto"); +const fs = require("node:fs"); +const { execFileSync } = require("node:child_process"); +const path = require("node:path"); + +class ReleaseArtifacts { + constructor(fetchPackage = fetch) { + this.fetchPackage = fetchPackage; + } + + static async findRelease(github, repo, tag) { + try { + const { data } = await github.rest.repos.getReleaseByTag({ + ...repo, + tag, + }); + return data; + } catch (error) { + if (error.status !== 404) throw error; + const releases = await github.paginate(github.rest.repos.listReleases, { + ...repo, + per_page: 100, + }); + return releases.find((release) => release.tag_name === tag); + } + } + + static verifyTarball({ name, version, tarballPath }) { + const manifest = JSON.parse( + execFileSync("tar", ["-xOf", tarballPath, "package/package.json"], { + encoding: "utf8", + }), + ); + if ( + manifest.name !== name || + manifest.version !== version || + manifest.private + ) + throw new Error( + "CI tarball must contain the expected public package and release version.", + ); + } + + async restorePackage({ name, version, tarballPath }) { + const response = await this.fetchPackage( + `https://registry.npmjs.org/${encodeURIComponent(name)}/${encodeURIComponent(version)}`, + ); + if (response.status === 404) return false; + if (!response.ok) + throw new Error(`npm registry lookup failed: HTTP ${response.status}`); + const metadata = await response.json(); + if (metadata.name !== name || metadata.version !== version) + throw new Error("npm registry returned an unexpected package version."); + const url = new URL(metadata.dist.tarball); + if (url.origin !== "https://registry.npmjs.org") + throw new Error( + "Published package tarball must come from the npm registry.", + ); + const tarballResponse = await this.fetchPackage(url.href); + if (!tarballResponse.ok) + throw new Error( + `npm tarball download failed: HTTP ${tarballResponse.status}`, + ); + const tarball = Buffer.from(await tarballResponse.arrayBuffer()); + const integrity = `sha512-${createHash("sha512").update(tarball).digest("base64")}`; + if (metadata.dist.integrity !== integrity) + throw new Error( + "Published package tarball failed integrity verification.", + ); + fs.writeFileSync(tarballPath, tarball); + return true; + } + + async prepareAssets({ github, repo, tag, directory }) { + const release = await ReleaseArtifacts.findRelease(github, repo, tag); + if (!release) throw new Error(`No release found for ${tag}.`); + const assets = await github.paginate(github.rest.repos.listReleaseAssets, { + ...repo, + release_id: release.id, + per_page: 100, + }); + const files = fs + .readdirSync(directory) + .filter((name) => name.endsWith(".tgz")); + if (!files.length) + throw new Error("No package tarballs available to attach."); + const missing = []; + for (const name of files) { + const data = fs.readFileSync(path.join(directory, name)); + const digest = `sha256:${createHash("sha256").update(data).digest("hex")}`; + const existing = assets.find((asset) => asset.name === name); + if (existing) { + if (existing.digest !== digest) + throw new Error( + `Release asset ${name} has a different or unavailable digest.`, + ); + continue; + } + if (!release.draft) + throw new Error(`Published release is missing expected asset ${name}.`); + missing.push({ name, data }); + } + const pendingDirectory = fs.mkdtempSync(path.join(directory, "pending-")); + for (const { name, data } of missing) + fs.writeFileSync(path.join(pendingDirectory, name), data); + return { release, pendingDirectory, hasAssets: missing.length > 0 }; + } +} + +module.exports = { ReleaseArtifacts }; diff --git a/actions/release/ReleaseProject.js b/actions/release/ReleaseProject.js new file mode 100644 index 0000000..af3d868 --- /dev/null +++ b/actions/release/ReleaseProject.js @@ -0,0 +1,308 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { execFileSync } = require("node:child_process"); + +class ReleaseProject { + constructor({ + workspace, + workingDirectory = ".", + versioning = "npm", + github, + context, + }) { + this.workspace = fs.realpathSync(workspace); + this.directory = fs.realpathSync(path.resolve(workspace, workingDirectory)); + this.relativeDirectory = path.relative(this.workspace, this.directory); + if ( + this.relativeDirectory.startsWith("..") || + path.isAbsolute(this.relativeDirectory) + ) { + throw new Error( + "Release working directory must be inside the repository.", + ); + } + if (!["lerna", "npm"].includes(versioning)) { + throw new Error("versioning must be npm or lerna."); + } + this.versioning = versioning; + this.github = github; + this.context = context; + const manifest = this.readJson("package.json"); + if (versioning === "npm" && (manifest.workspaces || manifest.private)) { + throw new Error( + "npm mode requires one public package; use lerna for fixed-version workspaces.", + ); + } + this.version(); + } + + readJson(file) { + return JSON.parse(fs.readFileSync(path.join(this.directory, file), "utf8")); + } + + run(command, args) { + return execFileSync(command, args, { + cwd: this.directory, + encoding: "utf8", + stdio: ["ignore", "pipe", "pipe"], + env: { ...process.env, CI: "true" }, + }).trim(); + } + + git(...args) { + return this.run("git", args); + } + + version() { + const { version } = this.readJson( + this.versioning === "lerna" ? "lerna.json" : "package.json", + ); + if ( + typeof version !== "string" || + !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(version) + ) { + throw new Error( + "Releases require a stable version; independent Lerna versions and prereleases are not supported.", + ); + } + return version; + } + + packages(tag) { + const version = this.version(); + if (this.versionFromTag(tag) !== version) + throw new Error("Release tag must match the committed package version."); + const candidates = + this.versioning === "lerna" + ? JSON.parse( + this.run("npm", [ + "exec", + "--no", + "--", + "lerna", + "list", + "--all", + "--json", + "--loglevel", + "silent", + ]), + ) + : [{ ...this.readJson("package.json"), location: this.directory }]; + const packages = candidates + .filter((item) => !item.private && item.version === version) + .map((item) => { + if ( + typeof item.name !== "string" || + !/^(?:@[a-z0-9-]+\/)?[a-z0-9][a-z0-9._-]*$/.test(item.name) + ) { + throw new Error("Release packages must have valid npm names."); + } + const directory = path.relative( + this.directory, + fs.realpathSync(item.location), + ); + if (directory.startsWith("..") || path.isAbsolute(directory)) + throw new Error("Package is outside the release working directory."); + return { + name: item.name, + version, + directory: directory || ".", + slug: item.name.replace(/^@/, "").replace("/", "-"), + }; + }); + if ( + !packages.length || + new Set(packages.map((item) => item.slug)).size !== packages.length + ) { + throw new Error( + "Expected uniquely named public packages at the release version.", + ); + } + return packages; + } + + tagCommit(tag) { + try { + return this.git("rev-parse", "--verify", `${tag}^{commit}`); + } catch { + return undefined; + } + } + + versionFromTag(tag) { + return ReleaseProject.versionFromTag( + tag, + this.directory, + this.relativeDirectory, + ); + } + + static versionFromTag(tag, directory, relativeDirectory) { + const slug = path + .basename(directory) + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, ""); + const prefixes = ["", "v", ...(relativeDirectory ? [`${slug}-`] : [])]; + const version = prefixes + .map((prefix) => (tag.startsWith(prefix) ? tag.slice(prefix.length) : "")) + .find((candidate) => + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(candidate), + ); + if (!version) + throw new Error( + "Expected a stable version tag, optionally prefixed with v or the project directory slug.", + ); + return version; + } + + currentTag() { + if (this.context.ref.startsWith("refs/tags/")) + return this.context.ref.slice("refs/tags/".length); + if ( + this.context.ref !== + `refs/heads/${this.context.payload.repository.default_branch}` + ) { + throw new Error( + "Run releases from the default branch or an existing release tag.", + ); + } + const tags = this.git("tag", "--points-at", this.context.sha) + .split("\n") + .filter((tag) => { + try { + return this.versionFromTag(tag) === this.version(); + } catch { + return false; + } + }); + if (tags.length > 1) + throw new Error( + "Several release tags match this commit; resume the intended tag explicitly.", + ); + return tags[0]; + } + + prepareVersion({ tag, body }) { + const version = this.versionFromTag(tag); + const current = this.version(); + const previousParts = current.split(".").map(BigInt); + const parts = version.split(".").map(BigInt); + const difference = parts + .map((part, index) => part - previousParts[index]) + .find((part) => part !== 0n); + if (!difference || difference < 0n) + throw new Error( + "Planned version must be newer than the committed version; reconcile the release history and configuration.", + ); + if (this.tagCommit(tag)) + throw new Error(`Existing tag ${tag} must not be overwritten.`); + if (typeof body !== "string" || !body.trim()) + throw new Error( + "Upstream release notes are required before preparing source files.", + ); + const branch = this.context.payload.repository.default_branch; + this.git("switch", "--force-create", branch, this.context.sha); + if (this.git("status", "--porcelain")) + throw new Error( + "Release source must be clean before applying the planned version.", + ); + this.git("config", "user.name", "github-actions[bot]"); + this.git( + "config", + "user.email", + "41898282+github-actions[bot]@users.noreply.github.com", + ); + if (this.versioning === "lerna") { + this.run("npm", [ + "exec", + "--no", + "--", + "lerna", + "version", + version, + "--conventional-commits", + "--tag-version-prefix", + tag.slice(0, -version.length), + "--no-git-tag-version", + "--no-push", + "--yes", + ]); + if (this.version() === current) return { status: "no-changes" }; + } else { + this.run("npm", [ + "version", + version, + "--no-git-tag-version", + "--ignore-scripts", + ]); + } + if (this.version() !== version) + throw new Error("Version preparation did not apply the planned version."); + const changelog = path.join(this.directory, "CHANGELOG.md"); + const previous = fs.existsSync(changelog) + ? fs.readFileSync(changelog, "utf8").replace(/^# Changelog\s*/i, "") + : ""; + fs.writeFileSync( + changelog, + `# Changelog\n\n## ${tag}\n\n${body.trim()}\n\n${previous}`, + ); + this.git("add", "--all", "--", "."); + this.git("commit", "-m", `chore(release): ${tag}`); + this.git("tag", tag); + this.git( + "push", + "--atomic", + "origin", + `HEAD:refs/heads/${branch}`, + `refs/tags/${tag}`, + ); + return { tag }; + } + + async prepare({ workflowRef, findRelease, plan }) { + const { ref, payload, repo } = this.context; + if (ref.startsWith("refs/tags/")) { + const tag = ref.slice("refs/tags/".length); + const packages = this.packages(tag); + const release = await findRelease(this.github, repo, tag); + return { + status: "ready", + tag, + packages, + published: Boolean(release && !release.draft), + }; + } + if (ref !== `refs/heads/${payload.repository.default_branch}`) { + throw new Error( + "Run releases from the default branch or an existing release tag.", + ); + } + const currentTag = this.currentTag(); + if (!currentTag && !plan) + throw new Error("An upstream release plan is required."); + if (!currentTag && !plan.hasChanges) return { status: "no-changes" }; + const result = currentTag ? { tag: currentTag } : this.prepareVersion(plan); + if (!result.tag) return result; + const release = await findRelease(this.github, repo, result.tag); + if (release && !release.draft) { + return { ...result, status: "released", url: release.html_url }; + } + const prefix = `${repo.owner}/${repo.repo}/`; + const workflow = workflowRef.startsWith(prefix) + ? workflowRef.slice(prefix.length).split("@")[0] + : ""; + if (!/^\.github\/workflows\/[^/]+\.ya?ml$/.test(workflow)) + throw new Error( + "Cannot determine the caller workflow for publication dispatch.", + ); + await this.github.rest.actions.createWorkflowDispatch({ + ...repo, + workflow_id: workflow, + ref: result.tag, + }); + return { ...result, status: "dispatched" }; + } +} + +module.exports = { ReleaseProject }; diff --git a/actions/release/finalize/README.md b/actions/release/finalize/README.md new file mode 100644 index 0000000..1d3dee4 --- /dev/null +++ b/actions/release/finalize/README.md @@ -0,0 +1,78 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItdGFnIiBjb2xvcj0iYmx1ZSI+PHBhdGggZD0iTTIwLjU5IDEzLjQxbC03LjE3IDcuMTdhMiAyIDAgMCAxLTIuODMgMEwyIDEyVjJoMTBsOC41OSA4LjU5YTIgMiAwIDAgMSAwIDIuODJ6Ij48L3BhdGg+PGxpbmUgeDE9IjciIHkxPSI3IiB4Mj0iNy4wMSIgeTI9IjciPjwvbGluZT48L3N2Zz4=) GitHub Action: Finalize Node.js release + +
+ Finalize Node.js release +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-finalize--node.js--release-blue?logo=github-actions)](https://github.com/marketplace/actions/finalize-node.js-release) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Verify published npm tarballs against existing assets, then upload missing assets and publish the draft with HoverKraft release/update. + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| --------------------- | ------------------------------------------------ | ------------ | --------------------- | +| **`tag`** | Committed release tag. | **true** | - | +| **`asset-directory`** | Directory containing the published npm tarballs. | **true** | - | +| **`github-token`** | Token with contents write permissions. | **false** | `${{ github.token }}` | + + + + + + +## Outputs + +| **Output** | **Description** | +| ---------- | ----------------------------- | +| **`url`** | Published GitHub release URL. | + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/actions/release/finalize/action.yml b/actions/release/finalize/action.yml new file mode 100644 index 0000000..a446056 --- /dev/null +++ b/actions/release/finalize/action.yml @@ -0,0 +1,52 @@ +name: Finalize Node.js release +description: Verify published npm tarballs against existing assets, then upload missing assets and publish the draft with HoverKraft release/update. +author: hoverkraft +branding: + icon: tag + color: blue +inputs: + tag: + description: Committed release tag. + required: true + asset-directory: + description: Directory containing the published npm tarballs. + required: true + github-token: + description: Token with contents write permissions. + default: ${{ github.token }} +outputs: + url: + description: Published GitHub release URL. + value: ${{ steps.assets.outputs.url }} +runs: + using: composite + steps: + - id: assets + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + ACTION_PATH: ${{ github.action_path }} + RELEASE_TAG: ${{ inputs.tag }} + ASSET_DIRECTORY: ${{ inputs.asset-directory }} + with: + github-token: ${{ inputs.github-token }} + script: | + const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`); + const { release, pendingDirectory, hasAssets } = await new ReleaseArtifacts().prepareAssets({ github, repo: context.repo, tag: process.env.RELEASE_TAG, directory: process.env.ASSET_DIRECTORY }); + core.setOutput('url', release.html_url); + core.setOutput('published', String(!release.draft)); + core.setOutput('pending-directory', pendingDirectory); + core.setOutput('has-assets', String(hasAssets)); + - id: pending-assets + if: steps.assets.outputs.has-assets == 'true' + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: release-pending-assets-${{ github.run_id }}-${{ github.run_attempt }} + path: ${{ steps.assets.outputs.pending-directory }}/*.tgz + if-no-files-found: error + - uses: hoverkraft-tech/ci-github-publish/actions/release/update@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + if: steps.assets.outputs.published != 'true' + with: + tag: ${{ inputs.tag }} + publish: "true" + release-artifact-id: ${{ steps.pending-assets.outputs.artifact-id }} + github-token: ${{ inputs.github-token }} diff --git a/actions/release/prepare/README.md b/actions/release/prepare/README.md new file mode 100644 index 0000000..fc784aa --- /dev/null +++ b/actions/release/prepare/README.md @@ -0,0 +1,81 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItZ2l0LWNvbW1pdCIgY29sb3I9ImJsdWUiPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjQiPjwvY2lyY2xlPjxsaW5lIHgxPSIxLjA1IiB5MT0iMTIiIHgyPSI3IiB5Mj0iMTIiPjwvbGluZT48bGluZSB4MT0iMTcuMDEiIHkxPSIxMiIgeDI9IjIyLjk2IiB5Mj0iMTIiPjwvbGluZT48L3N2Zz4=) GitHub Action: Prepare Node.js release + +
+ Prepare Node.js release +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-prepare--node.js--release-blue?logo=github-actions)](https://github.com/marketplace/actions/prepare-node.js-release) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Plan with HoverKraft, apply the version and changelog with npm or Lerna, and dispatch publication from the committed tag. + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------ | --------------------- | +| **`versioning`** | Tool applying the HoverKraft release plan, npm for one package or lerna for fixed-version workspaces. | **false** | `npm` | +| **`working-directory`** | Project directory relative to the caller repository root. | **false** | `.` | +| **`github-token`** | Token with contents and actions write and pull-requests read permissions. Its identity must be allowed to push release commits and tags. | **false** | `${{ github.token }}` | + + + + + + +## Outputs + +| **Output** | **Description** | +| --------------- | ------------------------------------------------------------------------------------------------------- | +| **`status`** | One of no-changes, dispatched, ready or released. Only ready should start CI, followed by publication. | +| **`tag`** | Stable release tag, empty when preparation has no release to publish. | +| **`packages`** | JSON array of public packages at the committed release version, with name, version, directory and slug. | +| **`published`** | Whether the tag already has a published GitHub release. | + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/actions/release/prepare/action.yml b/actions/release/prepare/action.yml new file mode 100644 index 0000000..b31fdf3 --- /dev/null +++ b/actions/release/prepare/action.yml @@ -0,0 +1,113 @@ +name: Prepare Node.js release +description: Plan with HoverKraft, apply the version and changelog with npm or Lerna, and dispatch publication from the committed tag. +author: hoverkraft +branding: + icon: git-commit + color: blue +inputs: + versioning: + description: Tool applying the HoverKraft release plan, npm for one package or lerna for fixed-version workspaces. + default: npm + working-directory: + description: Project directory relative to the caller repository root. + default: . + github-token: + description: Token with contents and actions write and pull-requests read permissions. Its identity must be allowed to push release commits and tags. + default: ${{ github.token }} +outputs: + status: + description: One of no-changes, dispatched, ready or released. Only ready should start CI, followed by publication. + value: ${{ steps.prepare.outputs.status }} + tag: + description: Stable release tag, empty when preparation has no release to publish. + value: ${{ steps.prepare.outputs.tag }} + packages: + description: JSON array of public packages at the committed release version, with name, version, directory and slug. + value: ${{ steps.prepare.outputs.packages }} + published: + description: Whether the tag already has a published GitHub release. + value: ${{ steps.prepare.outputs.published }} +runs: + using: composite + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + token: ${{ inputs.github-token }} + # The preparation step pushes version commits and tags atomically. + persist-credentials: true + - name: Validate release project + id: inspect + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + ACTION_PATH: ${{ github.action_path }} + WORKING_DIRECTORY: ${{ inputs.working-directory }} + VERSIONING: ${{ inputs.versioning }} + with: + script: | + const { ReleaseProject } = require(`${process.env.ACTION_PATH}/../ReleaseProject.js`); + const project = new ReleaseProject({ workspace: process.env.GITHUB_WORKSPACE, workingDirectory: process.env.WORKING_DIRECTORY, versioning: process.env.VERSIONING, github, context }); + core.setOutput('needs-plan', String(!project.currentTag())); + - name: Plan release with HoverKraft + id: plan + if: steps.inspect.outputs.needs-plan == 'true' + uses: hoverkraft-tech/ci-github-publish/actions/release/plan@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + with: + github-token: ${{ inputs.github-token }} + target-sha: ${{ github.sha }} + working-directory: ${{ inputs.working-directory != '.' && inputs.working-directory || '' }} + - name: Restore source checkout for version preparation + if: steps.plan.outputs.has-changes == 'true' + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + token: ${{ inputs.github-token }} + persist-credentials: true + - uses: $/actions/setup-node + if: steps.plan.outputs.has-changes == 'true' || inputs.versioning == 'lerna' && steps.inspect.outputs.needs-plan != 'true' + with: + working-directory: ${{ inputs.working-directory }} + - id: configuration + if: steps.plan.outputs.has-changes == 'true' + uses: hoverkraft-tech/ci-github-publish/actions/release/get-configuration@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + with: + working-directory: ${{ inputs.working-directory != '.' && inputs.working-directory || '' }} + - name: Render the planned changelog without creating release state + id: notes + if: steps.plan.outputs.has-changes == 'true' + uses: hoverkraft-tech/ci-github-publish/actions/release/prepare@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + with: + config-name: file:${{ steps.configuration.outputs.config-path }} + token: ${{ inputs.github-token }} + dry-run: "true" + tag: ${{ steps.plan.outputs.tag }} + commitish: ${{ github.sha }} # codespell:ignore commitish + - name: Prepare release source + id: prepare + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + ACTION_PATH: ${{ github.action_path }} + WORKING_DIRECTORY: ${{ inputs.working-directory }} + VERSIONING: ${{ inputs.versioning }} + CALLER_WORKFLOW_REF: ${{ github.workflow_ref }} + PLANNED_TAG: ${{ steps.plan.outputs.tag }} + HAS_CHANGES: ${{ steps.plan.outputs.has-changes }} + CHANGELOG: ${{ steps.notes.outputs.body }} + with: + github-token: ${{ inputs.github-token }} + script: | + const { ReleaseProject } = require(`${process.env.ACTION_PATH}/../ReleaseProject.js`); + const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`); + const project = new ReleaseProject({ workspace: process.env.GITHUB_WORKSPACE, workingDirectory: process.env.WORKING_DIRECTORY, versioning: process.env.VERSIONING, github, context }); + const plan = { tag: process.env.PLANNED_TAG, hasChanges: process.env.HAS_CHANGES === 'true', body: process.env.CHANGELOG }; + const result = await project.prepare({ workflowRef: process.env.CALLER_WORKFLOW_REF, findRelease: ReleaseArtifacts.findRelease, plan }); + for (const [name, value] of Object.entries(result)) core.setOutput(name, value); + core.setOutput('packages', result.packages || []); + core.setOutput('published', String(Boolean(result.published))); + const messages = { + 'no-changes': 'No changes to release.', + dispatched: `Publication dispatched for ${result.tag}. Follow the new workflow run for that tag.`, + ready: `Ready for CI on committed release ${result.tag}.`, + released: `${result.tag} is already released.`, + }; + await core.summary.addRaw(messages[result.status]).write(); diff --git a/actions/release/restore-package/README.md b/actions/release/restore-package/README.md new file mode 100644 index 0000000..b7c6f55 --- /dev/null +++ b/actions/release/restore-package/README.md @@ -0,0 +1,78 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItcGFja2FnZSIgY29sb3I9ImJsdWUiPjxsaW5lIHgxPSIxNi41IiB5MT0iOS40IiB4Mj0iNy41IiB5Mj0iNC4yMSI+PC9saW5lPjxwYXRoIGQ9Ik0yMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzNsNyA0YTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNnoiPjwvcGF0aD48cG9seWxpbmUgcG9pbnRzPSIzLjI3IDYuOTYgMTIgMTIuMDEgMjAuNzMgNi45NiI+PC9wb2x5bGluZT48bGluZSB4MT0iMTIiIHkxPSIyMi4wOCIgeDI9IjEyIiB5Mj0iMTIiPjwvbGluZT48L3N2Zz4=) GitHub Action: Restore published Node.js package + +
+ Restore published Node.js package +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-restore--published--node.js--package-blue?logo=github-actions)](https://github.com/marketplace/actions/restore-published-node.js-package) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Validate a CI tarball, check an exact npm version and restore its original tarball with integrity verification when resuming publication. + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| ------------------ | ---------------------------------------------------------------------------- | ------------ | ----------- | +| **`name`** | Expected npm package name. | **true** | - | +| **`version`** | Expected committed package version. | **true** | - | +| **`tarball-path`** | Local tarball path to replace with the original published bytes on recovery. | **true** | - | + + + + + + +## Outputs + +| **Output** | **Description** | +| --------------- | ----------------------------------------------------------------------------- | +| **`published`** | Whether the exact version already exists on npm and its tarball was restored. | + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/actions/release/restore-package/action.yml b/actions/release/restore-package/action.yml new file mode 100644 index 0000000..a191917 --- /dev/null +++ b/actions/release/restore-package/action.yml @@ -0,0 +1,37 @@ +name: Restore published Node.js package +description: Validate a CI tarball, check an exact npm version and restore its original tarball with integrity verification when resuming publication. +author: hoverkraft +branding: + icon: package + color: blue +inputs: + name: + description: Expected npm package name. + required: true + version: + description: Expected committed package version. + required: true + tarball-path: + description: Local tarball path to replace with the original published bytes on recovery. + required: true +outputs: + published: + description: Whether the exact version already exists on npm and its tarball was restored. + value: ${{ steps.restore.outputs.published }} +runs: + using: composite + steps: + - id: restore + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + ACTION_PATH: ${{ github.action_path }} + PACKAGE_NAME: ${{ inputs.name }} + PACKAGE_VERSION: ${{ inputs.version }} + TARBALL_PATH: ${{ inputs.tarball-path }} + with: + script: | + const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`); + const options = { name: process.env.PACKAGE_NAME, version: process.env.PACKAGE_VERSION, tarballPath: process.env.TARBALL_PATH }; + ReleaseArtifacts.verifyTarball(options); + const published = await new ReleaseArtifacts().restorePackage(options); + core.setOutput('published', String(published)); diff --git a/actions/release/verify/README.md b/actions/release/verify/README.md new file mode 100644 index 0000000..1b6cf72 --- /dev/null +++ b/actions/release/verify/README.md @@ -0,0 +1,79 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItY2hlY2stY2lyY2xlIiBjb2xvcj0iYmx1ZSI+PHBhdGggZD0iTTIyIDExLjA4VjEyYTEwIDEwIDAgMSAxLTUuOTMtOS4xNCI+PC9wYXRoPjxwb2x5bGluZSBwb2ludHM9IjIyIDQgMTIgMTQuMDEgOSAxMS4wMSI+PC9wb2x5bGluZT48L3N2Zz4=) GitHub Action: Verify release package artifacts + +
+ Verify release package artifacts +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-verify--release--package--artifacts-blue?logo=github-actions)](https://github.com/marketplace/actions/verify-release-package-artifacts) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Require CI tarballs from this tag, workflow run and source commit before creating release state. + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| ----------------------- | -------------------------------------------------------------------------------- | ------------ | ----------- | +| **`package-artifacts`** | JSON package artifact list from the CI workflow. | **true** | - | +| **`working-directory`** | Project directory relative to the repository root, matching release preparation. | **false** | `.` | + + + + + + +## Outputs + +| **Output** | **Description** | +| --------------- | ----------------------------------------------------------------------------- | +| **`packages`** | Verified package artifact list for publication. | +| **`tag`** | Release tag from this workflow's immutable source ref. | +| **`published`** | Whether the GitHub release is already public and its notes must be preserved. | + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/actions/release/verify/action.yml b/actions/release/verify/action.yml new file mode 100644 index 0000000..66f0be7 --- /dev/null +++ b/actions/release/verify/action.yml @@ -0,0 +1,49 @@ +name: Verify release package artifacts +description: Require CI tarballs from this tag, workflow run and source commit before creating release state. +author: hoverkraft +branding: + icon: check-circle + color: blue +inputs: + package-artifacts: + description: JSON package artifact list from the CI workflow. + required: true + working-directory: + description: Project directory relative to the repository root, matching release preparation. + default: . +outputs: + packages: + description: Verified package artifact list for publication. + value: ${{ steps.verify.outputs.packages }} + tag: + description: Release tag from this workflow's immutable source ref. + value: ${{ steps.verify.outputs.tag }} + published: + description: Whether the GitHub release is already public and its notes must be preserved. + value: ${{ steps.verify.outputs.published }} +runs: + using: composite + steps: + - id: verify + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + ACTION_PATH: ${{ github.action_path }} + PACKAGES: ${{ inputs.package-artifacts }} + WORKING_DIRECTORY: ${{ inputs.working-directory }} + with: + script: | + const path = require('node:path'); + const { PackageArtifacts } = require(`${process.env.ACTION_PATH}/../../package-artifacts/PackageArtifacts.js`); + const { ReleaseProject } = require(`${process.env.ACTION_PATH}/../ReleaseProject.js`); + const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`); + if (!context.ref.startsWith('refs/tags/')) throw new Error('Publish from the prepared release tag.'); + const tag = context.ref.slice('refs/tags/'.length); + const directory = path.resolve(process.env.GITHUB_WORKSPACE, process.env.WORKING_DIRECTORY); + const relativeDirectory = path.relative(process.env.GITHUB_WORKSPACE, directory); + if (relativeDirectory.startsWith('..') || path.isAbsolute(relativeDirectory)) throw new Error('Release directory must be inside the repository.'); + const version = ReleaseProject.versionFromTag(tag, directory, relativeDirectory); + const packages = await new PackageArtifacts({ github, context }).verify(process.env.PACKAGES, version); + const release = await ReleaseArtifacts.findRelease(github, context.repo, tag); + core.setOutput('packages', packages); + core.setOutput('tag', tag); + core.setOutput('published', String(Boolean(release && !release.draft))); diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..a5bcdae --- /dev/null +++ b/docs/README.md @@ -0,0 +1,9 @@ +# Documentation + +- [Release a single package or Lerna workspaces](usage/releases.md) +- [Compose a custom release pipeline](usage/custom-releases.md) +- [Validate release automation](development/release-tests.md) +- [Release orchestration decision](adr/0001-release-orchestration.md) +- [Separation of CI and release](adr/0002-separate-ci-from-release.md) +- [HoverKraft release planning and publication](adr/0003-hoverkraft-release-actions.md) +- [CI produces release artifacts](adr/0004-ci-produces-release-artifacts.md) diff --git a/docs/adr/0001-release-orchestration.md b/docs/adr/0001-release-orchestration.md new file mode 100644 index 0000000..081955f --- /dev/null +++ b/docs/adr/0001-release-orchestration.md @@ -0,0 +1,65 @@ +# ADR 0001: Shared Node.js release orchestration + +- Status: accepted +- Date: 2026-10-29 + +The decision to run CI inside release is superseded by +[ADR 0002](0002-separate-ci-from-release.md). The version planning and release PR +decisions are superseded by [ADR 0003](0003-hoverkraft-release-actions.md). +The other decisions remain accepted. + +## Context + +The Package and Publish actions handle a single tarball. Consumers still need +to prepare versions, select workspaces, start CI at the versioned source and +recover partial releases. Reactionable's first integration added custom scripts +for those responsibilities. A single-package consumer, reactionable-cli, uses +Release Please and has a different source preparation policy. + +The Node.js release guide at commit +`b7eadcff0bdbd690f4688e7ce3f31d7ba0e39865` documents composition of the actions, +including committing versions before building and targeted recovery. The former +reusable publish workflow was removed in 0.25; the new workflow covers source +preparation and the complete release lifecycle instead of restoring that interface. + +## Decision + +Provide an optional reusable Release workflow, retaining the composable actions. +Consumers own triggers, build options, credentials, environment rules and optional +documentation deployment. HoverKraft owns preparation, publication and recovery. + +Support one public package through Release Please and fixed-version workspaces +through the consumer's installed Lerna. Keep preparation policies explicit: +Release Please requires a merged release PR; Lerna pushes versions directly. +Both infer versions from Conventional Commits without a user-supplied version. + +Use Release Please's PR creation action with GitHub release creation disabled. +Detect merged pending release PRs explicitly, tag their merge commits and mark +them released only after npm and GitHub publication succeed. Release Please v5.0.0 +was verified on the decision date; its breaking change is the Node 24 runtime. + +Dispatch the caller workflow at the resulting tag using `GITHUB_TOKEN` or an +explicit token. The Package action performs its own checkout, so starting a new +run ensures CI, package manifests, source archives and provenance use that commit. +The workflow serializes both runs and reports when publication has been dispatched. + +Preserve successful npm publishes on retry. Restore their original tarballs, +verify registry integrity and never replace conflicting GitHub assets. Keep +published release notes intact. Reuse the existing release create/update actions +for AI notes and final publication. Do not introduce a second SemVer engine. + +## Consequences + +Consumers need no release scripts. The single-package path retains a review step; +the Lerna path requires branch rules that permit its atomic push. An app token is +needed when release PR creation must trigger normal PR CI. Neither mode bypasses +repository protection rules. + +Preparation success and publication success belong to separate runs. A tag can +remain after CI or service failure, and npm publication is not atomic across +packages. Recovery operates on the original tag and package versions. + +The initial scope is stable public npm packages on GitHub.com hosted Linux +runners. Independent workspace versions, custom registries and prereleases remain +available through custom composition. New consumer pins require the upstream +workflow implementation to be available on GitHub. diff --git a/docs/adr/0002-separate-ci-from-release.md b/docs/adr/0002-separate-ci-from-release.md new file mode 100644 index 0000000..d43ed6f --- /dev/null +++ b/docs/adr/0002-separate-ci-from-release.md @@ -0,0 +1,39 @@ +# ADR 0002: Separate CI checks from release publication + +- Status: accepted; build ownership and orchestration partially superseded by + [ADR 0004](0004-ci-produces-release-artifacts.md) +- Date: 2026-10-31 +- Partially supersedes: [ADR 0001](0001-release-orchestration.md) + +## Context + +ADR 0001 made the release workflow invoke the full continuous-integration +workflow. That coupled publication to lint, test, coverage and security settings, +repeated checks already owned by consumer CI, and required unrelated permissions. + +Building release artifacts still depends on release preparation: compiled output +can embed the package version, and packaging and provenance must use the tagged +source. Reusing a pre-version CI artifact would break that relationship. + +## Decision + +Keep linting, tests, coverage and security analysis in independent consumer CI. +Remove their inputs and the nested CI invocation from the release workflow. +Keep a dedicated build job that delegates compilation to the existing Build +action. A small release build action translates the release build configuration +and preserves artifact paths for packaging and documentation deployment. + +Release retains version preparation, tagged builds, changelogs, optional AI notes, +publication and recovery. Consumers retain CI policy and release environment +rules. The release workflow does not query or wait for CI status. + +## Consequences + +CI changes no longer change the release workflow's validation settings. The build +job needs only contents and packages read permissions. A release build is not +proof that tests passed on the tag; consumers must enforce their own checks. +This matters for Lerna's generated version commit, which is pushed directly. + +Artifact output and recovery contracts remain unchanged. A failed release build +stops publication, and retries rebuild the original tag. Manual and scheduled +triggers and automatic Conventional Commit version selection remain unchanged. diff --git a/docs/adr/0003-hoverkraft-release-actions.md b/docs/adr/0003-hoverkraft-release-actions.md new file mode 100644 index 0000000..528a605 --- /dev/null +++ b/docs/adr/0003-hoverkraft-release-actions.md @@ -0,0 +1,52 @@ +# ADR 0003: Use HoverKraft release actions for planning and publication + +- Status: accepted; build ownership and orchestration partially superseded by + [ADR 0004](0004-ci-produces-release-artifacts.md) +- Date: 2026-10-31 +- Partially supersedes: [ADR 0001](0001-release-orchestration.md) + +## Context + +Release Please added a separate release policy and PR lifecycle for single +packages. Lerna independently selected monorepo versions. HoverKraft already +provides shared release planning, changelog rendering, AI notes and publication. + +The `ci-github-publish` stable release 1.0.3, commit +`ea6682de88070c254dac619a6623a242a6d57cd3`, was checked on this date. +Its `release/plan` returns change detection and the planned tag. Its internal +`release/prepare` helper can render notes for an explicit tag without writing a +release. `release/update` uploads provided assets without overwriting existing +names and publishes only after those uploads succeed. + +## Decision + +Use `release/plan` as the version authority for both single packages and Lerna +workspaces. Keep npm and Lerna as tools that apply the exact planned version to +manifests and lockfiles. Lerna also maintains workspace dependencies and package +changelogs. Remove Release Please, release PR detection and its pending labels. + +Use `release/get-configuration` and the pinned `release/prepare` helper in dry-run +mode to render the planned changelog before committing source files. This is the +one direct use of the internal helper: the public planner's outputs do not expose +the rendered notes. Pass the planned tag explicitly; do not calculate a second +release identity. Preserve older root changelog entries. + +Push the version commit and tag atomically in both modes. Retain explicit tag +dispatch, build and npm publication. Use `release/create` for the draft and its +optional AI summary. Verify existing asset digests and stage only missing files; +let `release/update` upload those files and publish the draft. + +## Consequences + +Manual and scheduled releases share the same preparation policy. Both require +branch rules permitting the release commit. Neither mode creates or auto-merges +a release PR. CI remains independent as decided in ADR 0002. + +Root changelogs and release notes use HoverKraft's configuration. The initial +interface supports stable bare, v-prefixed and directory-scoped version tags. +Existing release history must be consistent with committed versions. Older or +equal plans, existing tags and concurrent branch updates stop preparation. + +Retries use the original tag without planning again. Already published npm bytes +and GitHub assets remain protected. No additional release planner or npm runtime +dependency is introduced by the Node.js workflow. diff --git a/docs/adr/0004-ci-produces-release-artifacts.md b/docs/adr/0004-ci-produces-release-artifacts.md new file mode 100644 index 0000000..46c0dec --- /dev/null +++ b/docs/adr/0004-ci-produces-release-artifacts.md @@ -0,0 +1,49 @@ +# ADR 0004: CI produces the artifacts consumed by release + +- Status: accepted +- Date: 2026-10-31 +- Partially supersedes: [ADR 0002](0002-separate-ci-from-release.md) and + [ADR 0003](0003-hoverkraft-release-actions.md) + +## Context + +ADR 0002 separated validation from publication but left compilation and packaging +inside release. This duplicated build ownership and did not prove that CI checked +the generated version commit. Artifacts from before version preparation can embed +an old version, so simply reusing the preceding branch build is insufficient. + +## Decision + +Expose preparation and publication as separate reusable workflows. The caller +connects preparation, its existing CI configuration, and publication through `needs`. +Preparation retains HoverKraft's planner, npm/Lerna version application, atomic push +and explicit dispatch at the resulting tag. It never builds the project. + +CI owns compilation, tests and optional packaging on that exact tagged commit. Add +an optional package list input and an artifact list output to the existing CI +workflow. Packaging runs only after all enabled checks succeed. Ordinary CI leaves +packaging disabled. Consumers with a shared CI wrapper forward these two values +instead of duplicating build and test settings. + +Publication consumes immutable CI tarball IDs from the same run and source SHA. +Verify artifact metadata, tag versions and tarball manifests before npm publication. +Keep HoverKraft draft creation, AI summaries, asset upload and final publication. +Remove the release build helper and its configuration surface. + +## Consequences + +One caller serializes the complete pipeline; reusable workflow concurrency groups +remain distinct. The publication job depends on successful CI. Artifact metadata +checks alone cannot prove that tests passed, so that dependency is part of the caller +contract. Cross-run lookup and polling are deliberately excluded. + +A failed-job rerun reuses successful CI artifacts, including successful matrix jobs +from earlier attempts of the same run. A new dispatch at the original tag reruns CI. +Expired artifacts fail explicitly. Existing npm bytes and GitHub assets retain the +integrity and retry protections from ADR 0003. Documentation deploys from CI's build +artifact after publication succeeds. + +The initial packaging path supports the existing default Ubuntu runner and restored +build artifacts, not container-backed CI. This avoids promising path restoration +across incompatible runner layouts. Manual and scheduled triggers and automatic +Conventional Commit versions are unchanged. diff --git a/docs/development/release-tests.md b/docs/development/release-tests.md new file mode 100644 index 0000000..c36278b --- /dev/null +++ b/docs/development/release-tests.md @@ -0,0 +1,30 @@ +# Validate release automation + +Install the test dependencies and run the release suite: + +```sh +npm ci --prefix tests/release +npm test --prefix tests/release +``` + +Artifact handoff tests check exact run and commit identity, package versions, +missing and expired artifacts, partial matrix reruns, and tarball manifests. +The suite uses temporary local Git repositories and offline npm commands. It +executes npm and the installed Lerna with planned versions, checks dependent +package and lockfile changes, and +tests no-change behavior, tag collisions and concurrent branch pushes. A single +package fixture applies a release plan, builds a CLI, packs it, installs +the tarball and executes its entry point. + +Registry and GitHub responses are mocked for partial publication, integrity +failures, draft lookup and staging missing assets for HoverKraft upload. Release +plans and rendered notes are supplied as upstream action outputs; this suite does +not duplicate HoverKraft's version calculation tests. Tests do not call +OpenAI, publish packages or create remote releases. The suite runs in the shared +CI workflow. The continuous-integration workflow test also enables packaging, +downloads the returned raw artifact ID and compares its compiled file with the +original CI build output. It does not publish a package. + +Run `make lint` for repository linting. Generate changed action and workflow +readmes with the existing CI Dokumentor tool used by `release-actions.yml`; edit +metadata rather than generated files. The user guide lives in `docs/usage/`. diff --git a/docs/usage/custom-releases.md b/docs/usage/custom-releases.md new file mode 100644 index 0000000..94d39ad --- /dev/null +++ b/docs/usage/custom-releases.md @@ -0,0 +1,58 @@ +# Compose a custom release pipeline + +Use [the shared release workflows](releases.md) for single npm packages and +fixed-version Lerna workspaces. For custom registries or packaging rules, compose +the existing actions while keeping preparation, CI and publication separate. + +## Preparation + +Use HoverKraft [`release/plan`](https://github.com/hoverkraft-tech/ci-github-publish/tree/1.0.3/actions/release/plan) +for version selection. Commit version, lockfile and changelog updates before CI +builds the source, especially when compiled files embed the version. Keep the planned +tag fixed throughout the pipeline. The [Node.js preparation action](../../actions/release/prepare/README.md) +handles this for npm and fixed-version Lerna projects and dispatches the caller at the tag. + +## CI artifacts + +Run the [CI workflow](../../.github/workflows/continuous-integration.md) against the +prepared commit. Its optional `packages` input delegates packaging to the +[Package action](../../actions/package/README.md) after checks pass. It returns +`package-artifacts` for publication and `build-artifact-id` for documentation deployment. + +If you own the packaging jobs, the Package action accepts a build artifact ID and +package directory. It checks out the workflow's source ref, installs dependencies, +restores build output, and runs `npm pack`. Start that workflow at the prepared tag; +an earlier step checking out a different ref does not change Package's own checkout. +Leave its `version` input empty when versions are already committed. Run any tarball +smoke tests in CI before making artifacts available to publication. + +## Publication + +Keep publication dependent on successful CI. The [Publish action](../../actions/publish/README.md) +consumes one CI tarball artifact ID and never packages the project. A dry run validates +`npm publish` inputs, but does not prove registry authentication or trusted publishing. +See its [authentication guide](../../actions/publish/README.md#registry-tokens-and-github-packages) +for registries beyond npmjs.org. + +Use HoverKraft [`release/create`](https://github.com/hoverkraft-tech/ci-github-publish/tree/1.0.3/actions/release/create) +to draft notes and optional AI summaries before npm publication. Pass the prepared +tag and source SHA. Set `publish: "false"` until all packages and assets succeed. +Use [`release/update`](https://github.com/hoverkraft-tech/ci-github-publish/tree/1.0.3/actions/release/update) +to attach assets and publish the draft. Those actions expect ZIP artifacts for release +assets; the Package action's raw `.tgz` must be wrapped with `upload-artifact` using +its default archive mode. + +The [shared publication workflow](../../.github/workflows/release.md) already performs +these steps for npmjs.org, including exact artifact identity checks, AI summaries and +safe retries. It accepts only artifacts from CI in the same run and at the same tag. + +## Recovery + +npm publication across several packages cannot be atomic. Check exact package +versions before retrying; published versions cannot be overwritten. Restore original +published bytes for release assets, verify integrity and existing asset digests, and +upload only missing assets. Do not delete a draft to undo an npm publication. + +The [release recovery guide](releases.md#run-and-resume-releases) describes this behavior +for the shared workflow. Custom pipelines own equivalent recovery rules. Keep the +original tag and source identity when finishing a partial release. diff --git a/docs/usage/examples/reactionable-cli.yml b/docs/usage/examples/reactionable-cli.yml new file mode 100644 index 0000000..8b53f52 --- /dev/null +++ b/docs/usage/examples/reactionable-cli.yml @@ -0,0 +1,87 @@ +# Replace with a published ci-github-nodejs commit containing these workflows. +name: Release + +on: + workflow_dispatch: + schedule: + - cron: "25 8 * * 1" + +permissions: {} + +concurrency: + group: release-${{ github.repository }} + cancel-in-progress: false + +jobs: + prepare: + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/prepare-release.yml@ + permissions: + actions: write + contents: write + pull-requests: read + with: + environment: github-pages + + ci: + needs: prepare + if: needs.prepare.outputs.status == 'ready' + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@ + permissions: + actions: read + contents: read + packages: read + pull-requests: write + security-events: write + id-token: write + with: + packages: ${{ needs.prepare.outputs.packages }} + build: | + {"commands":["build","build:doc"],"artifact":["dist","build"]} + test: '{"coverage":"codecov"}' + + release: + needs: ci + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/release.yml@ + permissions: + actions: read + contents: write + pull-requests: read + id-token: write + with: + package-artifacts: ${{ needs.ci.outputs.package-artifacts }} + environment: github-pages + ai-summary: true + secrets: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + + pages: + name: Deploy documentation + needs: [ci, release] + if: needs.release.outputs.status == 'published' + runs-on: ubuntu-latest + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.url }} + outputs: + url: ${{ steps.deployment.outputs.url }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - id: deployment + uses: hoverkraft-tech/ci-github-publish/actions/deploy/github-pages@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + with: + build-artifact-id: ${{ needs.ci.outputs.build-artifact-id }} + build-path: build/docs + + deploy-checks: + needs: pages + uses: hoverkraft-tech/ci-github-publish/.github/workflows/deploy-checks.yml@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + permissions: + contents: read + with: + url: ${{ needs.pages.outputs.url }} diff --git a/docs/usage/examples/reactionable.yml b/docs/usage/examples/reactionable.yml new file mode 100644 index 0000000..6740598 --- /dev/null +++ b/docs/usage/examples/reactionable.yml @@ -0,0 +1,80 @@ +# Replace with a published ci-github-nodejs commit containing these workflows. +name: Release + +on: + workflow_dispatch: + schedule: + - cron: "25 8 * * 1" + +permissions: {} + +concurrency: + group: release-${{ github.repository }} + cancel-in-progress: false + +jobs: + prepare: + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/prepare-release.yml@ + permissions: + actions: write + contents: write + pull-requests: read + with: + versioning: lerna + environment: github-pages + + ci: + needs: prepare + if: needs.prepare.outputs.status == 'ready' + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@ + permissions: + actions: read + contents: read + packages: read + pull-requests: write + security-events: write + id-token: write + with: + packages: ${{ needs.prepare.outputs.packages }} + build: | + {"commands":["build:ci","storybook:build","docs:build"],"artifact":["packages/**/lib","build","packages/**/docs"]} + test: '{"coverage":"codecov"}' + + release: + needs: ci + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/release.yml@ + permissions: + actions: read + contents: write + pull-requests: read + id-token: write + with: + package-artifacts: ${{ needs.ci.outputs.package-artifacts }} + environment: github-pages + ai-summary: true + secrets: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + + pages: + name: Deploy documentation + needs: [ci, release] + if: needs.release.outputs.status == 'published' + runs-on: ubuntu-latest + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.url }} + outputs: + url: ${{ steps.deployment.outputs.url }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - id: deployment + uses: hoverkraft-tech/ci-github-publish/actions/deploy/github-pages@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3 + with: + build-artifact-id: ${{ needs.ci.outputs.build-artifact-id }} + build-path: build/storybook diff --git a/docs/usage/releases.md b/docs/usage/releases.md new file mode 100644 index 0000000..a88503d --- /dev/null +++ b/docs/usage/releases.md @@ -0,0 +1,152 @@ +# Release a single package or Lerna workspaces + +Connect three reusable workflows: **prepare → CI → publish**. The caller owns the +manual and scheduled triggers. Consumers need no versioning or publication scripts. + +- [Prepare release](../../.github/workflows/prepare-release.md) uses HoverKraft's + Conventional Commit release plan, commits versions and changelogs, and atomically + pushes the version commit and tag. It dispatches the caller at that tag. +- [Continuous integration](../../.github/workflows/continuous-integration.md) builds, + tests and packages the prepared commit. Use the same CI configuration as pull requests. +- [Release](../../.github/workflows/release.md) consumes those CI tarballs, generates + release notes and an optional AI summary, publishes npm packages, and finalizes the + GitHub release. It does not build or pack the project. + +The tag run is essential: artifacts built before version preparation can contain the +old version. All three workflows run against the prepared commit during publication. + +## Set up + +1. Keep the package's stable version and existing GitHub release history aligned. + HoverKraft selects the next version from that history and Conventional Commits. + A plan older than or equal to the committed version fails instead of guessing a + replacement. Configure `.github/release-config.yml` when needed; repository + configuration takes precedence over generated defaults. +2. Configure [npm trusted publishing](../../actions/publish/README.md#npm-trusted-publishing) + for your repository, caller workflow filename and environment. Publish a new + package's first version before configuring its trusted publisher. Publication + uses GitHub-hosted runners with `id-token: write`. +3. Permit the preparation identity to push release commits and tags under your branch + and tag rules. Preparation defaults to `GITHUB_TOKEN`; optionally pass + `github-token` to `prepare-release.yml`. The token does not bypass repository rules. +4. Allow the chosen environment on the default branch and release tags. Set + `OPENAI_API_KEY` and pass it to publication when enabling `ai-summary`. +5. Copy a caller example and replace `` with the same supported + `ci-github-nodejs` commit throughout: + - [Single npm package with documentation deployment](examples/reactionable-cli.yml) + - [Fixed-version Lerna workspaces with documentation deployment](examples/reactionable.yml) + +The minimal connection between the jobs is: + +```yaml +jobs: + prepare: + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/prepare-release.yml@ + permissions: + actions: write + contents: write + pull-requests: read + + ci: + needs: prepare + if: needs.prepare.outputs.status == 'ready' + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@ + permissions: + actions: read + contents: read + packages: read + pull-requests: write + security-events: write + id-token: write + with: + packages: ${{ needs.prepare.outputs.packages }} + build: '{"commands":["build"],"artifact":["dist"]}' + + release: + needs: ci + uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/release.yml@ + permissions: + actions: read + contents: write + pull-requests: read + id-token: write + with: + package-artifacts: ${{ needs.ci.outputs.package-artifacts }} +``` + +Add `workflow_dispatch`, your schedule, `permissions: {}` and a caller concurrency +group such as `release-${{ github.repository }}` with `cancel-in-progress: false`. +Use a different group from either reusable workflow. This serializes the whole +pipeline, including CI. If your repository already has a shared CI wrapper, forward +its optional `packages` input and `package-artifacts` output instead of copying build +and test settings into the release caller. Ordinary CI leaves `packages` empty. + +## Versioning and packaging + +Preparation defaults to `versioning: npm` for a single public package. npm applies +the exact planned version to the manifest and lockfile without running version scripts. +For fixed-version workspaces, set `versioning: lerna` on **prepare** and install +Lerna in the project. Lerna applies the exact planned version, updates internal +dependency ranges and lockfiles, and uses `--conventional-commits` for package +changelogs. It does not select another version. Independent versions and prereleases +are unsupported. The root `CHANGELOG.md` receives HoverKraft's rendered notes. + +Only public workspaces at the new version are packaged; unchanged packages can keep +their previous versions. If Lerna reports no changed packages, preparation creates no +commit, tag or publication run. If the default branch advances during preparation, +the atomic push fails without publishing the new tag. Existing tags are never overwritten. + +Set matching `working-directory` values on all three workflows for nested projects. +The planner supports bare stable tags, `v`-prefixed tags and directory-slug prefixes +for nested projects. The committed version must match the selected tag. + +CI packaging requires `checks: true`, a build artifact, the default +`runs-on: '["ubuntu-latest"]'`, and no container. Configure the build artifact to +include the compiled package files and any documentation you deploy. Packaging runs +after all enabled checks succeed, restores the build output and runs `npm pack`. +Package lifecycle scripts therefore run in CI. Publication never installs project +dependencies or invokes its build or packaging scripts. + +CI returns immutable tarball IDs. Publication verifies that each artifact belongs to +this run and commit, then checks the tarball's package name and version before npm +publication. Cross-run artifact reuse is unsupported. A caller must keep `release` +dependent on successful CI; artifact metadata alone is not proof that checks passed. + +## Run and resume releases + +Run the caller from the default branch or wait for its schedule. Preparation reports: + +| Status | Meaning | +| ------------ | --------------------------------------------------- | +| `no-changes` | No release needed; CI and publication are skipped. | +| `dispatched` | Follow the new caller run at the prepared tag. | +| `released` | This version already has a public GitHub release. | +| `ready` | This tag run can start CI, followed by publication. | + +Publication reports `published` only after all npm packages and release assets +succeed. Preparation success alone does not mean publication succeeded. + +AI generation runs before npm publication. The draft becomes public only after every +package and asset succeeds. Review AI summaries for accuracy; published releases +keep their notes on retries. Asset upload and final publication use HoverKraft +`release/update`. + +For a failed publication job, rerun failed jobs: successful CI tarballs from earlier +attempts of the same run are reused without rebuilding. Expired or deleted artifacts +fail rather than falling back to another run. To run CI again and resume the same +release, dispatch the **caller** at its original tag: + +```sh +gh workflow run release.yml --ref v1.2.3 +``` + +A tag run never plans another version. Already published npm versions are skipped, +and their original tarballs are restored with SHA-512 verification for GitHub assets. +Existing assets are reused only when SHA-256 digests match. Conflicts or unavailable +digests fail instead of replacing assets. Partial npm publication remains possible; +registry errors stop recovery, and only an absent version permits publication. +If source needs changing, make a new commit and release. Do not move a release tag. + +For documentation deployment, require `release.outputs.status == 'published'` and +consume **CI's** `build-artifact-id`. The publication workflow returns `status`, +`tag` and `release-url`; documentation remains an independent caller job. diff --git a/tests/release/artifacts.test.js b/tests/release/artifacts.test.js new file mode 100644 index 0000000..59dd627 --- /dev/null +++ b/tests/release/artifacts.test.js @@ -0,0 +1,220 @@ +const assert = require("node:assert/strict"); +const { createHash } = require("node:crypto"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const { test } = require("node:test"); +const { + ReleaseArtifacts, +} = require("../../actions/release/ReleaseArtifacts.js"); +const restorePackage = (inputs, fetchPackage) => + new ReleaseArtifacts(fetchPackage).restorePackage(inputs); + +function directory(t) { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "nodejs-release-assets-")); + t.after(() => fs.rmSync(root, { recursive: true, force: true })); + return root; +} + +test("finds drafts when the release-by-tag endpoint does not return them", async () => { + const draft = { id: 1, tag_name: "v1.2.0", draft: true }; + const github = { + rest: { + repos: { + getReleaseByTag: async () => { + throw Object.assign(new Error("Not found"), { status: 404 }); + }, + }, + }, + paginate: async () => [draft], + }; + assert.equal(await ReleaseArtifacts.findRelease(github, {}, "v1.2.0"), draft); + assert.equal( + await ReleaseArtifacts.findRelease(github, {}, "v1.3.0"), + undefined, + ); + github.rest.repos.getReleaseByTag = async () => { + throw Object.assign(new Error("Forbidden"), { status: 403 }); + }; + await assert.rejects( + ReleaseArtifacts.findRelease(github, {}, "v1.2.0"), + /Forbidden/, + ); +}); + +function registryFixture(t) { + const root = directory(t); + const tarballPath = path.join(root, "package.tgz"); + fs.writeFileSync(tarballPath, "new build"); + const published = Buffer.from("the exact bytes published to npm"); + const metadata = { + name: "@example/core", + version: "1.2.0", + dist: { + tarball: "https://registry.npmjs.org/@example/core/-/core-1.2.0.tgz", + integrity: `sha512-${createHash("sha512").update(published).digest("base64")}`, + }, + }; + return { + tarballPath, + published, + metadata, + inputs: { name: metadata.name, version: metadata.version, tarballPath }, + }; +} + +test("allows publication only when the npm version is absent", async (t) => { + const f = registryFixture(t); + assert.equal( + await restorePackage( + f.inputs, + async () => new Response(null, { status: 404 }), + ), + false, + ); + assert.equal(fs.readFileSync(f.tarballPath, "utf8"), "new build"); + await assert.rejects( + restorePackage(f.inputs, async () => new Response(null, { status: 503 })), + /HTTP 503/, + ); +}); + +test("recovers the original npm tarball for an already published version", async (t) => { + const f = registryFixture(t); + const requested = []; + const published = await restorePackage(f.inputs, async (url) => { + requested.push(url); + return requested.length === 1 + ? Response.json(f.metadata) + : new Response(f.published); + }); + assert.equal(published, true); + assert.deepEqual(fs.readFileSync(f.tarballPath), f.published); + assert.deepEqual(requested, [ + "https://registry.npmjs.org/%40example%2Fcore/1.2.0", + f.metadata.dist.tarball, + ]); +}); + +test("rejects corrupted tarballs without replacing the package file", async (t) => { + const f = registryFixture(t); + let requests = 0; + await assert.rejects( + restorePackage(f.inputs, async () => + ++requests === 1 ? Response.json(f.metadata) : new Response("corrupt"), + ), + /integrity verification/, + ); + assert.equal(fs.readFileSync(f.tarballPath, "utf8"), "new build"); +}); + +test("rejects unexpected registry identities, download hosts, and failed downloads", async (t) => { + const f = registryFixture(t); + await assert.rejects( + restorePackage(f.inputs, async () => + Response.json({ ...f.metadata, version: "9.0.0" }), + ), + /unexpected package version/, + ); + await assert.rejects( + restorePackage(f.inputs, async () => + Response.json({ + ...f.metadata, + dist: { tarball: "https://example.invalid/package.tgz" }, + }), + ), + /npm registry/, + ); + let requests = 0; + await assert.rejects( + restorePackage(f.inputs, async () => + ++requests === 1 + ? Response.json(f.metadata) + : new Response(null, { status: 503 }), + ), + /download failed/, + ); +}); + +function assetsFixture(t) { + const root = directory(t); + const data = Buffer.from("published package"); + fs.writeFileSync(path.join(root, "example-core-1.2.0.tgz"), data); + const release = { id: 1, draft: true }; + const assets = []; + const github = { + rest: { + repos: { + getReleaseByTag: async () => ({ data: release }), + }, + }, + paginate: async () => assets, + }; + return { + release, + assets, + data, + args: { + github, + repo: { owner: "example", repo: "project" }, + tag: "v1.2.0", + directory: root, + }, + }; +} + +test("stages only missing package bytes for HoverKraft upload and skips identical assets", async (t) => { + const f = assetsFixture(t); + const result = await new ReleaseArtifacts().prepareAssets(f.args); + assert.equal(result.hasAssets, true); + assert.deepEqual( + fs.readFileSync( + path.join(result.pendingDirectory, "example-core-1.2.0.tgz"), + ), + f.data, + ); + f.assets.push({ + name: "example-core-1.2.0.tgz", + digest: `sha256:${createHash("sha256").update(f.data).digest("hex")}`, + }); + const retry = await new ReleaseArtifacts().prepareAssets(f.args); + assert.equal(retry.hasAssets, false); + assert.deepEqual(fs.readdirSync(retry.pendingDirectory), []); + f.release.draft = false; + assert.equal( + (await new ReleaseArtifacts().prepareAssets(f.args)).hasAssets, + false, + ); +}); + +test("does not overwrite mismatched assets or modify an incomplete published release", async (t) => { + const f = assetsFixture(t); + f.assets.push({ name: "example-core-1.2.0.tgz", digest: "sha256:different" }); + await assert.rejects( + new ReleaseArtifacts().prepareAssets(f.args), + /different or unavailable digest/, + ); + f.assets.length = 0; + f.release.draft = false; + await assert.rejects( + new ReleaseArtifacts().prepareAssets(f.args), + /missing expected asset/, + ); +}); + +test("partial asset recovery passes only missing tarballs to the uploader", async (t) => { + const f = assetsFixture(t); + const name = "example-cli-1.2.0.tgz"; + fs.writeFileSync(path.join(f.args.directory, name), "second package"); + f.assets.push({ + name: "example-core-1.2.0.tgz", + digest: `sha256:${createHash("sha256").update(f.data).digest("hex")}`, + }); + const result = await new ReleaseArtifacts().prepareAssets(f.args); + assert.equal(result.hasAssets, true); + assert.deepEqual(fs.readdirSync(result.pendingDirectory), [name]); + assert.equal( + fs.readFileSync(path.join(result.pendingDirectory, name), "utf8"), + "second package", + ); +}); diff --git a/tests/release/package-artifacts.test.js b/tests/release/package-artifacts.test.js new file mode 100644 index 0000000..67f8511 --- /dev/null +++ b/tests/release/package-artifacts.test.js @@ -0,0 +1,160 @@ +const assert = require("node:assert/strict"); +const { test } = require("node:test"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const { execFileSync } = require("node:child_process"); +const { + PackageArtifacts, +} = require("../../actions/package-artifacts/PackageArtifacts.js"); +const { + ReleaseArtifacts, +} = require("../../actions/release/ReleaseArtifacts.js"); + +const context = { + repo: { owner: "example", repo: "project" }, + runId: 42, + sha: "prepared-commit", +}; +const item = { + name: "@example/cli", + slug: "example-cli", + version: "1.2.3", + directory: ".", +}; +const artifact = (id, attempt = 1, overrides = {}) => ({ + id, + name: `npm-example-cli-42-${attempt}.tgz`, + expired: false, + workflow_run: { id: 42, head_sha: context.sha }, + ...overrides, +}); +const collector = (artifacts) => + new PackageArtifacts({ + context, + github: { + paginate: async () => artifacts, + rest: { + actions: { + listWorkflowRunArtifacts() {}, + getArtifact: async ({ artifact_id }) => ({ + data: artifacts.find((entry) => entry.id === artifact_id), + }), + }, + }, + }, + }); + +test("collects exact CI artifact IDs and filenames for publication", async () => { + const result = await collector([artifact(10)]).collect( + JSON.stringify([item]), + ); + assert.deepEqual(result, [ + { ...item, "artifact-id": 10, "artifact-name": "npm-example-cli-42-1.tgz" }, + ]); + assert.deepEqual( + await collector([artifact(10)]).verify(JSON.stringify(result), "1.2.3"), + result, + ); +}); + +test("failed-job reruns combine successful packages from different attempts", async () => { + const other = { + ...item, + name: "other", + slug: "other", + directory: "packages/other", + }; + const result = await collector([ + artifact(10), + artifact(20, 2), + artifact(30, 1, { name: "npm-other-42-1.tgz" }), + ]).collect(JSON.stringify([item, other])); + assert.deepEqual( + result.map((entry) => entry["artifact-id"]), + [20, 30], + ); +}); + +test("fails when any package is missing, expired or from another run", async () => { + for (const artifacts of [ + [], + [artifact(10, 1, { expired: true })], + [artifact(10, 1, { workflow_run: { id: 41, head_sha: context.sha } })], + [artifact(10, 1, { workflow_run: undefined })], + ]) { + await assert.rejects( + collector(artifacts).collect(JSON.stringify([item])), + /CI tarball|CI artifact/, + ); + } +}); + +test("rejects ambiguous names, unsafe paths, invalid versions and invalid package lists", () => { + const service = collector([]); + for (const packages of [ + [], + {}, + [null], + [item, item], + [{ ...item, slug: "wrong" }], + [{ ...item, name: "../bad" }], + [{ ...item, directory: "../outside" }], + [{ ...item, directory: "/tmp" }], + [{ ...item, version: "1.2.3-beta" }], + ]) { + assert.throws( + () => service.parse(JSON.stringify(packages)), + /Expected|unique/, + ); + } +}); + +test("publication rejects changed artifact IDs, filenames, source commits and release versions", async () => { + const service = collector([artifact(10)]); + const [valid] = await service.collect(JSON.stringify([item])); + for (const entry of [ + { ...valid, version: "1.2.2" }, + { ...valid, "artifact-id": "10" }, + { ...valid, "artifact-name": "other.tgz" }, + ]) { + await assert.rejects( + service.verify(JSON.stringify([entry]), "1.2.3"), + /version|artifact/, + ); + } + await assert.rejects( + collector([ + artifact(10, 1, { workflow_run: { id: 42, head_sha: "old" } }), + ]).verify(JSON.stringify([valid]), "1.2.3"), + /prepared commit/, + ); +}); + +test("checks the packaged manifest without executing package lifecycle scripts", (t) => { + const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ci-tarball-")); + t.after(() => fs.rmSync(directory, { recursive: true, force: true })); + fs.mkdirSync(path.join(directory, "package")); + const tarballPath = path.join(directory, "package.tgz"); + for (const manifest of [ + { name: item.name, version: item.version }, + { name: "wrong", version: item.version }, + { name: item.name, version: "1.2.2" }, + { name: item.name, version: item.version, private: true }, + ]) { + fs.writeFileSync( + path.join(directory, "package/package.json"), + JSON.stringify({ ...manifest, scripts: { prepublishOnly: "exit 1" } }), + ); + execFileSync("tar", ["-czf", tarballPath, "package"], { cwd: directory }); + const verify = () => + ReleaseArtifacts.verifyTarball({ ...item, tarballPath }); + if ( + manifest.name === item.name && + manifest.version === item.version && + !manifest.private + ) + assert.doesNotThrow(verify); + else assert.throws(verify, /expected public package/); + } +}); diff --git a/tests/release/package-lock.json b/tests/release/package-lock.json new file mode 100644 index 0000000..90f9ebb --- /dev/null +++ b/tests/release/package-lock.json @@ -0,0 +1,5499 @@ +{ + "name": "nodejs-release-tests", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nodejs-release-tests", + "devDependencies": { + "lerna": "10.1.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@clack/core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", + "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@clack/prompts": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz", + "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/core": "1.4.3", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@conventional-changelog/template": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.4.0.tgz", + "integrity": "sha512-aalGyl7dbB5PArRebDIX43ZvBlXrYm9uWzGJ26t+4SzJVPsOuvfILGGbw5X4yX7i50YEmJ8zvbiWnqH/AAnZqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@emnapi/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", + "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emnapi/wasi-threads": "1.0.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", + "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@gar/promise-retry": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", + "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@inquirer/ansi": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.10.tgz", + "integrity": "sha512-dwrc+1aqVZpHNkNDswXGtn1typ+Pxpo5FHZRyBw1le7onEJUkPUkYOY1FIFC1LvFMYUqqLuWBwElhAmencL7MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.8.tgz", + "integrity": "sha512-NY/S1EalQhlonqhwwsarrcnkH7s9ByQuvjWYdk1jB2Gb9EPQJjKkhCTWjM3yQ0UpHaLm1XbIL89b+32G8rhO5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.10", + "@inquirer/core": "^12.0.6", + "@inquirer/figures": "^2.0.10", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/checkbox/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.3.5.tgz", + "integrity": "sha512-BJ59BOyURiZiAxdr9AuRu38/k+rV+DcTIM2fUF/c/BXrab6H8zMZTTOl3LgkSJH96Xob2vOJxDiBkHiz32Xx2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.6", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "12.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.6.tgz", + "integrity": "sha512-5yxn2LsJ8Tu4ei2a+yNkmFRhM/cb+JMEsEs/AW6CCOnBnpMy4IjYiPMFyHtYq8weOmlTyqqCx40y0DsD7OsEPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.10", + "@inquirer/figures": "^2.0.10", + "@inquirer/type": "4.2.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.6.tgz", + "integrity": "sha512-Z5SOeRC5VNkINfKN4rY8BSaYKb3GYi8iSEqZZRqogsE2GhBBToQ0Xw25SbI+4bcatLzU009mZ5d9EuJNiJuUCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.6", + "@inquirer/external-editor": "^3.0.7", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.8.tgz", + "integrity": "sha512-dMEnTkpLqzM/sbILwL7QJgx9iX5hoEM8+bh6shgwd9mYJamdOnth7y2mMaFd08Glj9AXEFKllWcGYyBqnJsHrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.6", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.7.tgz", + "integrity": "sha512-enNqTJpojgISCG+a5acjnfJ02hcRTFUBVm8uXiCY40PRPZtSzFnNLskOTU+kDUUEODYma90syxuea1rRtUFh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.10.tgz", + "integrity": "sha512-51elrUJV3jZpvD0ygz8+U10Kc6+Lzqln+/tYmnbhy6jo5oXpE6hMCcv+OTBC0enwJXsb3JIuT3VtEinRNCSK2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/input": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.9.tgz", + "integrity": "sha512-2Vd5T7lTxfgJMpAd3aOu6bQpbUnCU7tBgvTQIZkP/7juJzmRmTM2t5XfOCuirFduWLTSJI/WZp32Cq1E01TVeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.6", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/input/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.6.tgz", + "integrity": "sha512-22LnGGCDm1M/pKXxxF8n6ppr/1IztdsxqeqeBRUMTTNnJTkjIBiAkewiDM4u/gjtazj/FvZS+nk9AbO/vEcBFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.6", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.2.5.tgz", + "integrity": "sha512-0v0wLQA4uhWbybmdH6oPl7ooxCiymNylkvi2gCSc+mA5ZQB6QoJLVhoHq12T82lhozpp9fpMJnJkC1nJrU/A+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.10", + "@inquirer/core": "^12.0.6", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.7.5.tgz", + "integrity": "sha512-l/IWwC+QhOyXgxkZloOh+n5quGzc1m5ZawyzBmoizCZaxbJeLRdS3pStoqg/JVInJRXaG5aHMhjK6H6oYiBC9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^5.2.8", + "@inquirer/confirm": "^6.3.5", + "@inquirer/editor": "^5.3.6", + "@inquirer/expand": "^5.1.8", + "@inquirer/input": "^5.1.9", + "@inquirer/number": "^4.2.6", + "@inquirer/password": "^5.2.5", + "@inquirer/rawlist": "^5.3.8", + "@inquirer/search": "^4.3.6", + "@inquirer/select": "^5.2.8" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.8.tgz", + "integrity": "sha512-h+6Y4pPvYvuRbksn1kIBdD9tCYD+E468W5sIcVfLmoLP5IasnY0r33N+r+46ej/P8b2PCREjyKR+MnnfPGdTzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.6", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.6.tgz", + "integrity": "sha512-JZj9ttkIvuaFQIc2oxsyqC1ad05WL02ku6W/INVKTCzNaVq1KkhP3AfTRC0m7OWlKZyw+EWwPBFZfYiG9jF6Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.6", + "@inquirer/figures": "^2.0.10", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.8.tgz", + "integrity": "sha512-BklkkAAOpjdCfuQw5fVGcDuhKxA7T1iBpn6b2JUvDDdkIsO3Ftlg+WnWUCVpkUBFagL2o036OFW+xL4lC9wIPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.10", + "@inquirer/core": "^12.0.6", + "@inquirer/figures": "^2.0.10", + "@inquirer/type": "4.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select/node_modules/@inquirer/type": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz", + "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.1.tgz", + "integrity": "sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", + "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", + "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emnapi/core": "^1.1.0", + "@emnapi/runtime": "^1.1.0", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@npmcli/agent": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-5.0.2.tgz", + "integrity": "sha512-EkzGmEsgbQ1rqWkRJe2P0oQHx/ylZozDUNPMXCklLuSFL3GY+QyEfBUjhjCsgGXzh4OGpnHvkboSQgczjP/jJg==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^9.0.0", + "http-proxy-agent": "^9.0.0", + "https-proxy-agent": "^9.0.0", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^10.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/arborist": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-10.0.3.tgz", + "integrity": "sha512-QuGpR01YV/4RuJ+5S0W5qh4uljQygmk7b50Jkx+zLErOMMUpKhpbLu/TqQlKfsvuR3SOwXIn3ht+G4bcxrv1WA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^6.0.0", + "@npmcli/installed-package-contents": "^5.0.0", + "@npmcli/map-workspaces": "^6.0.0", + "@npmcli/metavuln-calculator": "^10.0.0", + "@npmcli/name-from-folder": "^5.0.0", + "@npmcli/node-gyp": "^6.0.0", + "@npmcli/package-json": "^8.0.0", + "@npmcli/query": "^5.0.0", + "@npmcli/redact": "^5.0.0", + "@npmcli/run-script": "^11.0.0", + "bin-links": "^7.0.0", + "cacache": "^21.0.1", + "common-ancestor-path": "^2.0.0", + "diff": "^8.0.2", + "hosted-git-info": "^10.1.1", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^11.2.1", + "minimatch": "^10.0.3", + "nopt": "^10.0.1", + "npm-install-checks": "^9.0.0", + "npm-package-arg": "^14.0.0", + "npm-pick-manifest": "^12.0.0", + "npm-registry-fetch": "^20.0.1", + "pacote": "^22.0.0", + "parse-conflict-json": "^6.0.0", + "proc-log": "^7.0.0", + "proggy": "^4.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "semver": "^7.3.7", + "ssri": "^14.0.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^8.0.0", + "walk-up-path": "^4.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-6.0.0.tgz", + "integrity": "sha512-AheOs4swKka/XLtht6xxJDPezlQ7K2IYQ9Y8lST4JLDjnralnWuMM9AE2CdVcgQJ5omrXhsRzM7F7aYmeZBvKQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-8.0.0.tgz", + "integrity": "sha512-5P1oo+TbxZNAiiMBtpzHA8QyEGh5D69LYLexNWJEDXLdxnAZvT/SLitGJBXxjtCE4ftAcFOS/Tu2185MeIjooQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^10.0.0", + "ini": "^7.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^12.0.0", + "proc-log": "^7.0.0", + "semver": "^7.3.5", + "which": "^7.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-5.0.0.tgz", + "integrity": "sha512-6Ay12sf2Lh7U1ifvnS1mq7TZFeh/rXHMXye+kV7jQrANIubaoVcleeh4HdFumxhsRYwm9OaHycB5lYmSwGrcIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^6.0.0", + "npm-normalize-package-bin": "^6.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/map-workspaces": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-6.0.0.tgz", + "integrity": "sha512-Dsex7XBea0BoFRbfALMbNuaNqeI3kbZJxiBMQhFvPUNluv0yEeKMd5FLIXy0NCsOuGMYQkLa+i219CadnoqLbg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^5.0.0", + "@npmcli/package-json": "^8.0.0", + "glob": "^13.0.0", + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-10.0.0.tgz", + "integrity": "sha512-fC56lpGOae+unrFx6hoiWeWa0/4q+bLhOQTSrB65qcy+Zm34i1OdBcevAQFJJdUB/3i9uXw7PjdrrRjt0KSKXw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cacache": "^21.0.1", + "json-parse-even-better-errors": "^6.0.0", + "pacote": "^22.0.0", + "proc-log": "^7.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/name-from-folder": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-5.0.0.tgz", + "integrity": "sha512-Mua2i5asmOn4sGGAsANS9Guamo7sgUd4BihhQWzlNGz6l/Ki23CzC2oGe4I94r2k/39ImCjDLbyu/rSJr/SXoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-6.0.0.tgz", + "integrity": "sha512-MFakpea4pcZNlHSTbMi15HK8RY8zl2UpgDtxhZCWOer+KRN3x7HFIMk/fKpOMgR55L4LIcA2qn8IHeyABhIFtw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-8.0.0.tgz", + "integrity": "sha512-agNZzYQ18MR0wKp3Emg1q5QbcC8CXigYp3Z3CvB0Sax9Ge9aF4cVyyuSG+5SbACSrZUKTvMjVULWiE1RJA38wg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^8.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^10.1.1", + "json-parse-even-better-errors": "^6.0.0", + "proc-log": "^7.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-10.0.1.tgz", + "integrity": "sha512-IstFcKAoEIZ7olS9iTwBsyNOZkIturafO2da9ocSP3LifRlm1+sxuo8IVM5phg5sNe0tNYLT0ZqCBRTLNzz0AA==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^7.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-5.0.0.tgz", + "integrity": "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-5.0.0.tgz", + "integrity": "sha512-3zcN5Q3yEmeyxXBzqB6fXPQFzYa2ROsGFSr69W0ArXIAGJqxl/aFECOVPD2kbkYPm0U/EHxFKgclK3UA9WQg5A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-11.0.0.tgz", + "integrity": "sha512-leBRl6F5F0TvWut8m1/aZcMTUHi2vXjKeMJ/Ik1lW7Q7Yy16Dhtkklu+cEqQww1p1NeLnUNzV3+uwpzqRcy9vw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^6.0.0", + "@npmcli/package-json": "^8.0.0", + "@npmcli/promise-spawn": "^10.0.0", + "node-gyp": "^13.0.0", + "proc-log": "^7.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@nx/devkit": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-23.3.1.tgz", + "integrity": "sha512-Cw6YISZUjit22Trfo/p6rnrNklIKHYgRyp2IyOgr0i9naDgO3Ufllib9D/v0SInwX2zKevaWJWMyreqVvHRU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ejs": "5.0.1", + "minimatch": "10.2.5", + "semver": "^7.6.3", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 22 <= 24 || ^23.0.0-0" + } + }, + "node_modules/@nx/devkit/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@nx/nx-darwin-arm64": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-23.3.1.tgz", + "integrity": "sha512-T3KOTrUIdWaqlIIMyusbpKHujXTumoltkYwBjqjw9Py6Fb3c8Eb7uvWVW6dP8ODknqr9oEcTlk+C8Nid+bunAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@nx/nx-darwin-x64": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-23.3.1.tgz", + "integrity": "sha512-GnbMF9xEGIdUI/7KoQdcTILWmRUrMLbbFi3CO8KgKcA1Be7eaoeKdgBQoCQ2yF7r7DyQOR1PXp7sF3s7gqUATQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@nx/nx-freebsd-x64": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-23.3.1.tgz", + "integrity": "sha512-RzLx1pVL/MQQ/fSreMFIufAfsrj/TpD1+69n5kBcr3An2FaqKdQ6BhKLWRlAeOSKq6Su75Y0la8e2AU5zlmdpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-23.3.1.tgz", + "integrity": "sha512-/K7ig9xL4FMO2eQovTSLtk4QR7d0phbKoWf1wYQZ2r0ZrHNo2gPYmS8wU0Ci4d6oSiqa2fdeHKVDtEvWldTBaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@nx/nx-linux-arm64-gnu": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-23.3.1.tgz", + "integrity": "sha512-Uj3xl5aLXUV6EQ/vWbZBqMqZO9K58CxRIsMTISC1+LxjvGnf4uUL73ObTi3K1eih3f1CVCGsU95LF3Kf6T2Frw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@nx/nx-linux-arm64-musl": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-23.3.1.tgz", + "integrity": "sha512-woeNHutXYgiWU0SQnvKQ4VNgVbqwy1uer6bS0HF2RbfN80HglsjhtzTAUZY2pZiWBLbHcHZwTNmDGTAXSNMLAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@nx/nx-linux-x64-gnu": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-23.3.1.tgz", + "integrity": "sha512-GckqfXo7BAIrcR07CoI0IM06h1wbUim+4AyUYosokrI4Gx1zHZFRwrE3vpPrMpSKVVYZD7BGQp2bhZBPvgGaxg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@nx/nx-linux-x64-musl": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-23.3.1.tgz", + "integrity": "sha512-QjOj5S/X39OxVykltLFSvNxaZtnI9uRk0Uqfyt69kOrZn+/Ap2SM/bT70Xqn8PFxj5hfA0viI2vU1AlOM4JQxg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@nx/nx-win32-arm64-msvc": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-23.3.1.tgz", + "integrity": "sha512-Jf5kc3zhek8Fz06DaMxaJTJxgNJIN2tddE8yxt+XaIHtulmW+MMjy6Z91QPKPf9iZA70N+oT9vwgvYPmOsdO8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@nx/nx-win32-x64-msvc": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-23.3.1.tgz", + "integrity": "sha512-RKQ5t6u4fgOWQyVt61y5Jn/xzXCYxqXOKz2okDbuWccBShQddF8jsqRaLMZDlGT5d8CJTLIso8Y9BiY12/7x7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.8.tgz", + "integrity": "sha512-L7y8eYc+AwxGr2PWI4WFt1VG4TiJ66c26BD16mXpYIlXxG0SMigM1+m4aTSlYyBr5BlQsGAlz8uDCoZN4SEMcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.5", + "@octokit/request": "^10.0.16", + "@octokit/request-error": "^7.1.2", + "@octokit/types": "^18.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.5.tgz", + "integrity": "sha512-iXa654H3yFafF/ieHkukfbgWo2rmXD2ceD0ZOtrPhw1bc3FDch1d9N/TNs0FQ1/cIbwb7kspUX8jzIs8nzb9DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^18.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.5.tgz", + "integrity": "sha512-bt/hm03LeU6Vy7FwTrkkC9p3XGT/lBwClglMqxBSe5/q0E5CdJTXeAqEI0vlw89/LF/G6tryTIH8HirZ3prMVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.16", + "@octokit/types": "^18.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", + "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.16", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.16.tgz", + "integrity": "sha512-A0zWGjHzISIb+9ccG8s0dq7LKO5zVpJLRICjgUb+sJxEWqn8RUHB1rD3AE51+PECvXHIxqZ1VVvs4fHTSD9nUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.5", + "@octokit/request-error": "^7.1.2", + "@octokit/types": "^18.0.0", + "content-type": "^3.0.0", + "json-with-bigint": "^3.5.12", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.2.tgz", + "integrity": "sha512-XZRuT3xZ84D3gYErI1DZvhJ33dCWVV6uzBtWkaBB4TvA/L6eOeTZodxLFVB44bBEEo3vEx7y00UfX1tBLrtLRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^18.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/rest": { + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", + "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.6", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-request-log": "^6.0.0", + "@octokit/plugin-rest-endpoint-methods": "^17.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^29.0.1" + } + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sigstore/bundle": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-5.0.0.tgz", + "integrity": "sha512-wefjygudENbzbQMks1t5u34EP0fFoD0XvaEP7DOUP/sXKvogzEJYFw5E6pegGyp3onGWzVEYKVa3bNZWyTYX+A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-4.0.1.tgz", + "integrity": "sha512-9v5hRjujn5NXq8o7XFEUgLyAtdr5Iisb4pzM05u3K61IS5q3hP3luWAndk0RkPPLTUFoTbg7Vb84UQ1ZQeajWQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.2.tgz", + "integrity": "sha512-SQqvFMt4V78fdjcDdYX6HbiVSOR4QK3ZgwCa2KOsopAgPIHy1rU5UDUmzLl02r5oyyaYcYHR1hpwDRk/yUe+Mw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-5.0.0.tgz", + "integrity": "sha512-DSFivqz9/i5AkwZ5fq0YdjaJlc4o1WeS2Zffon0kqtChx0vy4W9NOjkEet9bF2vkzOufX72eVH8kZBIGtcBp1w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@gar/promise-retry": "^1.0.2", + "@sigstore/bundle": "^5.0.0", + "@sigstore/core": "^4.0.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^16.0.0", + "proc-log": "^7.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-5.0.0.tgz", + "integrity": "sha512-Zyqg9tcHps3uRAlKHLNmsW4ohsUZAjb9G+31r7lg0ICh/JOcadzmJsIRdjKljlRHpaR0K4aJ2kXXIdywdcdMlA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^6.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-4.1.2.tgz", + "integrity": "sha512-BfD9eLrz3A/DG58aSgfgZYmIR6V9Yw96QVN/frtu2bEH7ctSTk2TDvHU12un3JsDPBTqTNkqkIkucjxljpOFqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^5.0.0", + "@sigstore/core": "^4.0.1", + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@simple-libs/child-process-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-2.0.0.tgz", + "integrity": "sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^2.0.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/hosted-git-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/hosted-git-info/-/hosted-git-info-2.0.0.tgz", + "integrity": "sha512-55XwK/GYgV58PuN8lZFhI1qRxdKoMLJocXl/yM1EPqazFDmM4QWY7q6BxPCPDNKTNunj794DSD4h0H7SrqUdMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/normalize-package-data": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/normalize-package-data/-/normalize-package-data-1.0.0.tgz", + "integrity": "sha512-/EOmFBekV9tGee8gac/k+5Ox3twkypNqh5TfxA9vTkmcJkjm6f1xqrlstDNOrEhTvnYyVtU6Du2ZhY/IV1+9GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/hosted-git-info": "^2.0.0", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-2.0.0.tgz", + "integrity": "sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-5.0.1.tgz", + "integrity": "sha512-wacy5twbJk36R0dTcGE3qmPNNH095bFselAYNrVCzf0Byd0t3+Qzk3+3gn/rHGP10FuHBVk4swg4aczr1c2z/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^10.2.6" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/parse-path": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz", + "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", + "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/abbrev": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-5.0.0.tgz", + "integrity": "sha512-/XrFJgzQQQHpti1raDJC6m4ws6aNktmjBlhk8Fdlk7LwCEuDoieEJJY9OFHjfiFJFFRM2tK+Ky/IsfbbmlMu1w==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/agent-base": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/argue-cli": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/argue-cli/-/argue-cli-3.2.0.tgz", + "integrity": "sha512-VipTB0gXgGIFO2Rg9yEVN5wLt2AurJcZqDbgmYSwPwsykhLrQhs240/bfceev4w68lI8JshoOJIk9uW7tFzROw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bin-links": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-7.0.1.tgz", + "integrity": "sha512-lgxd7FtxW02eSuafotQOGEQf1iGfDExMz2BRaL+e1tU5xTLx+vvSVA5oHIO6B1tR91LDKcWqYGsktUHdFMtHHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^9.0.0", + "npm-normalize-package-bin": "^6.0.0", + "proc-log": "^7.0.0", + "read-cmd-shim": "^7.0.0", + "write-file-atomic": "^8.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacache": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-21.0.1.tgz", + "integrity": "sha512-pTwz/uj3Jyp6WXdJ6fWhR+7LVxVs6RyroQSn7KJwHsSxXuyGSp0pcMVcwSwTpCFq1X2YG8QBe0W+vN+cr0SwzA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^6.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^14.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cmd-shim": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-9.0.2.tgz", + "integrity": "sha512-xVHoI+wNrM4tDB9iC1idf/8D0tYnVimlBp/5zHW+x1sGjjRD69NvR9th3Z1JAYGN/BTW4he6aZFYV6kzy+k+jw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/columnify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/common-ancestor-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", + "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/content-type": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-3.1.1.tgz", + "integrity": "sha512-GW4qUsfFo59d0HbUibDlWv5wPz+vAAcaTWbKIuKCf0JkC7wWkSyf8f13IpXn5JkeMlB2P8iTSSIjwXljorg2vA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/conventional-changelog": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-8.1.3.tgz", + "integrity": "sha512-fOMwLCxm46znJKPB08jLxl1FD8SOZOQHktlzCVhvhhVUfq0KgQSryoYXsRRHs1aRlZPR1/QK5wztnY8sBNC2AA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@conventional-changelog/git-client": "^3.1.2", + "@simple-libs/hosted-git-info": "^2.0.0", + "@simple-libs/normalize-package-data": "^1.0.0", + "argue-cli": "^3.1.0", + "conventional-changelog-preset-loader": "^6.0.1", + "conventional-changelog-writer": "^9.2.1", + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.1.2", + "fd-package-json": "^2.0.0" + }, + "bin": { + "conventional-changelog": "dist/cli/index.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-9.4.0.tgz", + "integrity": "sha512-HdxRxuS8bBXVIuo4V82gvSwAXT0vYQUizrjs/izmPg5JdDstr8v8I5hduGL3iQbG+o310dUDxC4+LetuS5hu9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@conventional-changelog/template": "^1.4.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-6.0.1.tgz", + "integrity": "sha512-GZ8E3RQzXQb3JFy0pKl8oeSf7ENIhvAMvJr+PlWkavZOesLHHdhkfNJ4SvW35eo1Fu2+EyVxWQ1tVvtzAG2iWg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-9.3.0.tgz", + "integrity": "sha512-lxiECDlvy880e7JIYAtAhxg0wD/CGCVbZCdeua5aOlQVFTEd39zAeOzwK22i/FO4xnEOURK1gbUTETNEYW7zxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@conventional-changelog/template": "^1.4.0", + "@simple-libs/stream-utils": "^2.0.0", + "argue-cli": "^3.1.0", + "conventional-commits-filter": "^6.0.1", + "verkit": "^0.5.0" + }, + "bin": { + "conventional-changelog-writer": "dist/cli/index.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-changelog/node_modules/@conventional-changelog/git-client": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.2.0.tgz", + "integrity": "sha512-sD/E0vzpkoDz/dqM1Hhv0ihC4KBw6RXjefeO8SG1XrX+wGkMxe1pKeedkKDPCtr2JjuhbuS9aJNgOvnT8hbeBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/child-process-utils": "^2.0.0", + "@simple-libs/stream-utils": "^2.0.0", + "verkit": "^0.5.0" + }, + "engines": { + "node": ">=22" + }, + "peerDependencies": { + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.1.3" + }, + "peerDependenciesMeta": { + "conventional-commits-filter": { + "optional": true + }, + "conventional-commits-parser": { + "optional": true + } + } + }, + "node_modules/conventional-changelog/node_modules/conventional-commits-parser": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.3.tgz", + "integrity": "sha512-Q9oWm1o9uy/oEsZQIraoFMZ4RuPD+79KgwWj6mJVP356tazolCB0piRLZ5Kz9te9p027uSEcUW+Gu44Eh+X79g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^2.0.0", + "argue-cli": "^3.1.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-commits-filter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-6.0.1.tgz", + "integrity": "sha512-cs+LadpH7Kpw0M3k8wurk+sOVVDAENA0iK4OBOrkL94j5lEVYRJ4j3zd2bhY9qgzyrPqthdcYT3axzRN7AliMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-commits-parser": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.2.tgz", + "integrity": "sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^2.0.0", + "argue-cli": "^3.1.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-12.1.0.tgz", + "integrity": "sha512-HTNG3kEZXOOfKwrEx54ljURU9bG4nVPQzXMyCSeUcA/PE8EpNpQNujSrbXNBI8QZyN35zM+pVw+FuQk4KqHSHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@conventional-changelog/git-client": "^3.1.0", + "argue-cli": "^3.1.0", + "conventional-changelog-preset-loader": "^6.0.1", + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.1.0" + }, + "bin": { + "conventional-recommended-bump": "dist/cli/index.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-recommended-bump/node_modules/@conventional-changelog/git-client": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.2.0.tgz", + "integrity": "sha512-sD/E0vzpkoDz/dqM1Hhv0ihC4KBw6RXjefeO8SG1XrX+wGkMxe1pKeedkKDPCtr2JjuhbuS9aJNgOvnT8hbeBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/child-process-utils": "^2.0.0", + "@simple-libs/stream-utils": "^2.0.0", + "verkit": "^0.5.0" + }, + "engines": { + "node": ">=22" + }, + "peerDependencies": { + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.1.3" + }, + "peerDependenciesMeta": { + "conventional-commits-filter": { + "optional": true + }, + "conventional-commits-parser": { + "optional": true + } + } + }, + "node_modules/conventional-recommended-bump/node_modules/conventional-commits-parser": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.3.tgz", + "integrity": "sha512-Q9oWm1o9uy/oEsZQIraoFMZ4RuPD+79KgwWj6mJVP356tazolCB0piRLZ5Kz9te9p027uSEcUW+Gu44Eh+X79g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^2.0.0", + "argue-cli": "^3.1.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", + "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ejs": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.1.tgz", + "integrity": "sha512-COqBPFMxuPTPspXl2DkVYaDS3HtrD1GpzOGkNTJ1IYkifq/r9h8SVEFrjA3D9/VJGOEoMQcrlhpntcSUrM8k6A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.12.18" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-10.0.1.tgz", + "integrity": "sha512-ge98qjkRK4IB7tL7Ju/6qmm5LHoH1eEMt5FNZrz3f4UIYhF28lggX20z3FaX1sgc67msLEn0N0BscOs29iuwyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "figures": "^6.1.0", + "get-stream": "^9.0.1", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.3.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "which-command": "^0.1.0", + "yoctocolors": "^2.1.2" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/fd-package-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-2.0.0.tgz", + "integrity": "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "walk-up-path": "^4.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz", + "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-up": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz", + "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-ssh": "^1.4.0", + "parse-url": "^9.2.0" + } + }, + "node_modules/git-url-parse": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz", + "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==", + "dev": true, + "license": "MIT", + "dependencies": { + "git-up": "^8.1.0" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.10.tgz", + "integrity": "sha512-P5VJMVM7qgBn6vjXMw8WG9uVI+ncf2pi72j4de4yz5ZULLj2RGqLYaKOYGsgyrViQ0tePOVlN1tDCCXXtFqXKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.8", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hosted-git-info": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-10.1.1.tgz", + "integrity": "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz", + "integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/https-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", + "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-9.0.0.tgz", + "integrity": "sha512-tCBEZV2z2FNpIDl2vrhiWzIHzs4qOAuIDEO85eS02vZ3L1U3P56qpPL8GuGGAijDktAEaq2swMkO/Fmbo7YmfQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-7.0.0.tgz", + "integrity": "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/init-package-json": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-9.0.0.tgz", + "integrity": "sha512-aYDqz4jgX1plB2GDCFYStlOh67QXVpAIeNgDq8rRGVDYMvLE39yYlf8+CjYY2chVOVfqLsSIycFYznHWozZ9CA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^8.0.0", + "npm-package-arg": "^14.0.0", + "promzard": "^4.0.0", + "read": "^6.0.0", + "semver": "^7.7.2", + "validate-npm-package-name": "^8.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/inquirer": { + "version": "14.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-14.2.2.tgz", + "integrity": "sha512-WGerZIIb7mTtaFFskkD/P0europ8xBWf1OXACMiugzKPSmVzoqhcPSuSUzbzMch/t3rf1ncBT3v/0WU73cLqJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/core": "^12.0.3", + "@inquirer/prompts": "^8.7.2", + "@inquirer/type": "4.1.1", + "mute-stream": "^3.0.0", + "run-async": "^4.0.6" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/ip-address": { + "version": "10.7.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.5.tgz", + "integrity": "sha512-t2v0rkILYv9WXmSL7TpAaU3HXgaFYOPUcH3QHgwQ++gpJuH3bqyMy4Fvt/DJCTKwzH3Cf+bAp5W/mFL39KPLzA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ssh": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", + "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.1" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.2.tgz", + "integrity": "sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.mjs" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-6.0.0.tgz", + "integrity": "sha512-2/8adwnK1/+Fdjyts4r6wSpfANWw8zdNhU9U/Llk59c6O+DjSisPWPykwoL8gZmocP9Dy64S7oie2g+Mia123A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/json-stringify-nice": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", + "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/json-with-bigint": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.12.tgz", + "integrity": "sha512-uwbF/wSSuOgC7qqlq27Xp5B6a2MHVug3t0idZdTqu0JnlFvgJuH7ju+KAk/J06C7GfhoYy2gnb9wz2INqcne7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/just-diff": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", + "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", + "dev": true, + "license": "MIT" + }, + "node_modules/just-diff-apply": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", + "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lerna": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-10.1.1.tgz", + "integrity": "sha512-WDGaMGDGj5jV0n6Yx2zuBDWH0ym6toUE6w+maaPLqeMd3ncDRN+NJMcVWImVdUKCIHRk2Xk+X7QQkFXdHKsscA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@npmcli/arborist": "10.0.3", + "@npmcli/package-json": "8.0.0", + "@npmcli/run-script": "11.0.0", + "@nx/devkit": ">=23.1.0 < 24.0.0", + "@octokit/plugin-enterprise-rest": "6.0.1", + "@octokit/rest": "22.0.1", + "ci-info": "4.4.0", + "columnify": "1.6.0", + "conventional-changelog": "8.1.3", + "conventional-changelog-angular": "9.4.0", + "conventional-commits-filter": "6.0.1", + "conventional-commits-parser": "7.1.2", + "conventional-recommended-bump": "12.1.0", + "cosmiconfig": "9.0.2", + "dedent": "1.7.2", + "envinfo": "7.21.0", + "execa": "10.0.1", + "fs-extra": "^11.2.0", + "git-url-parse": "16.1.0", + "handlebars": "4.7.10", + "import-local": "3.2.0", + "ini": "^7.0.0", + "init-package-json": "9.0.0", + "inquirer": "14.2.2", + "js-yaml": "5.4.2", + "libnpmaccess": "11.0.0", + "libnpmpublish": "12.0.1", + "load-json-file": "7.0.1", + "make-fetch-happen": "16.0.1", + "minimatch": "10.2.6", + "npm-package-arg": "14.0.0", + "npm-packlist": "11.3.0", + "npm-registry-fetch": "20.0.1", + "nx": ">=23.1.0 < 24.0.0", + "p-map": "7.0.8", + "p-queue": "9.3.3", + "pacote": "22.0.0", + "semver": "7.8.5", + "signal-exit": "4.1.0", + "ssri": "14.0.0", + "string-width": "^8.0.0", + "tar": "7.5.22", + "tinyglobby": "0.2.17", + "validate-npm-package-name": "8.0.0", + "write-file-atomic": "8.0.0", + "yargs": "18.2.0" + }, + "bin": { + "lerna": "dist/cli.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || ^26.0.0" + } + }, + "node_modules/libnpmaccess": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-11.0.0.tgz", + "integrity": "sha512-qku5OaTtCv7f4xq5lmZMh4H6pd9WRalww3WF4PEk/aFo1Bpi7/IRCzy28EQBvyrprhzZGifbpM378U4waB9/0Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^14.0.0", + "npm-registry-fetch": "^20.0.1" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/libnpmpublish": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-12.0.1.tgz", + "integrity": "sha512-gG32Hgikbb8mx+c+b2MKseuQcwKbiIl7wM4a5+scxuRtu/Q7L/fbywMyLD4naUfL0yexdKWzfi6kglMz6BGOWQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^8.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^14.0.0", + "npm-registry-fetch": "^20.0.1", + "proc-log": "^7.0.0", + "semver": "^7.3.7", + "sigstore": "^5.0.0", + "ssri": "^14.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/load-json-file": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", + "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-fetch-happen": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-16.0.1.tgz", + "integrity": "sha512-uUv1yxHzaKVVEPfcFeGSNov/Cehjv08ovlY8ImTljgL7Q+SiA0dAYLQ6SYVa2kkKqNj4Y3aZEI7xv2teadie0A==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/agent": "^5.0.0", + "@npmcli/redact": "^5.0.0", + "cacache": "^21.0.0", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^6.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^7.0.0", + "ssri": "^14.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-6.0.0.tgz", + "integrity": "sha512-AWI8bKapGmgx/J0E6IGYSKj8TiHebZkmKWSs8raPSw8KXwgEAJ+Bw3+LSdXHR6T/RHKAWCOYk2MiLrYluaUU6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^2.0.0", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.7.2" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-sized": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz", + "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/negotiator/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-gyp": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-13.1.0.tgz", + "integrity": "sha512-FpNzOLFACKG0oRBYbZ5WOeWD1EqRTIWX90MaRIWTO18lVYPx8fqIjrdS3pihjnCkSmgop6zVGkSqg1vXZLksuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "nopt": "^10.0.0", + "proc-log": "^7.0.0", + "semver": "^7.3.5", + "tar": "^7.5.7", + "tinyglobby": "^0.2.12", + "undici": "^8.4.1", + "which": "^7.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/nopt": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-10.0.1.tgz", + "integrity": "sha512-df3sBr/6ax9hSGuC3CspvLlbnX8cP5L5nZwXF8cGN8l0zSWR6BvzmQ6jPUKjvo6+/xdpkNvEcucBNUdBeeV13g==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^5.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-bundled": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-6.0.0.tgz", + "integrity": "sha512-EqdodKEW6pYM+dPxA66TZQfMEqVDiuzjDM9edSjuPI1mXUbUJwVxkgqMZSJvs8RTXz2CGq8HUol/AffTZX5g8w==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^6.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-9.0.0.tgz", + "integrity": "sha512-t05Izcgi7p15cpldqoiXYpjzlkTTvBw33sgjmL/JjcvtV0ydbm2O4iEXO8A6smqComu5FAQhUas86HTMQ6Z1Uw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-6.0.0.tgz", + "integrity": "sha512-tdt4aFn9QamlhdN3HV2D2ccpBwO5/fyjjbXUxYA6uBjyekMZcZvDq0aSj9t5Jo+tih6AYFnt/cuIRn9013e0Uw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-14.0.0.tgz", + "integrity": "sha512-69XQh3k+dtGa1p+7RaR57IuG3rCko96xr/nUfN4yDYBXbTYICiWcOpsFKLN2GtGE9cyIljE+f1exnaYt9MvM+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^10.1.0", + "proc-log": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^8.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-11.3.0.tgz", + "integrity": "sha512-cS1yVkyriZgQAbiK8PtwhZHEtsFOsKHsCg5Ww2ONckAvXIspgqd6o4WirOzvkupU24iMRZ4xtO4kb2iK2rbnag==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^13.0.6", + "ignore-walk": "^9.0.0", + "proc-log": "^7.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-12.0.0.tgz", + "integrity": "sha512-8Fs3YLrnNOhrCdPNZy18MzNgVC58LTDAFzq1FdZO/p3BHeCC/coz+t4F5Pxabys8HJpyTUorMea26GkXsb4J/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^9.0.0", + "npm-normalize-package-bin": "^6.0.0", + "npm-package-arg": "^14.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-20.0.1.tgz", + "integrity": "sha512-vzc1svxw/kw1IRjFsLi6gaxe1Olqm88V0tIfu2u5raL0b1gChe6ZEXNkyUlKxUC7s/egt5NxZHkbY18tMKKLfQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^5.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^16.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^6.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^14.0.0", + "proc-log": "^7.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nx": { + "version": "23.3.1", + "resolved": "https://registry.npmjs.org/nx/-/nx-23.3.1.tgz", + "integrity": "sha512-dufPxsiUazuSejFYdtLAotKXeda9ufz3B9gVtsrvgxkjWjpAM23rOpIJoqZj3FFauig64lYsaMX+nX2hh+YhYQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@clack/core": "1.4.3", + "@clack/prompts": "1.7.0", + "@emnapi/core": "1.4.5", + "@emnapi/runtime": "1.4.5", + "@emnapi/wasi-threads": "1.0.4", + "@jest/diff-sequences": "30.0.1", + "@napi-rs/wasm-runtime": "0.2.4", + "@tybys/wasm-util": "0.9.0", + "@yarnpkg/lockfile": "1.1.0", + "@zkochan/js-yaml": "0.0.7", + "ansi-regex": "5.0.1", + "ansi-styles": "4.3.0", + "argparse": "2.0.1", + "balanced-match": "4.0.3", + "base64-js": "1.5.1", + "bl": "4.1.0", + "brace-expansion": "5.0.12", + "buffer": "5.7.1", + "bundle-name": "4.1.0", + "chalk": "4.1.2", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "8.0.1", + "clone": "1.0.4", + "color-convert": "2.0.1", + "color-name": "1.1.4", + "default-browser": "5.2.1", + "default-browser-id": "5.0.0", + "defaults": "1.0.4", + "define-lazy-prop": "3.0.0", + "dotenv": "16.4.7", + "dotenv-expand": "12.0.3", + "ejs": "5.0.1", + "emoji-regex": "8.0.0", + "end-of-stream": "1.4.5", + "escalade": "3.2.0", + "escape-string-regexp": "1.0.5", + "fast-string-truncated-width": "3.0.3", + "fast-string-width": "3.0.2", + "fast-wrap-ansi": "0.2.0", + "figures": "3.2.0", + "fs-constants": "1.0.0", + "get-caller-file": "2.0.5", + "has-flag": "4.0.0", + "ieee754": "1.2.1", + "ignore": "7.0.6", + "inherits": "2.0.4", + "is-docker": "3.0.0", + "is-fullwidth-code-point": "3.0.0", + "is-inside-container": "1.0.0", + "is-interactive": "1.0.0", + "is-unicode-supported": "0.1.0", + "is-wsl": "3.1.0", + "isexe": "2.0.0", + "json5": "2.2.3", + "jsonc-parser": "3.3.1", + "lines-and-columns": "2.0.3", + "log-symbols": "4.1.0", + "mimic-fn": "2.1.0", + "minimatch": "10.2.5", + "minimist": "1.2.8", + "npm-run-path": "4.0.1", + "once": "1.4.0", + "onetime": "5.1.2", + "open": "10.1.0", + "ora": "5.4.1", + "path-key": "3.1.1", + "picocolors": "1.1.1", + "readable-stream": "3.6.2", + "require-directory": "2.1.1", + "resolve.exports": "2.0.3", + "restore-cursor": "3.1.0", + "run-applescript": "7.0.0", + "safe-buffer": "5.2.1", + "semver": "7.8.5", + "signal-exit": "3.0.7", + "sisteransi": "1.0.5", + "smol-toml": "1.9.0", + "string_decoder": "1.3.0", + "string-width": "4.2.3", + "strip-ansi": "6.0.1", + "strip-bom": "3.0.0", + "supports-color": "7.2.0", + "tar-stream": "2.2.0", + "tmp": "0.2.7", + "tsconfig-paths": "4.2.0", + "tslib": "2.8.1", + "undici": "7.29.0", + "util-deprecate": "1.0.2", + "wcwidth": "1.0.1", + "which": "3.0.1", + "wrap-ansi": "7.0.0", + "wrappy": "1.0.2", + "y18n": "5.0.8", + "yaml": "2.9.0", + "yargs": "17.7.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "dist/bin/nx.js", + "nx-cloud": "dist/bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "23.3.1", + "@nx/nx-darwin-x64": "23.3.1", + "@nx/nx-freebsd-x64": "23.3.1", + "@nx/nx-linux-arm-gnueabihf": "23.3.1", + "@nx/nx-linux-arm64-gnu": "23.3.1", + "@nx/nx-linux-arm64-musl": "23.3.1", + "@nx/nx-linux-x64-gnu": "23.3.1", + "@nx/nx-linux-x64-musl": "23.3.1", + "@nx/nx-win32-arm64-msvc": "23.3.1", + "@nx/nx-win32-x64-msvc": "23.3.1" + }, + "peerDependencies": { + "@swc-node/register": "^1.11.1", + "@swc/core": "^1.15.8" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/nx/node_modules/balanced-match": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", + "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/nx/node_modules/fast-wrap-ansi": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz", + "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/nx/node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nx/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nx/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nx/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nx/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nx/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nx/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nx/node_modules/undici": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/nx/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/nx/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.8.tgz", + "integrity": "sha512-MitaVsCuCFIvOLLPIU7NnfrZvS9H9h7kwMUkDo+T2pEISaJD48IV9S8iIdXB7PsvvdxyYcsSTTrr90XKsbulNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.3.tgz", + "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz", + "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-22.0.0.tgz", + "integrity": "sha512-++VqeOZeL03uGM2MFLk96jGCSt1owBGkyFKoPr+trwNlZhCpjN2RrvwYxt8nTbs1wNMqSFYurq0TafVWkAIHig==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/git": "^8.0.0", + "@npmcli/installed-package-contents": "^5.0.0", + "@npmcli/package-json": "^8.0.0", + "@npmcli/promise-spawn": "^10.0.0", + "@npmcli/run-script": "^11.0.0", + "cacache": "^21.0.1", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^14.0.0", + "npm-packlist": "^11.2.0", + "npm-pick-manifest": "^12.0.0", + "npm-registry-fetch": "^20.0.1", + "proc-log": "^7.0.0", + "sigstore": "^5.0.0", + "ssri": "^14.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-conflict-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-6.0.0.tgz", + "integrity": "sha512-JIdsITvN0yVRpYxiip9DpCduYi75AryIDSCf6ez/Yul6PV46L0B/8SxSvLiMmWiUZKopLrD1BZgexxCfufoT9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^6.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-json/node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-path": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.0" + } + }, + "node_modules/parse-url": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz", + "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-path": "^7.0.0", + "parse-path": "^7.0.0" + }, + "engines": { + "node": ">=14.13.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.7.tgz", + "integrity": "sha512-wWBro/7hJ40ye6TPiXkUQoXKCw23xSsjriUvqd7Uls9Sso3oLiON1flc18cCdnjgCRXw4fBVqUJJeOdDTh3P3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", + "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proc-log": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-7.0.0.tgz", + "integrity": "sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/proggy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/proggy/-/proggy-4.0.0.tgz", + "integrity": "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/promise-call-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.2.tgz", + "integrity": "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/promzard": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-4.0.0.tgz", + "integrity": "sha512-zqf38XGznB+ECFHQPGt0RNQCh0YF+r5iac0EZloSQlEWDxt0vCS39PEtUShBJOZU0tcJ+USPvmnyGo+3CEFwcQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "read": "^6.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/protocols": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-agent-negotiate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", + "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "kerberos": "^2.0.0" + }, + "peerDependenciesMeta": { + "kerberos": { + "optional": true + } + } + }, + "node_modules/read": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read/-/read-6.0.0.tgz", + "integrity": "sha512-Tg/LaEke7h9SDbp0xJJj53oa4s1VPPySVnxQF9nUS9DgA25M/ZCLk7RVF1kHjytC87XbkgQKmQ/79+DQgEIqLA==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^4.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/read-cmd-shim": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-7.0.1.tgz", + "integrity": "sha512-GhAsW4iJS0xNqv8P6HocT3gb5HCKHtEBKLIN7fE2oWr27jGIEihu48lXyGGeexkbiLv1XAbwyXvgjYMfT81kZA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/read/node_modules/mute-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-4.0.0.tgz", + "integrity": "sha512-gSrprq0fJ3EiOErzjdIZrjysVVmJ4uu1QWfCDss5LypA5OXvrMje5Ym5z6V6RLyJ2eF87lasX7t6a0AnFvZblg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-async": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-5.0.0.tgz", + "integrity": "sha512-hJqJfoG/e4qFQaauQL00c6J6FrHLBGKtkFvW3JbTSIEFOhLrSjdSM/gWd/yUOfYo/gsERehTXGC1VZWX+9X4Dg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^5.0.0", + "@sigstore/core": "^4.0.0", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^5.0.0", + "@sigstore/tuf": "^5.0.0", + "@sigstore/verify": "^4.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/smol-toml": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.0.tgz", + "integrity": "sha512-hpd+HLON7HdZXqYchMM/+LaTTbdK0AU3NngIJ4KVyWbY9bfQqdL9cD+4yf6dUoU2Ap4VsU0JkQi6FxAI1B2mXQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/socks": { + "version": "2.8.10", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz", + "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-10.1.0.tgz", + "integrity": "sha512-WlMj/67cEJ6MDI1OcsnjuYKDNDoyPCCYZ249kuuXPiMDw9F8PXkVaQ7YWu3siTydfQ/4BEZcvGzu+aYvz7dDCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.24", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.24.tgz", + "integrity": "sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/ssri": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-14.0.0.tgz", + "integrity": "sha512-jQxKI0yx0ZnTKrqjKkLDV2DXkBQn3k49JVmVqDGcDwKDtGDbImD/GXsq04KD0VVzCQQ9wZJYal3RwR1GzWTSow==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz", + "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/treeverse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", + "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tuf-js": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-6.0.1.tgz", + "integrity": "sha512-o59N1PU8xk0bBV3HpJ4jjwldIeze17yXW1XTv02CEEKdC3E/tnJDU3CPWDNT4IZpkx9Srv9v1DJZ+JTdo46THg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@gar/promise-retry": "^1.0.3", + "@tufjs/models": "5.0.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "8.12.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.12.3.tgz", + "integrity": "sha512-+fdndUTwBP86cVjihTp21hZHo7d6oj1c/47XPA3lL8mM0XHs+C4EkcjmgRsFnFk2f/UONGDy9ItBItmXsLOQHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-name": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-8.0.0.tgz", + "integrity": "sha512-SCv6OOV6Xj2/3cXy3dGmADluJTNcL3o7hZAglNPTe+WYuEuvxgJzxPrSDLZhF+CwyQOubqgecjMmTJGMVLWjYQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/verkit": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz", + "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/walk-up-path": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", + "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/which": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-7.0.0.tgz", + "integrity": "sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/which-command": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/which-command/-/which-command-0.1.0.tgz", + "integrity": "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA==", + "dev": true, + "license": "MIT", + "bin": { + "which-command": "cli.js" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/which-command?sponsor=1" + } + }, + "node_modules/which/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-8.0.0.tgz", + "integrity": "sha512-dYwyZredl67GyLLIHJnRM3h2PcOmN5SkcgC7eM5DPDEOEl6dLFqVrMg3F1Ea32usj4VSVZtd2H4MtKTNOf6nPg==", + "dev": true, + "license": "ISC", + "dependencies": { + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz", + "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz", + "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/yargs/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/yargs/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/yargs/node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/yargs/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/yargs/node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yoctocolors": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/tests/release/package.json b/tests/release/package.json new file mode 100644 index 0000000..5a885d0 --- /dev/null +++ b/tests/release/package.json @@ -0,0 +1,10 @@ +{ + "name": "nodejs-release-tests", + "private": true, + "scripts": { + "test": "node --test *.test.js" + }, + "devDependencies": { + "lerna": "10.1.1" + } +} diff --git a/tests/release/project.test.js b/tests/release/project.test.js new file mode 100644 index 0000000..6f82f55 --- /dev/null +++ b/tests/release/project.test.js @@ -0,0 +1,457 @@ +const assert = require("node:assert/strict"); +const { execFileSync } = require("node:child_process"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const { test } = require("node:test"); +const { ReleaseProject } = require("../../actions/release/ReleaseProject.js"); + +Object.assign(process.env, { + CI: "true", + NX_DAEMON: "false", + NX_ISOLATE_PLUGINS: "false", + GIT_CONFIG_GLOBAL: "/dev/null", + GIT_CONFIG_NOSYSTEM: "1", + npm_config_offline: "true", + npm_config_audit: "false", + npm_config_fund: "false", +}); + +function fixture(t, versioning = "npm") { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "nodejs-release-")); + t.after(() => fs.rmSync(root, { recursive: true, force: true })); + const directory = path.join(root, "project"); + const remote = path.join(root, "remote.git"); + fs.mkdirSync(directory); + const run = (command, args, cwd = directory) => + execFileSync(command, args, { + cwd, + encoding: "utf8", + stdio: "pipe", + }).trim(); + const git = (...args) => run("git", args); + const write = (file, content) => { + fs.mkdirSync(path.dirname(path.join(directory, file)), { recursive: true }); + fs.writeFileSync(path.join(directory, file), content); + }; + const json = (file, value) => + write(file, `${JSON.stringify(value, null, 2)}\n`); + const commit = (message) => { + git("add", "."); + git("commit", "-m", message); + return git("rev-parse", "HEAD"); + }; + git("init", "--bare", remote); + git("init", "-b", "main"); + git("config", "user.name", "Release test"); + git("config", "user.email", "test@example.invalid"); + git("remote", "add", "origin", remote); + write(".gitignore", "node_modules/\n.nx/\ndist/\n*.tgz\n"); + if (versioning === "lerna") { + json("package.json", { + name: "workspaces-test", + private: true, + workspaces: ["packages/*"], + }); + json("lerna.json", { version: "1.0.0", npmClient: "npm" }); + json("packages/core/package.json", { + name: "@example/core", + version: "1.0.0", + }); + json("packages/ui/package.json", { + name: "@example/ui", + version: "1.0.0", + dependencies: { "@example/core": "^1.0.0" }, + }); + json("packages/private/package.json", { + name: "@example/private", + version: "1.0.0", + private: true, + }); + write("packages/core/index.js", "module.exports = 1;\n"); + run("npm", ["install", "--package-lock-only", "--ignore-scripts"]); + fs.symlinkSync( + path.join(__dirname, "node_modules"), + path.join(directory, "node_modules"), + "dir", + ); + } else { + json("package.json", { + name: "@example/cli", + version: "1.0.0", + type: "module", + main: "dist/index.js", + bin: { "example-cli": "bin/example-cli" }, + files: ["dist", "bin", "CHANGELOG.md"], + scripts: { build: "node build.js" }, + }); + write( + "bin/example-cli", + "#!/usr/bin/env node\nimport { version } from '../dist/index.js';\nconsole.log(version);\n", + ); + fs.chmodSync(path.join(directory, "bin/example-cli"), 0o755); + write( + "build.js", + "import fs from 'node:fs';\nconst { version } = JSON.parse(fs.readFileSync('package.json'));\nfs.mkdirSync('dist', { recursive: true });\nfs.writeFileSync('dist/index.js', 'export const version = ' + JSON.stringify(version) + ';');\n", + ); + run("npm", ["install", "--package-lock-only", "--ignore-scripts"]); + } + commit("chore: initial"); + git("tag", "-a", "v1.0.0", "-m", "v1.0.0"); + git("push", "origin", "main", "--tags"); + const dispatches = []; + const github = { + rest: { + actions: { + createWorkflowDispatch: async (args) => dispatches.push(args), + }, + }, + }; + const plan = { + tag: "v1.1.0", + hasChanges: true, + body: "### Features\n\n* Add a command.\n", + }; + const context = { + repo: { owner: "example", repo: "project" }, + payload: { repository: { default_branch: "main" } }, + ref: "refs/heads/main", + sha: git("rev-parse", "HEAD"), + }; + const project = new ReleaseProject({ + workspace: directory, + versioning, + github, + context, + }); + const prepare = () => + project.prepare({ + workflowRef: + "example/project/.github/workflows/release.yml@refs/heads/main", + findRelease: async () => undefined, + plan, + }); + return { + root, + directory, + remote, + run, + git, + write, + json, + commit, + plan, + dispatches, + github, + context, + project, + prepare, + }; +} + +test("an unchanged upstream plan skips source preparation and publication", async (t) => { + const f = fixture(t); + f.write("README.md", "Documentation only."); + f.context.sha = f.commit("docs: describe setup"); + f.plan.hasChanges = false; + assert.equal((await f.prepare()).status, "no-changes"); + assert.equal(f.project.version(), "1.0.0"); + assert.equal(f.dispatches.length, 0); +}); + +test("single package applies the HoverKraft plan and packs an executable CLI", async (t) => { + const f = fixture(t); + f.write("CHANGELOG.md", "# Changelog\n\n## v1.0.0\n\nExisting history.\n"); + f.context.sha = f.commit("feat: add output"); + f.git("push", "origin", "main"); + assert.deepEqual(await f.prepare(), { tag: "v1.1.0", status: "dispatched" }); + const releaseSha = f.project.tagCommit("v1.1.0"); + assert.notEqual(releaseSha, f.context.sha); + assert.equal( + f.run("git", ["rev-parse", "refs/heads/main"], f.remote), + releaseSha, + ); + assert.equal( + f.project.readJson("package-lock.json").packages[""].version, + "1.1.0", + ); + const changelog = fs.readFileSync( + path.join(f.directory, "CHANGELOG.md"), + "utf8", + ); + assert.ok(changelog.includes(f.plan.body.trim())); + assert.ok(changelog.includes("Existing history.")); + assert.deepEqual(f.dispatches, [ + { + owner: "example", + repo: "project", + workflow_id: ".github/workflows/release.yml", + ref: "v1.1.0", + }, + ]); + f.context.ref = "refs/tags/v1.1.0"; + f.context.sha = releaseSha; + const ready = await f.prepare(); + assert.equal(ready.status, "ready"); + assert.deepEqual(ready.packages, [ + { + name: "@example/cli", + version: "1.1.0", + directory: ".", + slug: "example-cli", + }, + ]); + f.run("npm", ["run", "build"]); + const [packed] = JSON.parse( + f.run("npm", ["pack", "--json", "--pack-destination", f.root]), + ); + const files = packed.files.map((file) => file.path); + for (const file of [ + "bin/example-cli", + "dist/index.js", + "CHANGELOG.md", + "package.json", + ]) + assert.ok(files.includes(file)); + const installed = path.join(f.root, "installed"); + fs.mkdirSync(installed); + f.run( + "npm", + ["install", path.join(f.root, packed.filename), "--ignore-scripts"], + installed, + ); + assert.equal( + f.run("node", [ + path.join(installed, "node_modules/@example/cli/bin/example-cli"), + ]), + "1.1.0", + ); +}); + +for (const mode of ["npm", "lerna"]) { + test(`${mode} preserves an existing tag when the planned version collides`, async (t) => { + const f = fixture(t, mode); + f.git("tag", "v1.1.0"); + f.git("push", "origin", "refs/tags/v1.1.0"); + const original = f.project.tagCommit("v1.1.0"); + f.write( + mode === "lerna" ? "packages/core/index.js" : "feature.txt", + "new feature", + ); + f.context.sha = f.commit("feat: add output"); + f.git("push", "origin", "main"); + await assert.rejects(f.prepare(), /Existing tag/); + assert.equal(f.project.tagCommit("v1.1.0"), original); + assert.equal( + f.run("git", ["rev-parse", "refs/heads/main"], f.remote), + f.context.sha, + ); + assert.equal(f.dispatches.length, 0); + }); + + test(`${mode} applies a planned version without recomputing its increment`, async (t) => { + const f = fixture(t, mode); + f.write( + mode === "lerna" ? "packages/core/index.js" : "feature.txt", + "fixed output", + ); + f.context.sha = f.commit("fix: correct output"); + f.git("push", "origin", "main"); + f.plan.tag = "3.2.1"; + assert.equal((await f.prepare()).tag, "3.2.1"); + assert.equal(f.project.version(), "3.2.1"); + assert.equal(f.project.tagCommit("3.2.1"), f.git("rev-parse", "HEAD")); + }); + + test(`${mode} rejects invalid, older or missing plans before changing source`, async (t) => { + const f = fixture(t, mode); + f.write("feature.txt", "new feature"); + f.context.sha = f.commit("feat: add output"); + for (const tag of ["v0.9.0", "v1.0.0", "v1.0.1-rc.1", "latest"]) { + f.plan.tag = tag; + await assert.rejects(f.prepare(), /newer|stable version tag/); + assert.equal(f.git("rev-parse", "HEAD"), f.context.sha); + } + f.plan.tag = "v1.1.0"; + f.plan.body = ""; + await assert.rejects(f.prepare(), /release notes/); + await assert.rejects(f.project.prepare({}), /release plan/); + assert.equal(f.dispatches.length, 0); + }); +} + +for (const [message, version] of [ + ["fix: correct output", "1.0.1"], + ["feat: add output", "1.1.0"], + ["feat: change output\n\nBREAKING CHANGE: output is now structured", "2.0.0"], +]) { + test(`Lerna applies planned ${version}, updates dependent packages and resumes the tag`, async (t) => { + const f = fixture(t, "lerna"); + f.write("packages/core/index.js", "module.exports = 2;\n"); + f.context.sha = f.commit(message); + f.plan.tag = `v${version}`; + f.git("push", "origin", "main"); + assert.deepEqual(await f.prepare(), { + tag: `v${version}`, + status: "dispatched", + }); + assert.equal(f.project.readJson("lerna.json").version, version); + assert.equal( + f.project.readJson("packages/ui/package.json").dependencies[ + "@example/core" + ], + `^${version}`, + ); + assert.equal( + f.project.readJson("package-lock.json").packages["packages/core"].version, + version, + ); + assert.match( + fs.readFileSync( + path.join(f.directory, "packages/core/CHANGELOG.md"), + "utf8", + ), + new RegExp(version.replaceAll(".", "\\.")), + ); + f.context.sha = f.git("rev-parse", "HEAD"); + f.context.ref = `refs/tags/v${version}`; + const ready = await f.prepare(); + assert.equal(ready.status, "ready"); + assert.deepEqual(ready.packages.map((item) => item.name).sort(), [ + "@example/core", + "@example/ui", + ]); + assert.equal(f.git("rev-parse", "HEAD"), f.context.sha); + }); +} + +test("Lerna skips a commit that changes no packages", async (t) => { + const f = fixture(t, "lerna"); + f.write("README.md", "Documentation only."); + f.context.sha = f.commit("docs: describe setup"); + f.git("push", "origin", "main"); + assert.equal((await f.prepare()).status, "no-changes"); + assert.equal(f.dispatches.length, 0); +}); + +for (const mode of ["npm", "lerna"]) { + test(`${mode} rejects both commit and tag when the default branch advances`, async (t) => { + const f = fixture(t, mode); + f.write("packages/core/index.js", "module.exports = 2;\n"); + f.context.sha = f.commit("feat: add output"); + f.git("push", "origin", "main"); + f.write("later.txt", "concurrent main commit"); + const advanced = f.commit("docs: update main"); + f.git("push", "origin", "main"); + await assert.rejects(f.prepare()); + assert.equal( + f.run("git", ["rev-parse", "refs/heads/main"], f.remote), + advanced, + ); + assert.throws(() => + f.run("git", ["rev-parse", "refs/tags/v1.1.0"], f.remote), + ); + }); +} + +test("published releases skip dispatch and tag recovery preserves their notes", async (t) => { + const f = fixture(t, "lerna"); + const release = { draft: false, html_url: "https://example.invalid/release" }; + const result = await f.project.prepare({ + workflowRef: "", + findRelease: async () => release, + }); + assert.equal(result.status, "released"); + assert.equal(f.dispatches.length, 0); + f.context.ref = "refs/tags/v1.0.0"; + assert.equal( + (await f.project.prepare({ findRelease: async () => release })).published, + true, + ); +}); + +test("branch recovery dispatches an unfinished tagged version without planning again", async (t) => { + const f = fixture(t); + f.write("feature.txt", "feature"); + f.context.sha = f.commit("feat: add output"); + f.git("push", "origin", "main"); + await f.prepare(); + f.context.sha = f.git("rev-parse", "HEAD"); + const result = await f.project.prepare({ + workflowRef: "example/project/.github/workflows/release.yml@main", + findRelease: async () => ({ draft: true }), + }); + assert.equal(result.tag, "v1.1.0"); + assert.equal(result.status, "dispatched"); + assert.equal(f.dispatches.length, 2); +}); + +test("a nested npm project preserves the directory-scoped planned tag", async (t) => { + const f = fixture(t); + const nested = path.join(f.directory, "tools", "cli"); + fs.mkdirSync(nested, { recursive: true }); + for (const name of ["package.json", "package-lock.json", "build.js", "bin"]) { + fs.renameSync(path.join(f.directory, name), path.join(nested, name)); + } + f.context.sha = f.commit("feat: relocate CLI"); + f.git("push", "origin", "main"); + const project = new ReleaseProject({ + workspace: f.directory, + workingDirectory: "tools/cli", + github: f.github, + context: f.context, + }); + const result = await project.prepare({ + workflowRef: "example/project/.github/workflows/release.yml@main", + findRelease: async () => undefined, + plan: { ...f.plan, tag: "cli-1.1.0" }, + }); + assert.equal(result.tag, "cli-1.1.0"); + assert.equal(project.version(), "1.1.0"); + assert.equal(project.packages(result.tag)[0].directory, "."); + f.context.sha = f.git("rev-parse", "HEAD"); + assert.equal(project.currentTag(), "cli-1.1.0"); +}); + +test("ambiguous version tags require explicit tag recovery", (t) => { + const f = fixture(t); + f.git("tag", "1.0.0"); + assert.throws(() => f.project.currentTag(), /Several release tags/); + f.context.ref = "refs/tags/1.0.0"; + assert.equal(f.project.currentTag(), "1.0.0"); +}); + +test("rejects unsupported layouts, versions, refs and mismatched tags", async (t) => { + const f = fixture(t); + assert.throws( + () => new ReleaseProject({ workspace: f.directory, versioning: "unknown" }), + /versioning/, + ); + assert.throws( + () => + new ReleaseProject({ + workspace: f.directory, + workingDirectory: "..", + versioning: "npm", + }), + /inside/, + ); + f.context.ref = "refs/heads/feature"; + await assert.rejects(f.prepare(), /default branch/); + f.context.ref = "refs/tags/v9.0.0"; + await assert.rejects(f.prepare(), /committed package version/); + f.json("package.json", { name: "private", private: true, version: "1.0.0" }); + assert.throws( + () => + new ReleaseProject({ + workspace: f.directory, + versioning: "npm", + }), + /one public package/, + ); + f.json("lerna.json", { version: "independent" }); + assert.throws( + () => new ReleaseProject({ workspace: f.directory, versioning: "lerna" }), + /stable version/, + ); +});