├── .github ├── dependabot.yml └── workflows │ ├── cleanup.yml │ ├── draft-release.yml │ ├── integration.yml │ ├── publish.yml │ ├── release.yml │ └── unit.yml ├── .gitignore ├── .prettierrc.js ├── CHANGELOG.md ├── CODEOWNERS ├── README.md ├── action.yml ├── bin └── runTests.sh ├── dist └── index.js ├── eslint.config.mjs ├── example-app ├── .gcloudignore ├── app.yaml ├── index.js ├── package-lock.json └── package.json ├── package-lock.json ├── package.json ├── src ├── main.ts └── output-parser.ts ├── tests ├── main.test.ts └── output-parser.test.ts └── tsconfig.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: '/' 5 | rebase-strategy: 'disabled' 6 | schedule: 7 | interval: 'daily' 8 | commit-message: 9 | prefix: 'security: ' 10 | open-pull-requests-limit: 0 # only check security updates 11 | -------------------------------------------------------------------------------- /.github/workflows/cleanup.yml: -------------------------------------------------------------------------------- 1 | name: 'Cleanup' 2 | 3 | on: 4 | schedule: 5 | - cron: '0 */6 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: 'read' 10 | id-token: 'write' 11 | 12 | jobs: 13 | cleanup: 14 | runs-on: 'ubuntu-latest' 15 | 16 | steps: 17 | - uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4 18 | 19 | - uses: 'google-github-actions/auth@v2' # ratchet:exclude 20 | with: 21 | workload_identity_provider: '${{ vars.WIF_PROVIDER_NAME }}' 22 | service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}' 23 | 24 | - uses: 'google-github-actions/setup-gcloud@v2' # ratchet:exclude 25 | 26 | - name: Delete services 27 | run: |- 28 | gcloud config set core/project "${{ vars.PROJECT_ID }}" 29 | 30 | # List and delete all versions that were deployed 30 minutes ago or 31 | # earlier. The date math here is a little weird, but we're looking for 32 | # deployments "earlier than" 30 minutes ago, so it's less than since 33 | # time increases. 34 | (IFS=$'\n'; for NAME in $(gcloud app versions list --format="value(id)" --filter="service != "default" AND version.createTime < '-pt30m'"); do 35 | echo "Deleting ${NAME}..." 36 | gcloud app versions delete ${NAME} --quiet 37 | done) 38 | -------------------------------------------------------------------------------- /.github/workflows/draft-release.yml: -------------------------------------------------------------------------------- 1 | name: 'Draft release' 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version_strategy: 7 | description: 'Version strategy: The strategy to used to update the version based on semantic versioning (more info at https://semver.org/).' 8 | required: true 9 | default: 'patch' 10 | type: 'choice' 11 | options: 12 | - 'major' 13 | - 'minor' 14 | - 'patch' 15 | 16 | jobs: 17 | draft-release: 18 | uses: 'google-github-actions/.github/.github/workflows/draft-release.yml@v3' # ratchet:exclude 19 | with: 20 | version_strategy: '${{ github.event.inputs.version_strategy }}' 21 | secrets: 22 | ACTIONS_BOT_TOKEN: '${{ secrets.ACTIONS_BOT_TOKEN }}' 23 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | name: 'Integration' 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | - 'release/**/*' 8 | pull_request: 9 | branches: 10 | - 'main' 11 | - 'release/**/*' 12 | workflow_dispatch: 13 | 14 | concurrency: 15 | group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}' 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | integration: 20 | if: ${{ github.event_name == 'push' || github.repository == github.event.pull_request.head.repo.full_name && github.actor != 'dependabot[bot]' }} 21 | permissions: 22 | contents: 'read' 23 | id-token: 'write' 24 | runs-on: 'ubuntu-latest' 25 | 26 | steps: 27 | - uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4 28 | 29 | - uses: 'actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a' # ratchet:actions/setup-node@v4 30 | with: 31 | node-version: '20.x' 32 | 33 | - name: 'npm build' 34 | run: 'npm ci && npm run build' 35 | 36 | - uses: 'google-github-actions/auth@v2' # ratchet:exclude 37 | with: 38 | workload_identity_provider: '${{ vars.WIF_PROVIDER_NAME }}' 39 | service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}' 40 | 41 | - name: 'Update app.yaml' 42 | run: |- 43 | echo "service: ${{ github.job }}-${{ github.run_number }}" >> ${{ github.workspace }}/example-app/app.yaml 44 | 45 | - name: 'Deploy' 46 | id: 'deploy' 47 | uses: './' 48 | with: 49 | working_directory: '${{ github.workspace }}/example-app' 50 | build_env_vars: |- 51 | FOO=bar 52 | ZIP=zap 53 | env_vars: |- 54 | FOO=bar 55 | ZIP=zap 56 | 57 | - name: 'Verify deployment' 58 | run: |- 59 | curl '${{ steps.deploy.outputs.url }}' \ 60 | --silent \ 61 | --fail \ 62 | --location \ 63 | --retry 5 \ 64 | --retry-connrefused \ 65 | --retry-delay 5 \ 66 | --retry-max-time 300 67 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: 'Publish immutable action version' 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: 7 | - 'published' 8 | 9 | jobs: 10 | publish: 11 | runs-on: 'ubuntu-latest' 12 | permissions: 13 | contents: 'read' 14 | id-token: 'write' 15 | packages: 'write' 16 | 17 | steps: 18 | - name: 'Checkout' 19 | uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4 20 | 21 | - name: 'Publish' 22 | id: 'publish' 23 | uses: 'actions/publish-immutable-action@4bc8754ffc40f27910afb20287dbbbb675a4e978' # ratchet:actions/publish-immutable-action@v0.0.4 24 | with: 25 | github-token: '${{ secrets.GITHUB_TOKEN }}' 26 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 'Release' 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | - 'release/**/*' 8 | 9 | jobs: 10 | release: 11 | uses: 'google-github-actions/.github/.github/workflows/release.yml@v3' # ratchet:exclude 12 | secrets: 13 | ACTIONS_BOT_TOKEN: '${{ secrets.ACTIONS_BOT_TOKEN }}' 14 | -------------------------------------------------------------------------------- /.github/workflows/unit.yml: -------------------------------------------------------------------------------- 1 | name: 'Unit' 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | - 'release/**/*' 8 | pull_request: 9 | branches: 10 | - 'main' 11 | - 'release/**/*' 12 | workflow_dispatch: 13 | 14 | concurrency: 15 | group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}' 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | unit: 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | os: 24 | - 'ubuntu-latest' 25 | - 'windows-latest' 26 | - 'macos-latest' 27 | runs-on: '${{ matrix.os }}' 28 | 29 | steps: 30 | - uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4 31 | 32 | - uses: 'actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a' # ratchet:actions/setup-node@v4 33 | with: 34 | node-version: '20.x' 35 | 36 | - name: 'npm build' 37 | run: 'npm ci && npm run build' 38 | 39 | - name: 'npm lint' 40 | # There's no need to run the linter for each operating system, since it 41 | # will find the same thing 3x and clog up the PR review. 42 | if: ${{ matrix.os == 'ubuntu-latest' }} 43 | run: 'npm run lint' 44 | 45 | - name: 'npm test' 46 | run: 'npm run test' 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | __tests__/runner/* 3 | runner/ 4 | 5 | # Rest of the file pulled from https://github.com/github/gitignore/blob/main/Node.gitignore 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # TypeScript v1 declaration files 31 | typings/ 32 | 33 | # TypeScript cache 34 | *.tsbuildinfo 35 | 36 | # Optional npm cache directory 37 | .npm 38 | 39 | # Optional eslint cache 40 | .eslintcache 41 | 42 | # Optional REPL history 43 | .node_repl_history 44 | 45 | # Output of 'npm pack' 46 | *.tgz 47 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'always', 3 | bracketSpacing: true, 4 | endOfLine: 'auto', 5 | jsxSingleQuote: true, 6 | printWidth: 100, 7 | quoteProps: 'consistent', 8 | semi: true, 9 | singleQuote: true, 10 | tabWidth: 2, 11 | trailingComma: 'all', 12 | useTabs: false, 13 | }; 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Changelogs for each release are located on the [releases page](https://github.com/google-github-actions/deploy-appengine/releases). 4 | 5 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @google-github-actions/maintainers 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deploy-appengine 2 | 3 | This action deploys your source code to [App Engine][gae] and makes the URL 4 | available to later build steps via outputs. This allows you to parameterize your 5 | App Engine deployments. 6 | 7 | **This is not an officially supported Google product, and it is not covered by a 8 | Google Cloud support contract. To report bugs or request features in a Google 9 | Cloud product, please contact [Google Cloud 10 | support](https://cloud.google.com/support).** 11 | 12 | 13 | ## Prerequisites 14 | 15 | - This action requires Google Cloud credentials that are authorized to deploy 16 | an App Engine Application. See the [Authorization](#authorization) section 17 | below for more information. 18 | 19 | - This action runs using Node 20. If you are using self-hosted GitHub Actions 20 | runners, you must use runner version [2.285.0](https://github.com/actions/virtual-environments) 21 | or newer. 22 | 23 | ## Usage 24 | 25 | ```yaml 26 | jobs: 27 | job_id: 28 | permissions: 29 | contents: 'read' 30 | id-token: 'write' 31 | 32 | steps: 33 | - id: 'auth' 34 | uses: 'google-github-actions/auth@v2' 35 | with: 36 | workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider' 37 | service_account: 'my-service-account@my-project.iam.gserviceaccount.com' 38 | 39 | - id: 'deploy' 40 | uses: 'google-github-actions/deploy-appengine@v2' 41 | 42 | # Example of using the output 43 | - id: 'test' 44 | run: 'curl "${{ steps.deploy.outputs.version_url }}"' 45 | ``` 46 | 47 | ## Inputs 48 | 49 | - `project_id`: (Optional) ID of the Google Cloud project. If not provided, 50 | this is inherited from the environment. 51 | 52 | - `working_directory`: (Optional) The working directory to use. **Actions do 53 | not honor [default working-directory 54 | settings](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#defaultsrun).** 55 | The `deliverables` input is a relative path based on this setting. 56 | 57 | - `deliverables`: (Optional) The [yaml 58 | files](https://cloud.google.com/appengine/docs/standard/nodejs/configuration-files#optional_configuration_files) 59 | for the services or configurations you want to deploy. If not given, 60 | defaults to app.yaml in the current directory. If that is not found, 61 | attempts to automatically generate necessary configuration files (such as 62 | app.yaml) in the current directory (example, `app.yaml cron.yaml`). Note: 63 | the additional deliverables may require additional roles for your service 64 | account user. 65 | 66 | - `build_env_vars`: (Optional) List of key=value pairs to set as environment 67 | variables during tbe build process. This will overwrite any duplicate key 68 | environment variables defined in the app.yaml. 69 | 70 | ```yaml 71 | with: 72 | build_env_vars: |- 73 | FOO=bar 74 | ZIP=zap 75 | ``` 76 | 77 | Note: To include environment variables defined in another file, use the 78 | [`includes` directive][includes-directive] in your app.yaml. 79 | 80 | - `env_vars`: (Optional) List of key=value pairs to set as environment 81 | variables. This will overwrite any duplicate key environment variables 82 | defined in the app.yaml. 83 | 84 | ```yaml 85 | with: 86 | env_vars: |- 87 | FOO=bar 88 | ZIP=zap 89 | ``` 90 | 91 | Note: To include environment variables defined in another file, use the 92 | [`includes` directive][includes-directive] in your app.yaml. 93 | 94 | - `image_url`: (Optional) Deploy with a specific container image. The image 95 | url must be from one of the valid GCR hostnames (example, `gcr.io/`). 96 | 97 | - `version`: (Optional) The version of the app that will be created or 98 | replaced by this deployment. If you do not specify a version, one will be 99 | generated for you. 100 | 101 | - `promote`: (Optional) Promote the deployed version to receive all traffic. 102 | The default is `true`. 103 | 104 | - `flags`: (Optional) Space-separated list of other App Engine flags. This can 105 | be used to access features that are not exposed via this GitHub Action. 106 | 107 | ```yaml 108 | with: 109 | flags: '--ignore-file=...' 110 | ``` 111 | 112 | See the [complete list of flags](https://cloud.google.com/sdk/gcloud/reference/app/deploy#FLAGS) for more information. 113 | 114 | --- 115 | 116 | - `gcloud_version`: (Optional) Version of the gcloud CLI to use. The default value is `latest`. 117 | 118 | - `gcloud_component`: (Optional) Component of the gcloud CLI to use. Valid 119 | values are `alpha` and `beta`. The default value is to use the stable track. 120 | 121 | ### app.yaml customizations 122 | 123 | Other application configurations can be customized through the app.yaml, ie the 124 | service name. See [app.yaml Configuration File](https://cloud.google.com/appengine/docs/standard/nodejs/config/appref) 125 | for more information. 126 | 127 | ## Outputs 128 | 129 | - `name`: The fully-qualified resource name of the deployment. This will be of 130 | the format "apps//services//versions/". 131 | 132 | - `runtime`: The computed deployment runtime. 133 | 134 | - `service_account_email`: The email address of the runtime service account. 135 | 136 | - `serving_status`: The current serving status. The value is usually 137 | "SERVING", unless the deployment failed to start. 138 | 139 | - `version_id`: Unique identifier for the version, or the specified version if 140 | one was given. 141 | 142 | - `version_url`: URL of the version of the AppEngine service that was 143 | deployed. 144 | 145 | ## Authorization 146 | 147 | There are a few ways to authenticate this action. The caller must have the following [Google Cloud IAM Roles](https://cloud.google.com/appengine/docs/standard/python/roles#predefined_roles): 148 | 149 | - App Engine Admin (`roles/appengine.appAdmin`) to manage all App Engine 150 | resources and create new services and versions. 151 | 152 | - Storage Admin (`roles/storage.admin`) to upload files to Cloud Storage to 153 | store source artifacts. 154 | 155 | - Cloud Build Editor (`roles/cloudbuild.builds.editor`) to build the 156 | service. 157 | 158 | - Artifact Registry Reader (`roles/artifactregistry.reader`) to view & get artifacts for implementing CI/CD pipeline. 159 | 160 | - Service Account User (`roles/iam.serviceAccountUser`) permissions on the 161 | runtime service account to deploy the service. The default runtime service 162 | account is `PROJECT_ID@appspot.gserviceaccount.com`, but you can also 163 | customize the service account in your app.yaml file. 164 | 165 | - _(optional)_ Cloud Scheduler Admin (`roles/cloudscheduler.admin`) to 166 | schedule tasks 167 | 168 | *Note:* An owner will be needed to create the App Engine application. 169 | 170 | ### Via google-github-actions/auth 171 | 172 | Use [google-github-actions/auth](https://github.com/google-github-actions/auth) to authenticate the action. This Action supports both the recommended [Workload Identity Federation][wif] based authentication and the traditional [Service Account Key JSON][sa] based auth. 173 | 174 | ```yaml 175 | jobs: 176 | job_id: 177 | permissions: 178 | contents: 'read' 179 | id-token: 'write' 180 | 181 | steps: 182 | - id: 'auth' 183 | uses: 'google-github-actions/auth@v2' 184 | with: 185 | workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider' 186 | service_account: 'my-service-account@my-project.iam.gserviceaccount.com' 187 | 188 | - id: 'deploy' 189 | uses: 'google-github-actions/deploy-appengine@v2' 190 | ``` 191 | 192 | ### Via Application Default Credentials 193 | 194 | If you are hosting your own runners, **and** those runners are on Google Cloud, 195 | you can leverage the Application Default Credentials of the instance. This will 196 | authenticate requests as the service account attached to the instance. **This 197 | only works using a custom runner hosted on GCP.** 198 | 199 | ```yaml 200 | jobs: 201 | job_id: 202 | steps: 203 | - id: 'deploy' 204 | uses: 'google-github-actions/deploy-appengine@v2' 205 | ``` 206 | 207 | ## Advanced Configuration 208 | 209 | #### Custom Build Timeouts 210 | 211 | The default Google Cloud Build timeout to compile the application may be too 212 | short for some services. To extend the build timeout, set the 213 | `CLOUDSDK_APP_CLOUD_BUILD_TIMEOUT` environment variable to an integer 214 | representing the number of seconds for the timeout. Do not customize this value 215 | unless you are getting errors about build timeouts. This will consume more build 216 | minutes. 217 | 218 | ```yaml 219 | jobs: 220 | job_id: 221 | steps: 222 | - uses: 'google-github-actions/deploy-appengine@v2' 223 | env: 224 | CLOUDSDK_APP_CLOUD_BUILD_TIMEOUT: 1800 # 30 minutes 225 | ``` 226 | 227 | 228 | [gae]: https://cloud.google.com/appengine 229 | [sm]: https://cloud.google.com/secret-manager 230 | [sa]: https://cloud.google.com/iam/docs/creating-managing-service-accounts 231 | [wif]: https://cloud.google.com/iam/docs/workload-identity-federation 232 | [gh-runners]: https://help.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners 233 | [gh-secret]: https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets 234 | [setup-gcloud]: https://github.com/google-github-actions/setup-gcloud/ 235 | [roles]: https://cloud.google.com/iam/docs/granting-roles-to-service-accounts#granting_access_to_a_service_account_for_a_resource 236 | [create-key]: https://cloud.google.com/iam/docs/creating-managing-service-account-keys 237 | [app-engine-admin-api]: https://console.cloud.google.com/apis/api/appengine.googleapis.com/overview 238 | [app-engine-nodejs-docs]: https://cloud.google.com/appengine/docs/standard/nodejs/console#console 239 | [includes-directive]: https://cloud.google.com/appengine/docs/legacy/standard/python/config/appref#includes 240 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Deploy to App Engine' 2 | author: 'Google LLC' 3 | description: |- 4 | Deploy and promote a new service to Google App Engine. 5 | 6 | inputs: 7 | project_id: 8 | description: |- 9 | The Google Cloud Project ID. If unspecified, it is inherited from the 10 | environment. 11 | required: true 12 | 13 | working_directory: 14 | description: |- 15 | The path to set the working directory. The deliverables will be referenced 16 | from this path. 17 | required: false 18 | 19 | deliverables: 20 | description: |- 21 | The yaml files for the services or configurations you want to deploy. 22 | If not given, defaults to app.yaml in the current directory. If that is 23 | not found, attempts to automatically generate necessary configuration 24 | files (such as app.yaml) in the current directory. 25 | required: false 26 | 27 | build_env_vars: 28 | description: |- 29 | List of key=value pairs to set as environment variables during tbe build 30 | process. This will overwrite any duplicate key environment variables 31 | defined in the app.yaml. 32 | required: false 33 | 34 | env_vars: 35 | description: |- 36 | List of key=value pairs to set as environment variables. This will 37 | overwrite any duplicate key environment variables defined in the app.yaml. 38 | required: false 39 | 40 | image_url: 41 | description: |- 42 | Deploy with a specific container image. The image URL must be from one of 43 | the valid GCR host names. 44 | required: false 45 | 46 | version: 47 | description: |- 48 | The version of the app that will be created or replaced by this 49 | deployment. If you do not specify a version, one will be generated for 50 | you. 51 | required: false 52 | 53 | promote: 54 | description: |- 55 | Promote the deployed version to receive all traffic. 56 | required: false 57 | default: "true" 58 | 59 | flags: 60 | description: |- 61 | Space separated list of other App Engine flags, examples can be found: 62 | https://cloud.google.com/sdk/gcloud/reference/app/deploy#FLAGS. Ex 63 | --service-account=my-account@project.iam.gserviceaccount.com --no-cache 64 | required: false 65 | 66 | gcloud_version: 67 | description: |- 68 | Version of the Cloud SDK to install. If unspecified or set to "latest", 69 | the latest available gcloud SDK version for the target platform will be 70 | installed. Example: "290.0.1". 71 | required: false 72 | 73 | gcloud_component: 74 | description: |- 75 | Version of the Cloud SDK components to install and use. If unspecified, 76 | the latest or released version will be used. This is the equivalent of 77 | running 'gcloud alpha COMMAND' or 'gcloud beta COMMAND'. Valid values are 78 | `alpha` or `beta`. The default value is to use the stable track. 79 | required: false 80 | 81 | outputs: 82 | name: 83 | description: |- 84 | The fully-qualified resource name of the deployment. This will be of the 85 | format "apps//services//versions/". 86 | 87 | runtime: 88 | description: |- 89 | The computed deployment runtime. 90 | 91 | service_account_email: 92 | description: |- 93 | The email address of the runtime service account. 94 | 95 | serving_status: 96 | description: |- 97 | The current serving status. The value is usually "SERVING", unless the 98 | deployment failed to start. 99 | 100 | version_id: 101 | description: |- 102 | Unique identifier for the version, or the specified version if one was 103 | given. 104 | 105 | version_url: 106 | description: |- 107 | URL of the version of the AppEngine service that was deployed. 108 | 109 | url: 110 | description: |- 111 | DEPRECATED: Use "version_url" instead. URL of the version of the AppEngine 112 | service that was deployed. 113 | 114 | branding: 115 | icon: 'code' 116 | color: 'blue' 117 | 118 | runs: 119 | using: 'node20' 120 | main: 'dist/index.js' 121 | -------------------------------------------------------------------------------- /bin/runTests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eEuo pipefail 3 | 4 | # 5 | # As of Node 20, the --test parameter does not support globbing, and it does not 6 | # support variable Windows paths. We also cannot invoke the test runner 7 | # directly, because while it has an API, there's no way to force it to transpile 8 | # the Typescript into JavaScript before passing it to the runner. 9 | # 10 | # So we're left with this solution, which shells out to Node to list all files 11 | # that end in *.test.ts (excluding node_modules/), and then execs out to that 12 | # process. We have to exec so the stderr/stdout and exit code is appropriately 13 | # fed to the caller. 14 | # 15 | 16 | FILES="$(node -e "process.stdout.write(require('node:fs').readdirSync('./', { recursive: true }).filter((e) => {return e.endsWith('.test.ts') && !e.startsWith('node_modules');}).sort().join(' '));")" 17 | 18 | set -x 19 | exec node --require ts-node/register --test-reporter spec --test ${FILES} 20 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import ts from 'typescript-eslint'; 3 | import tsParser from '@typescript-eslint/parser'; 4 | 5 | import prettierRecommended from 'eslint-plugin-prettier/recommended'; 6 | 7 | export default ts.config( 8 | js.configs.recommended, 9 | ts.configs.eslintRecommended, 10 | { 11 | files: ['**/*.ts', '**/*.tsx'], 12 | languageOptions: { 13 | parser: tsParser, 14 | }, 15 | }, 16 | { ignores: ['dist/', '**/*.js'] }, 17 | prettierRecommended, 18 | ); 19 | -------------------------------------------------------------------------------- /example-app/.gcloudignore: -------------------------------------------------------------------------------- 1 | .github 2 | node_modules 3 | dist 4 | README.md 5 | -------------------------------------------------------------------------------- /example-app/app.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google, LLC. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | runtime: nodejs20 16 | -------------------------------------------------------------------------------- /example-app/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google, LLC. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | const express = require('express'); 16 | const app = express(); 17 | 18 | app.get('/', (req, res) => { 19 | console.log('Hello world received a request.'); 20 | 21 | const target = process.env.TARGET || 'World'; 22 | res.send(`Hello ${target}!`); 23 | }); 24 | 25 | const port = process.env.PORT || 8080; 26 | app.listen(port, () => { 27 | console.log('Hello world listening on port', port); 28 | }); 29 | -------------------------------------------------------------------------------- /example-app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helloworld", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.8", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 10 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 11 | "requires": { 12 | "mime-types": "~2.1.34", 13 | "negotiator": "0.6.3" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 20 | }, 21 | "body-parser": { 22 | "version": "1.20.3", 23 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", 24 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", 25 | "requires": { 26 | "bytes": "3.1.2", 27 | "content-type": "~1.0.5", 28 | "debug": "2.6.9", 29 | "depd": "2.0.0", 30 | "destroy": "1.2.0", 31 | "http-errors": "2.0.0", 32 | "iconv-lite": "0.4.24", 33 | "on-finished": "2.4.1", 34 | "qs": "6.13.0", 35 | "raw-body": "2.5.2", 36 | "type-is": "~1.6.18", 37 | "unpipe": "1.0.0" 38 | } 39 | }, 40 | "bytes": { 41 | "version": "3.1.2", 42 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 43 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 44 | }, 45 | "call-bind": { 46 | "version": "1.0.7", 47 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", 48 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", 49 | "requires": { 50 | "es-define-property": "^1.0.0", 51 | "es-errors": "^1.3.0", 52 | "function-bind": "^1.1.2", 53 | "get-intrinsic": "^1.2.4", 54 | "set-function-length": "^1.2.1" 55 | } 56 | }, 57 | "content-disposition": { 58 | "version": "0.5.4", 59 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 60 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 61 | "requires": { 62 | "safe-buffer": "5.2.1" 63 | } 64 | }, 65 | "content-type": { 66 | "version": "1.0.5", 67 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 68 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" 69 | }, 70 | "cookie": { 71 | "version": "0.6.0", 72 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", 73 | "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" 74 | }, 75 | "cookie-signature": { 76 | "version": "1.0.6", 77 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 78 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 79 | }, 80 | "debug": { 81 | "version": "2.6.9", 82 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 83 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 84 | "requires": { 85 | "ms": "2.0.0" 86 | } 87 | }, 88 | "define-data-property": { 89 | "version": "1.1.4", 90 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", 91 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 92 | "requires": { 93 | "es-define-property": "^1.0.0", 94 | "es-errors": "^1.3.0", 95 | "gopd": "^1.0.1" 96 | } 97 | }, 98 | "depd": { 99 | "version": "2.0.0", 100 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 101 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 102 | }, 103 | "destroy": { 104 | "version": "1.2.0", 105 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 106 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" 107 | }, 108 | "ee-first": { 109 | "version": "1.1.1", 110 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 111 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 112 | }, 113 | "encodeurl": { 114 | "version": "2.0.0", 115 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 116 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" 117 | }, 118 | "es-define-property": { 119 | "version": "1.0.0", 120 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", 121 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", 122 | "requires": { 123 | "get-intrinsic": "^1.2.4" 124 | } 125 | }, 126 | "es-errors": { 127 | "version": "1.3.0", 128 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 129 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" 130 | }, 131 | "escape-html": { 132 | "version": "1.0.3", 133 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 134 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 135 | }, 136 | "etag": { 137 | "version": "1.8.1", 138 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 139 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 140 | }, 141 | "express": { 142 | "version": "4.21.0", 143 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", 144 | "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", 145 | "requires": { 146 | "accepts": "~1.3.8", 147 | "array-flatten": "1.1.1", 148 | "body-parser": "1.20.3", 149 | "content-disposition": "0.5.4", 150 | "content-type": "~1.0.4", 151 | "cookie": "0.6.0", 152 | "cookie-signature": "1.0.6", 153 | "debug": "2.6.9", 154 | "depd": "2.0.0", 155 | "encodeurl": "~2.0.0", 156 | "escape-html": "~1.0.3", 157 | "etag": "~1.8.1", 158 | "finalhandler": "1.3.1", 159 | "fresh": "0.5.2", 160 | "http-errors": "2.0.0", 161 | "merge-descriptors": "1.0.3", 162 | "methods": "~1.1.2", 163 | "on-finished": "2.4.1", 164 | "parseurl": "~1.3.3", 165 | "path-to-regexp": "0.1.10", 166 | "proxy-addr": "~2.0.7", 167 | "qs": "6.13.0", 168 | "range-parser": "~1.2.1", 169 | "safe-buffer": "5.2.1", 170 | "send": "0.19.0", 171 | "serve-static": "1.16.2", 172 | "setprototypeof": "1.2.0", 173 | "statuses": "2.0.1", 174 | "type-is": "~1.6.18", 175 | "utils-merge": "1.0.1", 176 | "vary": "~1.1.2" 177 | } 178 | }, 179 | "finalhandler": { 180 | "version": "1.3.1", 181 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", 182 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", 183 | "requires": { 184 | "debug": "2.6.9", 185 | "encodeurl": "~2.0.0", 186 | "escape-html": "~1.0.3", 187 | "on-finished": "2.4.1", 188 | "parseurl": "~1.3.3", 189 | "statuses": "2.0.1", 190 | "unpipe": "~1.0.0" 191 | } 192 | }, 193 | "forwarded": { 194 | "version": "0.2.0", 195 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 196 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 197 | }, 198 | "fresh": { 199 | "version": "0.5.2", 200 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 201 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 202 | }, 203 | "function-bind": { 204 | "version": "1.1.2", 205 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 206 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" 207 | }, 208 | "get-intrinsic": { 209 | "version": "1.2.4", 210 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", 211 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", 212 | "requires": { 213 | "es-errors": "^1.3.0", 214 | "function-bind": "^1.1.2", 215 | "has-proto": "^1.0.1", 216 | "has-symbols": "^1.0.3", 217 | "hasown": "^2.0.0" 218 | } 219 | }, 220 | "gopd": { 221 | "version": "1.0.1", 222 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 223 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 224 | "requires": { 225 | "get-intrinsic": "^1.1.3" 226 | } 227 | }, 228 | "has-property-descriptors": { 229 | "version": "1.0.2", 230 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 231 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 232 | "requires": { 233 | "es-define-property": "^1.0.0" 234 | } 235 | }, 236 | "has-proto": { 237 | "version": "1.0.3", 238 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", 239 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" 240 | }, 241 | "has-symbols": { 242 | "version": "1.0.3", 243 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 244 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 245 | }, 246 | "hasown": { 247 | "version": "2.0.2", 248 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 249 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 250 | "requires": { 251 | "function-bind": "^1.1.2" 252 | } 253 | }, 254 | "http-errors": { 255 | "version": "2.0.0", 256 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 257 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 258 | "requires": { 259 | "depd": "2.0.0", 260 | "inherits": "2.0.4", 261 | "setprototypeof": "1.2.0", 262 | "statuses": "2.0.1", 263 | "toidentifier": "1.0.1" 264 | } 265 | }, 266 | "iconv-lite": { 267 | "version": "0.4.24", 268 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 269 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 270 | "requires": { 271 | "safer-buffer": ">= 2.1.2 < 3" 272 | } 273 | }, 274 | "inherits": { 275 | "version": "2.0.4", 276 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 277 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 278 | }, 279 | "ipaddr.js": { 280 | "version": "1.9.1", 281 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 282 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 283 | }, 284 | "media-typer": { 285 | "version": "0.3.0", 286 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 287 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 288 | }, 289 | "merge-descriptors": { 290 | "version": "1.0.3", 291 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", 292 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" 293 | }, 294 | "methods": { 295 | "version": "1.1.2", 296 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 297 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 298 | }, 299 | "mime": { 300 | "version": "1.6.0", 301 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 302 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 303 | }, 304 | "mime-db": { 305 | "version": "1.52.0", 306 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 307 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 308 | }, 309 | "mime-types": { 310 | "version": "2.1.35", 311 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 312 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 313 | "requires": { 314 | "mime-db": "1.52.0" 315 | } 316 | }, 317 | "ms": { 318 | "version": "2.0.0", 319 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 320 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 321 | }, 322 | "negotiator": { 323 | "version": "0.6.3", 324 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 325 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 326 | }, 327 | "object-inspect": { 328 | "version": "1.13.2", 329 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", 330 | "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" 331 | }, 332 | "on-finished": { 333 | "version": "2.4.1", 334 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 335 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 336 | "requires": { 337 | "ee-first": "1.1.1" 338 | } 339 | }, 340 | "parseurl": { 341 | "version": "1.3.3", 342 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 343 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 344 | }, 345 | "path-to-regexp": { 346 | "version": "0.1.10", 347 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", 348 | "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" 349 | }, 350 | "proxy-addr": { 351 | "version": "2.0.7", 352 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 353 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 354 | "requires": { 355 | "forwarded": "0.2.0", 356 | "ipaddr.js": "1.9.1" 357 | } 358 | }, 359 | "qs": { 360 | "version": "6.13.0", 361 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 362 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 363 | "requires": { 364 | "side-channel": "^1.0.6" 365 | } 366 | }, 367 | "range-parser": { 368 | "version": "1.2.1", 369 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 370 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 371 | }, 372 | "raw-body": { 373 | "version": "2.5.2", 374 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", 375 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", 376 | "requires": { 377 | "bytes": "3.1.2", 378 | "http-errors": "2.0.0", 379 | "iconv-lite": "0.4.24", 380 | "unpipe": "1.0.0" 381 | } 382 | }, 383 | "safe-buffer": { 384 | "version": "5.2.1", 385 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 386 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 387 | }, 388 | "safer-buffer": { 389 | "version": "2.1.2", 390 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 391 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 392 | }, 393 | "send": { 394 | "version": "0.19.0", 395 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", 396 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 397 | "requires": { 398 | "debug": "2.6.9", 399 | "depd": "2.0.0", 400 | "destroy": "1.2.0", 401 | "encodeurl": "~1.0.2", 402 | "escape-html": "~1.0.3", 403 | "etag": "~1.8.1", 404 | "fresh": "0.5.2", 405 | "http-errors": "2.0.0", 406 | "mime": "1.6.0", 407 | "ms": "2.1.3", 408 | "on-finished": "2.4.1", 409 | "range-parser": "~1.2.1", 410 | "statuses": "2.0.1" 411 | }, 412 | "dependencies": { 413 | "encodeurl": { 414 | "version": "1.0.2", 415 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 416 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 417 | }, 418 | "ms": { 419 | "version": "2.1.3", 420 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 421 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 422 | } 423 | } 424 | }, 425 | "serve-static": { 426 | "version": "1.16.2", 427 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", 428 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", 429 | "requires": { 430 | "encodeurl": "~2.0.0", 431 | "escape-html": "~1.0.3", 432 | "parseurl": "~1.3.3", 433 | "send": "0.19.0" 434 | } 435 | }, 436 | "set-function-length": { 437 | "version": "1.2.2", 438 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", 439 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 440 | "requires": { 441 | "define-data-property": "^1.1.4", 442 | "es-errors": "^1.3.0", 443 | "function-bind": "^1.1.2", 444 | "get-intrinsic": "^1.2.4", 445 | "gopd": "^1.0.1", 446 | "has-property-descriptors": "^1.0.2" 447 | } 448 | }, 449 | "setprototypeof": { 450 | "version": "1.2.0", 451 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 452 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 453 | }, 454 | "side-channel": { 455 | "version": "1.0.6", 456 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", 457 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", 458 | "requires": { 459 | "call-bind": "^1.0.7", 460 | "es-errors": "^1.3.0", 461 | "get-intrinsic": "^1.2.4", 462 | "object-inspect": "^1.13.1" 463 | } 464 | }, 465 | "statuses": { 466 | "version": "2.0.1", 467 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 468 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" 469 | }, 470 | "toidentifier": { 471 | "version": "1.0.1", 472 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 473 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 474 | }, 475 | "type-is": { 476 | "version": "1.6.18", 477 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 478 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 479 | "requires": { 480 | "media-typer": "0.3.0", 481 | "mime-types": "~2.1.24" 482 | } 483 | }, 484 | "unpipe": { 485 | "version": "1.0.0", 486 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 487 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 488 | }, 489 | "utils-merge": { 490 | "version": "1.0.1", 491 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 492 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 493 | }, 494 | "vary": { 495 | "version": "1.1.2", 496 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 497 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 498 | } 499 | } 500 | } 501 | -------------------------------------------------------------------------------- /example-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helloworld", 3 | "version": "1.0.0", 4 | "description": "Simple hello world sample in Node", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "author": "Google LLC", 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "express": "^4.21.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deploy-appengine", 3 | "version": "2.1.5", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "deploy-appengine", 9 | "version": "2.1.5", 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "@actions/core": "^1.11.1", 13 | "@actions/exec": "^1.1.1", 14 | "@google-github-actions/actions-utils": "^0.8.6", 15 | "@google-github-actions/setup-cloud-sdk": "^1.1.9", 16 | "yaml": "^2.7.0" 17 | }, 18 | "devDependencies": { 19 | "@eslint/eslintrc": "^3.2.0", 20 | "@eslint/js": "^9.19.0", 21 | "@types/node": "^22.13.0", 22 | "@typescript-eslint/eslint-plugin": "^8.22.0", 23 | "@typescript-eslint/parser": "^8.22.0", 24 | "@vercel/ncc": "^0.38.3", 25 | "eslint": "^9.19.0", 26 | "eslint-config-prettier": "^10.0.1", 27 | "eslint-plugin-prettier": "^5.2.3", 28 | "prettier": "^3.4.2", 29 | "ts-node": "^10.9.2", 30 | "typescript": "^5.7.3", 31 | "typescript-eslint": "^8.22.0" 32 | } 33 | }, 34 | "node_modules/@actions/core": { 35 | "version": "1.11.1", 36 | "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", 37 | "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", 38 | "license": "MIT", 39 | "dependencies": { 40 | "@actions/exec": "^1.1.1", 41 | "@actions/http-client": "^2.0.1" 42 | } 43 | }, 44 | "node_modules/@actions/exec": { 45 | "version": "1.1.1", 46 | "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", 47 | "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", 48 | "license": "MIT", 49 | "dependencies": { 50 | "@actions/io": "^1.0.1" 51 | } 52 | }, 53 | "node_modules/@actions/http-client": { 54 | "version": "2.2.3", 55 | "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", 56 | "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", 57 | "license": "MIT", 58 | "dependencies": { 59 | "tunnel": "^0.0.6", 60 | "undici": "^5.25.4" 61 | } 62 | }, 63 | "node_modules/@actions/io": { 64 | "version": "1.1.3", 65 | "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", 66 | "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", 67 | "license": "MIT" 68 | }, 69 | "node_modules/@actions/tool-cache": { 70 | "version": "2.0.2", 71 | "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.2.tgz", 72 | "integrity": "sha512-fBhNNOWxuoLxztQebpOaWu6WeVmuwa77Z+DxIZ1B+OYvGkGQon6kTVg6Z32Cb13WCuw0szqonK+hh03mJV7Z6w==", 73 | "license": "MIT", 74 | "dependencies": { 75 | "@actions/core": "^1.11.1", 76 | "@actions/exec": "^1.0.0", 77 | "@actions/http-client": "^2.0.1", 78 | "@actions/io": "^1.1.1", 79 | "semver": "^6.1.0" 80 | } 81 | }, 82 | "node_modules/@actions/tool-cache/node_modules/semver": { 83 | "version": "6.3.1", 84 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 85 | "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 86 | "license": "ISC", 87 | "bin": { 88 | "semver": "bin/semver.js" 89 | } 90 | }, 91 | "node_modules/@cspotcode/source-map-support": { 92 | "version": "0.8.1", 93 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 94 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 95 | "dev": true, 96 | "license": "MIT", 97 | "dependencies": { 98 | "@jridgewell/trace-mapping": "0.3.9" 99 | }, 100 | "engines": { 101 | "node": ">=12" 102 | } 103 | }, 104 | "node_modules/@eslint-community/eslint-utils": { 105 | "version": "4.4.1", 106 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", 107 | "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", 108 | "dev": true, 109 | "license": "MIT", 110 | "dependencies": { 111 | "eslint-visitor-keys": "^3.4.3" 112 | }, 113 | "engines": { 114 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 115 | }, 116 | "funding": { 117 | "url": "https://opencollective.com/eslint" 118 | }, 119 | "peerDependencies": { 120 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 121 | } 122 | }, 123 | "node_modules/@eslint-community/regexpp": { 124 | "version": "4.12.1", 125 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", 126 | "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", 127 | "dev": true, 128 | "license": "MIT", 129 | "engines": { 130 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 131 | } 132 | }, 133 | "node_modules/@eslint/config-array": { 134 | "version": "0.19.2", 135 | "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", 136 | "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", 137 | "dev": true, 138 | "license": "Apache-2.0", 139 | "dependencies": { 140 | "@eslint/object-schema": "^2.1.6", 141 | "debug": "^4.3.1", 142 | "minimatch": "^3.1.2" 143 | }, 144 | "engines": { 145 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 146 | } 147 | }, 148 | "node_modules/@eslint/core": { 149 | "version": "0.10.0", 150 | "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", 151 | "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", 152 | "dev": true, 153 | "license": "Apache-2.0", 154 | "dependencies": { 155 | "@types/json-schema": "^7.0.15" 156 | }, 157 | "engines": { 158 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 159 | } 160 | }, 161 | "node_modules/@eslint/eslintrc": { 162 | "version": "3.2.0", 163 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", 164 | "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", 165 | "dev": true, 166 | "license": "MIT", 167 | "dependencies": { 168 | "ajv": "^6.12.4", 169 | "debug": "^4.3.2", 170 | "espree": "^10.0.1", 171 | "globals": "^14.0.0", 172 | "ignore": "^5.2.0", 173 | "import-fresh": "^3.2.1", 174 | "js-yaml": "^4.1.0", 175 | "minimatch": "^3.1.2", 176 | "strip-json-comments": "^3.1.1" 177 | }, 178 | "engines": { 179 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 180 | }, 181 | "funding": { 182 | "url": "https://opencollective.com/eslint" 183 | } 184 | }, 185 | "node_modules/@eslint/js": { 186 | "version": "9.19.0", 187 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz", 188 | "integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==", 189 | "dev": true, 190 | "license": "MIT", 191 | "engines": { 192 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 193 | } 194 | }, 195 | "node_modules/@eslint/object-schema": { 196 | "version": "2.1.6", 197 | "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", 198 | "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", 199 | "dev": true, 200 | "license": "Apache-2.0", 201 | "engines": { 202 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 203 | } 204 | }, 205 | "node_modules/@eslint/plugin-kit": { 206 | "version": "0.2.5", 207 | "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", 208 | "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", 209 | "dev": true, 210 | "license": "Apache-2.0", 211 | "dependencies": { 212 | "@eslint/core": "^0.10.0", 213 | "levn": "^0.4.1" 214 | }, 215 | "engines": { 216 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 217 | } 218 | }, 219 | "node_modules/@fastify/busboy": { 220 | "version": "2.1.1", 221 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", 222 | "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", 223 | "license": "MIT", 224 | "engines": { 225 | "node": ">=14" 226 | } 227 | }, 228 | "node_modules/@google-github-actions/actions-utils": { 229 | "version": "0.8.6", 230 | "resolved": "https://registry.npmjs.org/@google-github-actions/actions-utils/-/actions-utils-0.8.6.tgz", 231 | "integrity": "sha512-X/iZ7dycTHjKWk20RUJOxK0G0YHS44N8NN22SwQ01CNUWn3knbkg/VFfmlYidIG2vcWxIK+xMCkQxbNVVbdt4A==", 232 | "license": "Apache-2.0", 233 | "dependencies": { 234 | "yaml": "^2.7.0" 235 | }, 236 | "bin": { 237 | "actions-gen-readme": "bin/actions-gen-readme.mjs" 238 | } 239 | }, 240 | "node_modules/@google-github-actions/setup-cloud-sdk": { 241 | "version": "1.1.9", 242 | "resolved": "https://registry.npmjs.org/@google-github-actions/setup-cloud-sdk/-/setup-cloud-sdk-1.1.9.tgz", 243 | "integrity": "sha512-RUJISUKmAnqY3ZsY2Eb8VM2emV7wRj9mPhLYoo5gmyCq25CmRVgyu5q1ZCmG9WziGtj3D4qT0UTWgqg4zivHKw==", 244 | "license": "Apache-2.0", 245 | "dependencies": { 246 | "@actions/core": "^1.11.1", 247 | "@actions/exec": "^1.1.1", 248 | "@actions/http-client": "^2.2.3", 249 | "@actions/tool-cache": "^2.0.2", 250 | "@google-github-actions/actions-utils": "^0.8.6", 251 | "semver": "^7.7.0" 252 | } 253 | }, 254 | "node_modules/@humanfs/core": { 255 | "version": "0.19.1", 256 | "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", 257 | "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", 258 | "dev": true, 259 | "license": "Apache-2.0", 260 | "engines": { 261 | "node": ">=18.18.0" 262 | } 263 | }, 264 | "node_modules/@humanfs/node": { 265 | "version": "0.16.6", 266 | "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", 267 | "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", 268 | "dev": true, 269 | "license": "Apache-2.0", 270 | "dependencies": { 271 | "@humanfs/core": "^0.19.1", 272 | "@humanwhocodes/retry": "^0.3.0" 273 | }, 274 | "engines": { 275 | "node": ">=18.18.0" 276 | } 277 | }, 278 | "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { 279 | "version": "0.3.1", 280 | "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", 281 | "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", 282 | "dev": true, 283 | "license": "Apache-2.0", 284 | "engines": { 285 | "node": ">=18.18" 286 | }, 287 | "funding": { 288 | "type": "github", 289 | "url": "https://github.com/sponsors/nzakas" 290 | } 291 | }, 292 | "node_modules/@humanwhocodes/module-importer": { 293 | "version": "1.0.1", 294 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 295 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 296 | "dev": true, 297 | "license": "Apache-2.0", 298 | "engines": { 299 | "node": ">=12.22" 300 | }, 301 | "funding": { 302 | "type": "github", 303 | "url": "https://github.com/sponsors/nzakas" 304 | } 305 | }, 306 | "node_modules/@humanwhocodes/retry": { 307 | "version": "0.4.1", 308 | "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", 309 | "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", 310 | "dev": true, 311 | "license": "Apache-2.0", 312 | "engines": { 313 | "node": ">=18.18" 314 | }, 315 | "funding": { 316 | "type": "github", 317 | "url": "https://github.com/sponsors/nzakas" 318 | } 319 | }, 320 | "node_modules/@jridgewell/resolve-uri": { 321 | "version": "3.1.2", 322 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 323 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 324 | "dev": true, 325 | "license": "MIT", 326 | "engines": { 327 | "node": ">=6.0.0" 328 | } 329 | }, 330 | "node_modules/@jridgewell/sourcemap-codec": { 331 | "version": "1.5.0", 332 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 333 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 334 | "dev": true, 335 | "license": "MIT" 336 | }, 337 | "node_modules/@jridgewell/trace-mapping": { 338 | "version": "0.3.9", 339 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 340 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 341 | "dev": true, 342 | "license": "MIT", 343 | "dependencies": { 344 | "@jridgewell/resolve-uri": "^3.0.3", 345 | "@jridgewell/sourcemap-codec": "^1.4.10" 346 | } 347 | }, 348 | "node_modules/@nodelib/fs.scandir": { 349 | "version": "2.1.5", 350 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 351 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 352 | "dev": true, 353 | "license": "MIT", 354 | "dependencies": { 355 | "@nodelib/fs.stat": "2.0.5", 356 | "run-parallel": "^1.1.9" 357 | }, 358 | "engines": { 359 | "node": ">= 8" 360 | } 361 | }, 362 | "node_modules/@nodelib/fs.stat": { 363 | "version": "2.0.5", 364 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 365 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 366 | "dev": true, 367 | "license": "MIT", 368 | "engines": { 369 | "node": ">= 8" 370 | } 371 | }, 372 | "node_modules/@nodelib/fs.walk": { 373 | "version": "1.2.8", 374 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 375 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 376 | "dev": true, 377 | "license": "MIT", 378 | "dependencies": { 379 | "@nodelib/fs.scandir": "2.1.5", 380 | "fastq": "^1.6.0" 381 | }, 382 | "engines": { 383 | "node": ">= 8" 384 | } 385 | }, 386 | "node_modules/@pkgr/core": { 387 | "version": "0.1.1", 388 | "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", 389 | "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", 390 | "dev": true, 391 | "license": "MIT", 392 | "engines": { 393 | "node": "^12.20.0 || ^14.18.0 || >=16.0.0" 394 | }, 395 | "funding": { 396 | "url": "https://opencollective.com/unts" 397 | } 398 | }, 399 | "node_modules/@tsconfig/node10": { 400 | "version": "1.0.11", 401 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", 402 | "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", 403 | "dev": true, 404 | "license": "MIT" 405 | }, 406 | "node_modules/@tsconfig/node12": { 407 | "version": "1.0.11", 408 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 409 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 410 | "dev": true, 411 | "license": "MIT" 412 | }, 413 | "node_modules/@tsconfig/node14": { 414 | "version": "1.0.3", 415 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 416 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 417 | "dev": true, 418 | "license": "MIT" 419 | }, 420 | "node_modules/@tsconfig/node16": { 421 | "version": "1.0.4", 422 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 423 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", 424 | "dev": true, 425 | "license": "MIT" 426 | }, 427 | "node_modules/@types/estree": { 428 | "version": "1.0.6", 429 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 430 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 431 | "dev": true, 432 | "license": "MIT" 433 | }, 434 | "node_modules/@types/json-schema": { 435 | "version": "7.0.15", 436 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", 437 | "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", 438 | "dev": true, 439 | "license": "MIT" 440 | }, 441 | "node_modules/@types/node": { 442 | "version": "22.13.0", 443 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.0.tgz", 444 | "integrity": "sha512-ClIbNe36lawluuvq3+YYhnIN2CELi+6q8NpnM7PYp4hBn/TatfboPgVSm2rwKRfnV2M+Ty9GWDFI64KEe+kysA==", 445 | "dev": true, 446 | "license": "MIT", 447 | "dependencies": { 448 | "undici-types": "~6.20.0" 449 | } 450 | }, 451 | "node_modules/@typescript-eslint/eslint-plugin": { 452 | "version": "8.22.0", 453 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.22.0.tgz", 454 | "integrity": "sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==", 455 | "dev": true, 456 | "license": "MIT", 457 | "dependencies": { 458 | "@eslint-community/regexpp": "^4.10.0", 459 | "@typescript-eslint/scope-manager": "8.22.0", 460 | "@typescript-eslint/type-utils": "8.22.0", 461 | "@typescript-eslint/utils": "8.22.0", 462 | "@typescript-eslint/visitor-keys": "8.22.0", 463 | "graphemer": "^1.4.0", 464 | "ignore": "^5.3.1", 465 | "natural-compare": "^1.4.0", 466 | "ts-api-utils": "^2.0.0" 467 | }, 468 | "engines": { 469 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 470 | }, 471 | "funding": { 472 | "type": "opencollective", 473 | "url": "https://opencollective.com/typescript-eslint" 474 | }, 475 | "peerDependencies": { 476 | "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", 477 | "eslint": "^8.57.0 || ^9.0.0", 478 | "typescript": ">=4.8.4 <5.8.0" 479 | } 480 | }, 481 | "node_modules/@typescript-eslint/parser": { 482 | "version": "8.22.0", 483 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.22.0.tgz", 484 | "integrity": "sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==", 485 | "dev": true, 486 | "license": "MIT", 487 | "dependencies": { 488 | "@typescript-eslint/scope-manager": "8.22.0", 489 | "@typescript-eslint/types": "8.22.0", 490 | "@typescript-eslint/typescript-estree": "8.22.0", 491 | "@typescript-eslint/visitor-keys": "8.22.0", 492 | "debug": "^4.3.4" 493 | }, 494 | "engines": { 495 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 496 | }, 497 | "funding": { 498 | "type": "opencollective", 499 | "url": "https://opencollective.com/typescript-eslint" 500 | }, 501 | "peerDependencies": { 502 | "eslint": "^8.57.0 || ^9.0.0", 503 | "typescript": ">=4.8.4 <5.8.0" 504 | } 505 | }, 506 | "node_modules/@typescript-eslint/scope-manager": { 507 | "version": "8.22.0", 508 | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.22.0.tgz", 509 | "integrity": "sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==", 510 | "dev": true, 511 | "license": "MIT", 512 | "dependencies": { 513 | "@typescript-eslint/types": "8.22.0", 514 | "@typescript-eslint/visitor-keys": "8.22.0" 515 | }, 516 | "engines": { 517 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 518 | }, 519 | "funding": { 520 | "type": "opencollective", 521 | "url": "https://opencollective.com/typescript-eslint" 522 | } 523 | }, 524 | "node_modules/@typescript-eslint/type-utils": { 525 | "version": "8.22.0", 526 | "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.22.0.tgz", 527 | "integrity": "sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==", 528 | "dev": true, 529 | "license": "MIT", 530 | "dependencies": { 531 | "@typescript-eslint/typescript-estree": "8.22.0", 532 | "@typescript-eslint/utils": "8.22.0", 533 | "debug": "^4.3.4", 534 | "ts-api-utils": "^2.0.0" 535 | }, 536 | "engines": { 537 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 538 | }, 539 | "funding": { 540 | "type": "opencollective", 541 | "url": "https://opencollective.com/typescript-eslint" 542 | }, 543 | "peerDependencies": { 544 | "eslint": "^8.57.0 || ^9.0.0", 545 | "typescript": ">=4.8.4 <5.8.0" 546 | } 547 | }, 548 | "node_modules/@typescript-eslint/types": { 549 | "version": "8.22.0", 550 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", 551 | "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", 552 | "dev": true, 553 | "license": "MIT", 554 | "engines": { 555 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 556 | }, 557 | "funding": { 558 | "type": "opencollective", 559 | "url": "https://opencollective.com/typescript-eslint" 560 | } 561 | }, 562 | "node_modules/@typescript-eslint/typescript-estree": { 563 | "version": "8.22.0", 564 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz", 565 | "integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==", 566 | "dev": true, 567 | "license": "MIT", 568 | "dependencies": { 569 | "@typescript-eslint/types": "8.22.0", 570 | "@typescript-eslint/visitor-keys": "8.22.0", 571 | "debug": "^4.3.4", 572 | "fast-glob": "^3.3.2", 573 | "is-glob": "^4.0.3", 574 | "minimatch": "^9.0.4", 575 | "semver": "^7.6.0", 576 | "ts-api-utils": "^2.0.0" 577 | }, 578 | "engines": { 579 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 580 | }, 581 | "funding": { 582 | "type": "opencollective", 583 | "url": "https://opencollective.com/typescript-eslint" 584 | }, 585 | "peerDependencies": { 586 | "typescript": ">=4.8.4 <5.8.0" 587 | } 588 | }, 589 | "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { 590 | "version": "2.0.1", 591 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 592 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 593 | "dev": true, 594 | "license": "MIT", 595 | "dependencies": { 596 | "balanced-match": "^1.0.0" 597 | } 598 | }, 599 | "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { 600 | "version": "9.0.5", 601 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 602 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 603 | "dev": true, 604 | "license": "ISC", 605 | "dependencies": { 606 | "brace-expansion": "^2.0.1" 607 | }, 608 | "engines": { 609 | "node": ">=16 || 14 >=14.17" 610 | }, 611 | "funding": { 612 | "url": "https://github.com/sponsors/isaacs" 613 | } 614 | }, 615 | "node_modules/@typescript-eslint/utils": { 616 | "version": "8.22.0", 617 | "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.22.0.tgz", 618 | "integrity": "sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==", 619 | "dev": true, 620 | "license": "MIT", 621 | "dependencies": { 622 | "@eslint-community/eslint-utils": "^4.4.0", 623 | "@typescript-eslint/scope-manager": "8.22.0", 624 | "@typescript-eslint/types": "8.22.0", 625 | "@typescript-eslint/typescript-estree": "8.22.0" 626 | }, 627 | "engines": { 628 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 629 | }, 630 | "funding": { 631 | "type": "opencollective", 632 | "url": "https://opencollective.com/typescript-eslint" 633 | }, 634 | "peerDependencies": { 635 | "eslint": "^8.57.0 || ^9.0.0", 636 | "typescript": ">=4.8.4 <5.8.0" 637 | } 638 | }, 639 | "node_modules/@typescript-eslint/visitor-keys": { 640 | "version": "8.22.0", 641 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", 642 | "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", 643 | "dev": true, 644 | "license": "MIT", 645 | "dependencies": { 646 | "@typescript-eslint/types": "8.22.0", 647 | "eslint-visitor-keys": "^4.2.0" 648 | }, 649 | "engines": { 650 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 651 | }, 652 | "funding": { 653 | "type": "opencollective", 654 | "url": "https://opencollective.com/typescript-eslint" 655 | } 656 | }, 657 | "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { 658 | "version": "4.2.0", 659 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", 660 | "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", 661 | "dev": true, 662 | "license": "Apache-2.0", 663 | "engines": { 664 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 665 | }, 666 | "funding": { 667 | "url": "https://opencollective.com/eslint" 668 | } 669 | }, 670 | "node_modules/@vercel/ncc": { 671 | "version": "0.38.3", 672 | "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.3.tgz", 673 | "integrity": "sha512-rnK6hJBS6mwc+Bkab+PGPs9OiS0i/3kdTO+CkI8V0/VrW3vmz7O2Pxjw/owOlmo6PKEIxRSeZKv/kuL9itnpYA==", 674 | "dev": true, 675 | "license": "MIT", 676 | "bin": { 677 | "ncc": "dist/ncc/cli.js" 678 | } 679 | }, 680 | "node_modules/acorn": { 681 | "version": "8.14.0", 682 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 683 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 684 | "dev": true, 685 | "license": "MIT", 686 | "bin": { 687 | "acorn": "bin/acorn" 688 | }, 689 | "engines": { 690 | "node": ">=0.4.0" 691 | } 692 | }, 693 | "node_modules/acorn-jsx": { 694 | "version": "5.3.2", 695 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 696 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 697 | "dev": true, 698 | "license": "MIT", 699 | "peerDependencies": { 700 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 701 | } 702 | }, 703 | "node_modules/acorn-walk": { 704 | "version": "8.3.4", 705 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", 706 | "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", 707 | "dev": true, 708 | "license": "MIT", 709 | "dependencies": { 710 | "acorn": "^8.11.0" 711 | }, 712 | "engines": { 713 | "node": ">=0.4.0" 714 | } 715 | }, 716 | "node_modules/ajv": { 717 | "version": "6.12.6", 718 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 719 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 720 | "dev": true, 721 | "license": "MIT", 722 | "dependencies": { 723 | "fast-deep-equal": "^3.1.1", 724 | "fast-json-stable-stringify": "^2.0.0", 725 | "json-schema-traverse": "^0.4.1", 726 | "uri-js": "^4.2.2" 727 | }, 728 | "funding": { 729 | "type": "github", 730 | "url": "https://github.com/sponsors/epoberezkin" 731 | } 732 | }, 733 | "node_modules/ansi-styles": { 734 | "version": "4.3.0", 735 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 736 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 737 | "dev": true, 738 | "license": "MIT", 739 | "dependencies": { 740 | "color-convert": "^2.0.1" 741 | }, 742 | "engines": { 743 | "node": ">=8" 744 | }, 745 | "funding": { 746 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 747 | } 748 | }, 749 | "node_modules/arg": { 750 | "version": "4.1.3", 751 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 752 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 753 | "dev": true, 754 | "license": "MIT" 755 | }, 756 | "node_modules/argparse": { 757 | "version": "2.0.1", 758 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 759 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 760 | "dev": true, 761 | "license": "Python-2.0" 762 | }, 763 | "node_modules/balanced-match": { 764 | "version": "1.0.2", 765 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 766 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 767 | "dev": true, 768 | "license": "MIT" 769 | }, 770 | "node_modules/brace-expansion": { 771 | "version": "1.1.11", 772 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 773 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 774 | "dev": true, 775 | "license": "MIT", 776 | "dependencies": { 777 | "balanced-match": "^1.0.0", 778 | "concat-map": "0.0.1" 779 | } 780 | }, 781 | "node_modules/braces": { 782 | "version": "3.0.3", 783 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 784 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 785 | "dev": true, 786 | "license": "MIT", 787 | "dependencies": { 788 | "fill-range": "^7.1.1" 789 | }, 790 | "engines": { 791 | "node": ">=8" 792 | } 793 | }, 794 | "node_modules/callsites": { 795 | "version": "3.1.0", 796 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 797 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 798 | "dev": true, 799 | "license": "MIT", 800 | "engines": { 801 | "node": ">=6" 802 | } 803 | }, 804 | "node_modules/chalk": { 805 | "version": "4.1.2", 806 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 807 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 808 | "dev": true, 809 | "license": "MIT", 810 | "dependencies": { 811 | "ansi-styles": "^4.1.0", 812 | "supports-color": "^7.1.0" 813 | }, 814 | "engines": { 815 | "node": ">=10" 816 | }, 817 | "funding": { 818 | "url": "https://github.com/chalk/chalk?sponsor=1" 819 | } 820 | }, 821 | "node_modules/color-convert": { 822 | "version": "2.0.1", 823 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 824 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 825 | "dev": true, 826 | "license": "MIT", 827 | "dependencies": { 828 | "color-name": "~1.1.4" 829 | }, 830 | "engines": { 831 | "node": ">=7.0.0" 832 | } 833 | }, 834 | "node_modules/color-name": { 835 | "version": "1.1.4", 836 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 837 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 838 | "dev": true, 839 | "license": "MIT" 840 | }, 841 | "node_modules/concat-map": { 842 | "version": "0.0.1", 843 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 844 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 845 | "dev": true, 846 | "license": "MIT" 847 | }, 848 | "node_modules/create-require": { 849 | "version": "1.1.1", 850 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 851 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 852 | "dev": true, 853 | "license": "MIT" 854 | }, 855 | "node_modules/cross-spawn": { 856 | "version": "7.0.6", 857 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 858 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 859 | "dev": true, 860 | "license": "MIT", 861 | "dependencies": { 862 | "path-key": "^3.1.0", 863 | "shebang-command": "^2.0.0", 864 | "which": "^2.0.1" 865 | }, 866 | "engines": { 867 | "node": ">= 8" 868 | } 869 | }, 870 | "node_modules/debug": { 871 | "version": "4.4.0", 872 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 873 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 874 | "dev": true, 875 | "license": "MIT", 876 | "dependencies": { 877 | "ms": "^2.1.3" 878 | }, 879 | "engines": { 880 | "node": ">=6.0" 881 | }, 882 | "peerDependenciesMeta": { 883 | "supports-color": { 884 | "optional": true 885 | } 886 | } 887 | }, 888 | "node_modules/deep-is": { 889 | "version": "0.1.4", 890 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 891 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 892 | "dev": true, 893 | "license": "MIT" 894 | }, 895 | "node_modules/diff": { 896 | "version": "4.0.2", 897 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 898 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 899 | "dev": true, 900 | "license": "BSD-3-Clause", 901 | "engines": { 902 | "node": ">=0.3.1" 903 | } 904 | }, 905 | "node_modules/escape-string-regexp": { 906 | "version": "4.0.0", 907 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 908 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 909 | "dev": true, 910 | "license": "MIT", 911 | "engines": { 912 | "node": ">=10" 913 | }, 914 | "funding": { 915 | "url": "https://github.com/sponsors/sindresorhus" 916 | } 917 | }, 918 | "node_modules/eslint": { 919 | "version": "9.19.0", 920 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz", 921 | "integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==", 922 | "dev": true, 923 | "license": "MIT", 924 | "dependencies": { 925 | "@eslint-community/eslint-utils": "^4.2.0", 926 | "@eslint-community/regexpp": "^4.12.1", 927 | "@eslint/config-array": "^0.19.0", 928 | "@eslint/core": "^0.10.0", 929 | "@eslint/eslintrc": "^3.2.0", 930 | "@eslint/js": "9.19.0", 931 | "@eslint/plugin-kit": "^0.2.5", 932 | "@humanfs/node": "^0.16.6", 933 | "@humanwhocodes/module-importer": "^1.0.1", 934 | "@humanwhocodes/retry": "^0.4.1", 935 | "@types/estree": "^1.0.6", 936 | "@types/json-schema": "^7.0.15", 937 | "ajv": "^6.12.4", 938 | "chalk": "^4.0.0", 939 | "cross-spawn": "^7.0.6", 940 | "debug": "^4.3.2", 941 | "escape-string-regexp": "^4.0.0", 942 | "eslint-scope": "^8.2.0", 943 | "eslint-visitor-keys": "^4.2.0", 944 | "espree": "^10.3.0", 945 | "esquery": "^1.5.0", 946 | "esutils": "^2.0.2", 947 | "fast-deep-equal": "^3.1.3", 948 | "file-entry-cache": "^8.0.0", 949 | "find-up": "^5.0.0", 950 | "glob-parent": "^6.0.2", 951 | "ignore": "^5.2.0", 952 | "imurmurhash": "^0.1.4", 953 | "is-glob": "^4.0.0", 954 | "json-stable-stringify-without-jsonify": "^1.0.1", 955 | "lodash.merge": "^4.6.2", 956 | "minimatch": "^3.1.2", 957 | "natural-compare": "^1.4.0", 958 | "optionator": "^0.9.3" 959 | }, 960 | "bin": { 961 | "eslint": "bin/eslint.js" 962 | }, 963 | "engines": { 964 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 965 | }, 966 | "funding": { 967 | "url": "https://eslint.org/donate" 968 | }, 969 | "peerDependencies": { 970 | "jiti": "*" 971 | }, 972 | "peerDependenciesMeta": { 973 | "jiti": { 974 | "optional": true 975 | } 976 | } 977 | }, 978 | "node_modules/eslint-config-prettier": { 979 | "version": "10.0.1", 980 | "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", 981 | "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", 982 | "dev": true, 983 | "license": "MIT", 984 | "bin": { 985 | "eslint-config-prettier": "build/bin/cli.js" 986 | }, 987 | "peerDependencies": { 988 | "eslint": ">=7.0.0" 989 | } 990 | }, 991 | "node_modules/eslint-plugin-prettier": { 992 | "version": "5.2.3", 993 | "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", 994 | "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", 995 | "dev": true, 996 | "license": "MIT", 997 | "dependencies": { 998 | "prettier-linter-helpers": "^1.0.0", 999 | "synckit": "^0.9.1" 1000 | }, 1001 | "engines": { 1002 | "node": "^14.18.0 || >=16.0.0" 1003 | }, 1004 | "funding": { 1005 | "url": "https://opencollective.com/eslint-plugin-prettier" 1006 | }, 1007 | "peerDependencies": { 1008 | "@types/eslint": ">=8.0.0", 1009 | "eslint": ">=8.0.0", 1010 | "eslint-config-prettier": "*", 1011 | "prettier": ">=3.0.0" 1012 | }, 1013 | "peerDependenciesMeta": { 1014 | "@types/eslint": { 1015 | "optional": true 1016 | }, 1017 | "eslint-config-prettier": { 1018 | "optional": true 1019 | } 1020 | } 1021 | }, 1022 | "node_modules/eslint-scope": { 1023 | "version": "8.2.0", 1024 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", 1025 | "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", 1026 | "dev": true, 1027 | "license": "BSD-2-Clause", 1028 | "dependencies": { 1029 | "esrecurse": "^4.3.0", 1030 | "estraverse": "^5.2.0" 1031 | }, 1032 | "engines": { 1033 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1034 | }, 1035 | "funding": { 1036 | "url": "https://opencollective.com/eslint" 1037 | } 1038 | }, 1039 | "node_modules/eslint-visitor-keys": { 1040 | "version": "3.4.3", 1041 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 1042 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 1043 | "dev": true, 1044 | "license": "Apache-2.0", 1045 | "engines": { 1046 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1047 | }, 1048 | "funding": { 1049 | "url": "https://opencollective.com/eslint" 1050 | } 1051 | }, 1052 | "node_modules/eslint/node_modules/eslint-visitor-keys": { 1053 | "version": "4.2.0", 1054 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", 1055 | "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", 1056 | "dev": true, 1057 | "license": "Apache-2.0", 1058 | "engines": { 1059 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1060 | }, 1061 | "funding": { 1062 | "url": "https://opencollective.com/eslint" 1063 | } 1064 | }, 1065 | "node_modules/espree": { 1066 | "version": "10.3.0", 1067 | "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", 1068 | "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", 1069 | "dev": true, 1070 | "license": "BSD-2-Clause", 1071 | "dependencies": { 1072 | "acorn": "^8.14.0", 1073 | "acorn-jsx": "^5.3.2", 1074 | "eslint-visitor-keys": "^4.2.0" 1075 | }, 1076 | "engines": { 1077 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1078 | }, 1079 | "funding": { 1080 | "url": "https://opencollective.com/eslint" 1081 | } 1082 | }, 1083 | "node_modules/espree/node_modules/eslint-visitor-keys": { 1084 | "version": "4.2.0", 1085 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", 1086 | "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", 1087 | "dev": true, 1088 | "license": "Apache-2.0", 1089 | "engines": { 1090 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1091 | }, 1092 | "funding": { 1093 | "url": "https://opencollective.com/eslint" 1094 | } 1095 | }, 1096 | "node_modules/esquery": { 1097 | "version": "1.6.0", 1098 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", 1099 | "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", 1100 | "dev": true, 1101 | "license": "BSD-3-Clause", 1102 | "dependencies": { 1103 | "estraverse": "^5.1.0" 1104 | }, 1105 | "engines": { 1106 | "node": ">=0.10" 1107 | } 1108 | }, 1109 | "node_modules/esrecurse": { 1110 | "version": "4.3.0", 1111 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1112 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1113 | "dev": true, 1114 | "license": "BSD-2-Clause", 1115 | "dependencies": { 1116 | "estraverse": "^5.2.0" 1117 | }, 1118 | "engines": { 1119 | "node": ">=4.0" 1120 | } 1121 | }, 1122 | "node_modules/estraverse": { 1123 | "version": "5.3.0", 1124 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 1125 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 1126 | "dev": true, 1127 | "license": "BSD-2-Clause", 1128 | "engines": { 1129 | "node": ">=4.0" 1130 | } 1131 | }, 1132 | "node_modules/esutils": { 1133 | "version": "2.0.3", 1134 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1135 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 1136 | "dev": true, 1137 | "license": "BSD-2-Clause", 1138 | "engines": { 1139 | "node": ">=0.10.0" 1140 | } 1141 | }, 1142 | "node_modules/fast-deep-equal": { 1143 | "version": "3.1.3", 1144 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1145 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1146 | "dev": true, 1147 | "license": "MIT" 1148 | }, 1149 | "node_modules/fast-diff": { 1150 | "version": "1.3.0", 1151 | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", 1152 | "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", 1153 | "dev": true, 1154 | "license": "Apache-2.0" 1155 | }, 1156 | "node_modules/fast-glob": { 1157 | "version": "3.3.3", 1158 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", 1159 | "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", 1160 | "dev": true, 1161 | "license": "MIT", 1162 | "dependencies": { 1163 | "@nodelib/fs.stat": "^2.0.2", 1164 | "@nodelib/fs.walk": "^1.2.3", 1165 | "glob-parent": "^5.1.2", 1166 | "merge2": "^1.3.0", 1167 | "micromatch": "^4.0.8" 1168 | }, 1169 | "engines": { 1170 | "node": ">=8.6.0" 1171 | } 1172 | }, 1173 | "node_modules/fast-glob/node_modules/glob-parent": { 1174 | "version": "5.1.2", 1175 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1176 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1177 | "dev": true, 1178 | "license": "ISC", 1179 | "dependencies": { 1180 | "is-glob": "^4.0.1" 1181 | }, 1182 | "engines": { 1183 | "node": ">= 6" 1184 | } 1185 | }, 1186 | "node_modules/fast-json-stable-stringify": { 1187 | "version": "2.1.0", 1188 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1189 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1190 | "dev": true, 1191 | "license": "MIT" 1192 | }, 1193 | "node_modules/fast-levenshtein": { 1194 | "version": "2.0.6", 1195 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1196 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 1197 | "dev": true, 1198 | "license": "MIT" 1199 | }, 1200 | "node_modules/fastq": { 1201 | "version": "1.19.0", 1202 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", 1203 | "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", 1204 | "dev": true, 1205 | "license": "ISC", 1206 | "dependencies": { 1207 | "reusify": "^1.0.4" 1208 | } 1209 | }, 1210 | "node_modules/file-entry-cache": { 1211 | "version": "8.0.0", 1212 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", 1213 | "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", 1214 | "dev": true, 1215 | "license": "MIT", 1216 | "dependencies": { 1217 | "flat-cache": "^4.0.0" 1218 | }, 1219 | "engines": { 1220 | "node": ">=16.0.0" 1221 | } 1222 | }, 1223 | "node_modules/fill-range": { 1224 | "version": "7.1.1", 1225 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 1226 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 1227 | "dev": true, 1228 | "license": "MIT", 1229 | "dependencies": { 1230 | "to-regex-range": "^5.0.1" 1231 | }, 1232 | "engines": { 1233 | "node": ">=8" 1234 | } 1235 | }, 1236 | "node_modules/find-up": { 1237 | "version": "5.0.0", 1238 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1239 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1240 | "dev": true, 1241 | "license": "MIT", 1242 | "dependencies": { 1243 | "locate-path": "^6.0.0", 1244 | "path-exists": "^4.0.0" 1245 | }, 1246 | "engines": { 1247 | "node": ">=10" 1248 | }, 1249 | "funding": { 1250 | "url": "https://github.com/sponsors/sindresorhus" 1251 | } 1252 | }, 1253 | "node_modules/flat-cache": { 1254 | "version": "4.0.1", 1255 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", 1256 | "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", 1257 | "dev": true, 1258 | "license": "MIT", 1259 | "dependencies": { 1260 | "flatted": "^3.2.9", 1261 | "keyv": "^4.5.4" 1262 | }, 1263 | "engines": { 1264 | "node": ">=16" 1265 | } 1266 | }, 1267 | "node_modules/flatted": { 1268 | "version": "3.3.2", 1269 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", 1270 | "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", 1271 | "dev": true, 1272 | "license": "ISC" 1273 | }, 1274 | "node_modules/glob-parent": { 1275 | "version": "6.0.2", 1276 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 1277 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 1278 | "dev": true, 1279 | "license": "ISC", 1280 | "dependencies": { 1281 | "is-glob": "^4.0.3" 1282 | }, 1283 | "engines": { 1284 | "node": ">=10.13.0" 1285 | } 1286 | }, 1287 | "node_modules/globals": { 1288 | "version": "14.0.0", 1289 | "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", 1290 | "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", 1291 | "dev": true, 1292 | "license": "MIT", 1293 | "engines": { 1294 | "node": ">=18" 1295 | }, 1296 | "funding": { 1297 | "url": "https://github.com/sponsors/sindresorhus" 1298 | } 1299 | }, 1300 | "node_modules/graphemer": { 1301 | "version": "1.4.0", 1302 | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 1303 | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 1304 | "dev": true, 1305 | "license": "MIT" 1306 | }, 1307 | "node_modules/has-flag": { 1308 | "version": "4.0.0", 1309 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1310 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1311 | "dev": true, 1312 | "license": "MIT", 1313 | "engines": { 1314 | "node": ">=8" 1315 | } 1316 | }, 1317 | "node_modules/ignore": { 1318 | "version": "5.3.2", 1319 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", 1320 | "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", 1321 | "dev": true, 1322 | "license": "MIT", 1323 | "engines": { 1324 | "node": ">= 4" 1325 | } 1326 | }, 1327 | "node_modules/import-fresh": { 1328 | "version": "3.3.0", 1329 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1330 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1331 | "dev": true, 1332 | "license": "MIT", 1333 | "dependencies": { 1334 | "parent-module": "^1.0.0", 1335 | "resolve-from": "^4.0.0" 1336 | }, 1337 | "engines": { 1338 | "node": ">=6" 1339 | }, 1340 | "funding": { 1341 | "url": "https://github.com/sponsors/sindresorhus" 1342 | } 1343 | }, 1344 | "node_modules/imurmurhash": { 1345 | "version": "0.1.4", 1346 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1347 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 1348 | "dev": true, 1349 | "license": "MIT", 1350 | "engines": { 1351 | "node": ">=0.8.19" 1352 | } 1353 | }, 1354 | "node_modules/is-extglob": { 1355 | "version": "2.1.1", 1356 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1357 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1358 | "dev": true, 1359 | "license": "MIT", 1360 | "engines": { 1361 | "node": ">=0.10.0" 1362 | } 1363 | }, 1364 | "node_modules/is-glob": { 1365 | "version": "4.0.3", 1366 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1367 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1368 | "dev": true, 1369 | "license": "MIT", 1370 | "dependencies": { 1371 | "is-extglob": "^2.1.1" 1372 | }, 1373 | "engines": { 1374 | "node": ">=0.10.0" 1375 | } 1376 | }, 1377 | "node_modules/is-number": { 1378 | "version": "7.0.0", 1379 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1380 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1381 | "dev": true, 1382 | "license": "MIT", 1383 | "engines": { 1384 | "node": ">=0.12.0" 1385 | } 1386 | }, 1387 | "node_modules/isexe": { 1388 | "version": "2.0.0", 1389 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1390 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1391 | "dev": true, 1392 | "license": "ISC" 1393 | }, 1394 | "node_modules/js-yaml": { 1395 | "version": "4.1.0", 1396 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1397 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1398 | "dev": true, 1399 | "license": "MIT", 1400 | "dependencies": { 1401 | "argparse": "^2.0.1" 1402 | }, 1403 | "bin": { 1404 | "js-yaml": "bin/js-yaml.js" 1405 | } 1406 | }, 1407 | "node_modules/json-buffer": { 1408 | "version": "3.0.1", 1409 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 1410 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 1411 | "dev": true, 1412 | "license": "MIT" 1413 | }, 1414 | "node_modules/json-schema-traverse": { 1415 | "version": "0.4.1", 1416 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1417 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1418 | "dev": true, 1419 | "license": "MIT" 1420 | }, 1421 | "node_modules/json-stable-stringify-without-jsonify": { 1422 | "version": "1.0.1", 1423 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1424 | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 1425 | "dev": true, 1426 | "license": "MIT" 1427 | }, 1428 | "node_modules/keyv": { 1429 | "version": "4.5.4", 1430 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", 1431 | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 1432 | "dev": true, 1433 | "license": "MIT", 1434 | "dependencies": { 1435 | "json-buffer": "3.0.1" 1436 | } 1437 | }, 1438 | "node_modules/levn": { 1439 | "version": "0.4.1", 1440 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1441 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1442 | "dev": true, 1443 | "license": "MIT", 1444 | "dependencies": { 1445 | "prelude-ls": "^1.2.1", 1446 | "type-check": "~0.4.0" 1447 | }, 1448 | "engines": { 1449 | "node": ">= 0.8.0" 1450 | } 1451 | }, 1452 | "node_modules/locate-path": { 1453 | "version": "6.0.0", 1454 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1455 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1456 | "dev": true, 1457 | "license": "MIT", 1458 | "dependencies": { 1459 | "p-locate": "^5.0.0" 1460 | }, 1461 | "engines": { 1462 | "node": ">=10" 1463 | }, 1464 | "funding": { 1465 | "url": "https://github.com/sponsors/sindresorhus" 1466 | } 1467 | }, 1468 | "node_modules/lodash.merge": { 1469 | "version": "4.6.2", 1470 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 1471 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 1472 | "dev": true, 1473 | "license": "MIT" 1474 | }, 1475 | "node_modules/make-error": { 1476 | "version": "1.3.6", 1477 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 1478 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 1479 | "dev": true, 1480 | "license": "ISC" 1481 | }, 1482 | "node_modules/merge2": { 1483 | "version": "1.4.1", 1484 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1485 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1486 | "dev": true, 1487 | "license": "MIT", 1488 | "engines": { 1489 | "node": ">= 8" 1490 | } 1491 | }, 1492 | "node_modules/micromatch": { 1493 | "version": "4.0.8", 1494 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 1495 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 1496 | "dev": true, 1497 | "license": "MIT", 1498 | "dependencies": { 1499 | "braces": "^3.0.3", 1500 | "picomatch": "^2.3.1" 1501 | }, 1502 | "engines": { 1503 | "node": ">=8.6" 1504 | } 1505 | }, 1506 | "node_modules/minimatch": { 1507 | "version": "3.1.2", 1508 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1509 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1510 | "dev": true, 1511 | "license": "ISC", 1512 | "dependencies": { 1513 | "brace-expansion": "^1.1.7" 1514 | }, 1515 | "engines": { 1516 | "node": "*" 1517 | } 1518 | }, 1519 | "node_modules/ms": { 1520 | "version": "2.1.3", 1521 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1522 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1523 | "dev": true, 1524 | "license": "MIT" 1525 | }, 1526 | "node_modules/natural-compare": { 1527 | "version": "1.4.0", 1528 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1529 | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 1530 | "dev": true, 1531 | "license": "MIT" 1532 | }, 1533 | "node_modules/optionator": { 1534 | "version": "0.9.4", 1535 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", 1536 | "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", 1537 | "dev": true, 1538 | "license": "MIT", 1539 | "dependencies": { 1540 | "deep-is": "^0.1.3", 1541 | "fast-levenshtein": "^2.0.6", 1542 | "levn": "^0.4.1", 1543 | "prelude-ls": "^1.2.1", 1544 | "type-check": "^0.4.0", 1545 | "word-wrap": "^1.2.5" 1546 | }, 1547 | "engines": { 1548 | "node": ">= 0.8.0" 1549 | } 1550 | }, 1551 | "node_modules/p-limit": { 1552 | "version": "3.1.0", 1553 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1554 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1555 | "dev": true, 1556 | "license": "MIT", 1557 | "dependencies": { 1558 | "yocto-queue": "^0.1.0" 1559 | }, 1560 | "engines": { 1561 | "node": ">=10" 1562 | }, 1563 | "funding": { 1564 | "url": "https://github.com/sponsors/sindresorhus" 1565 | } 1566 | }, 1567 | "node_modules/p-locate": { 1568 | "version": "5.0.0", 1569 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1570 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1571 | "dev": true, 1572 | "license": "MIT", 1573 | "dependencies": { 1574 | "p-limit": "^3.0.2" 1575 | }, 1576 | "engines": { 1577 | "node": ">=10" 1578 | }, 1579 | "funding": { 1580 | "url": "https://github.com/sponsors/sindresorhus" 1581 | } 1582 | }, 1583 | "node_modules/parent-module": { 1584 | "version": "1.0.1", 1585 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1586 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1587 | "dev": true, 1588 | "license": "MIT", 1589 | "dependencies": { 1590 | "callsites": "^3.0.0" 1591 | }, 1592 | "engines": { 1593 | "node": ">=6" 1594 | } 1595 | }, 1596 | "node_modules/path-exists": { 1597 | "version": "4.0.0", 1598 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1599 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1600 | "dev": true, 1601 | "license": "MIT", 1602 | "engines": { 1603 | "node": ">=8" 1604 | } 1605 | }, 1606 | "node_modules/path-key": { 1607 | "version": "3.1.1", 1608 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1609 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1610 | "dev": true, 1611 | "license": "MIT", 1612 | "engines": { 1613 | "node": ">=8" 1614 | } 1615 | }, 1616 | "node_modules/picomatch": { 1617 | "version": "2.3.1", 1618 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1619 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1620 | "dev": true, 1621 | "license": "MIT", 1622 | "engines": { 1623 | "node": ">=8.6" 1624 | }, 1625 | "funding": { 1626 | "url": "https://github.com/sponsors/jonschlinkert" 1627 | } 1628 | }, 1629 | "node_modules/prelude-ls": { 1630 | "version": "1.2.1", 1631 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 1632 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 1633 | "dev": true, 1634 | "license": "MIT", 1635 | "engines": { 1636 | "node": ">= 0.8.0" 1637 | } 1638 | }, 1639 | "node_modules/prettier": { 1640 | "version": "3.4.2", 1641 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", 1642 | "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", 1643 | "dev": true, 1644 | "license": "MIT", 1645 | "bin": { 1646 | "prettier": "bin/prettier.cjs" 1647 | }, 1648 | "engines": { 1649 | "node": ">=14" 1650 | }, 1651 | "funding": { 1652 | "url": "https://github.com/prettier/prettier?sponsor=1" 1653 | } 1654 | }, 1655 | "node_modules/prettier-linter-helpers": { 1656 | "version": "1.0.0", 1657 | "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", 1658 | "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", 1659 | "dev": true, 1660 | "license": "MIT", 1661 | "dependencies": { 1662 | "fast-diff": "^1.1.2" 1663 | }, 1664 | "engines": { 1665 | "node": ">=6.0.0" 1666 | } 1667 | }, 1668 | "node_modules/punycode": { 1669 | "version": "2.3.1", 1670 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 1671 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 1672 | "dev": true, 1673 | "license": "MIT", 1674 | "engines": { 1675 | "node": ">=6" 1676 | } 1677 | }, 1678 | "node_modules/queue-microtask": { 1679 | "version": "1.2.3", 1680 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1681 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1682 | "dev": true, 1683 | "funding": [ 1684 | { 1685 | "type": "github", 1686 | "url": "https://github.com/sponsors/feross" 1687 | }, 1688 | { 1689 | "type": "patreon", 1690 | "url": "https://www.patreon.com/feross" 1691 | }, 1692 | { 1693 | "type": "consulting", 1694 | "url": "https://feross.org/support" 1695 | } 1696 | ], 1697 | "license": "MIT" 1698 | }, 1699 | "node_modules/resolve-from": { 1700 | "version": "4.0.0", 1701 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1702 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1703 | "dev": true, 1704 | "license": "MIT", 1705 | "engines": { 1706 | "node": ">=4" 1707 | } 1708 | }, 1709 | "node_modules/reusify": { 1710 | "version": "1.0.4", 1711 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1712 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1713 | "dev": true, 1714 | "license": "MIT", 1715 | "engines": { 1716 | "iojs": ">=1.0.0", 1717 | "node": ">=0.10.0" 1718 | } 1719 | }, 1720 | "node_modules/run-parallel": { 1721 | "version": "1.2.0", 1722 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1723 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1724 | "dev": true, 1725 | "funding": [ 1726 | { 1727 | "type": "github", 1728 | "url": "https://github.com/sponsors/feross" 1729 | }, 1730 | { 1731 | "type": "patreon", 1732 | "url": "https://www.patreon.com/feross" 1733 | }, 1734 | { 1735 | "type": "consulting", 1736 | "url": "https://feross.org/support" 1737 | } 1738 | ], 1739 | "license": "MIT", 1740 | "dependencies": { 1741 | "queue-microtask": "^1.2.2" 1742 | } 1743 | }, 1744 | "node_modules/semver": { 1745 | "version": "7.7.0", 1746 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", 1747 | "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", 1748 | "license": "ISC", 1749 | "bin": { 1750 | "semver": "bin/semver.js" 1751 | }, 1752 | "engines": { 1753 | "node": ">=10" 1754 | } 1755 | }, 1756 | "node_modules/shebang-command": { 1757 | "version": "2.0.0", 1758 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1759 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1760 | "dev": true, 1761 | "license": "MIT", 1762 | "dependencies": { 1763 | "shebang-regex": "^3.0.0" 1764 | }, 1765 | "engines": { 1766 | "node": ">=8" 1767 | } 1768 | }, 1769 | "node_modules/shebang-regex": { 1770 | "version": "3.0.0", 1771 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1772 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1773 | "dev": true, 1774 | "license": "MIT", 1775 | "engines": { 1776 | "node": ">=8" 1777 | } 1778 | }, 1779 | "node_modules/strip-json-comments": { 1780 | "version": "3.1.1", 1781 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1782 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1783 | "dev": true, 1784 | "license": "MIT", 1785 | "engines": { 1786 | "node": ">=8" 1787 | }, 1788 | "funding": { 1789 | "url": "https://github.com/sponsors/sindresorhus" 1790 | } 1791 | }, 1792 | "node_modules/supports-color": { 1793 | "version": "7.2.0", 1794 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1795 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1796 | "dev": true, 1797 | "license": "MIT", 1798 | "dependencies": { 1799 | "has-flag": "^4.0.0" 1800 | }, 1801 | "engines": { 1802 | "node": ">=8" 1803 | } 1804 | }, 1805 | "node_modules/synckit": { 1806 | "version": "0.9.2", 1807 | "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", 1808 | "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", 1809 | "dev": true, 1810 | "license": "MIT", 1811 | "dependencies": { 1812 | "@pkgr/core": "^0.1.0", 1813 | "tslib": "^2.6.2" 1814 | }, 1815 | "engines": { 1816 | "node": "^14.18.0 || >=16.0.0" 1817 | }, 1818 | "funding": { 1819 | "url": "https://opencollective.com/unts" 1820 | } 1821 | }, 1822 | "node_modules/to-regex-range": { 1823 | "version": "5.0.1", 1824 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1825 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1826 | "dev": true, 1827 | "license": "MIT", 1828 | "dependencies": { 1829 | "is-number": "^7.0.0" 1830 | }, 1831 | "engines": { 1832 | "node": ">=8.0" 1833 | } 1834 | }, 1835 | "node_modules/ts-api-utils": { 1836 | "version": "2.0.0", 1837 | "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", 1838 | "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", 1839 | "dev": true, 1840 | "license": "MIT", 1841 | "engines": { 1842 | "node": ">=18.12" 1843 | }, 1844 | "peerDependencies": { 1845 | "typescript": ">=4.8.4" 1846 | } 1847 | }, 1848 | "node_modules/ts-node": { 1849 | "version": "10.9.2", 1850 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", 1851 | "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", 1852 | "dev": true, 1853 | "license": "MIT", 1854 | "dependencies": { 1855 | "@cspotcode/source-map-support": "^0.8.0", 1856 | "@tsconfig/node10": "^1.0.7", 1857 | "@tsconfig/node12": "^1.0.7", 1858 | "@tsconfig/node14": "^1.0.0", 1859 | "@tsconfig/node16": "^1.0.2", 1860 | "acorn": "^8.4.1", 1861 | "acorn-walk": "^8.1.1", 1862 | "arg": "^4.1.0", 1863 | "create-require": "^1.1.0", 1864 | "diff": "^4.0.1", 1865 | "make-error": "^1.1.1", 1866 | "v8-compile-cache-lib": "^3.0.1", 1867 | "yn": "3.1.1" 1868 | }, 1869 | "bin": { 1870 | "ts-node": "dist/bin.js", 1871 | "ts-node-cwd": "dist/bin-cwd.js", 1872 | "ts-node-esm": "dist/bin-esm.js", 1873 | "ts-node-script": "dist/bin-script.js", 1874 | "ts-node-transpile-only": "dist/bin-transpile.js", 1875 | "ts-script": "dist/bin-script-deprecated.js" 1876 | }, 1877 | "peerDependencies": { 1878 | "@swc/core": ">=1.2.50", 1879 | "@swc/wasm": ">=1.2.50", 1880 | "@types/node": "*", 1881 | "typescript": ">=2.7" 1882 | }, 1883 | "peerDependenciesMeta": { 1884 | "@swc/core": { 1885 | "optional": true 1886 | }, 1887 | "@swc/wasm": { 1888 | "optional": true 1889 | } 1890 | } 1891 | }, 1892 | "node_modules/tslib": { 1893 | "version": "2.8.1", 1894 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 1895 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 1896 | "dev": true, 1897 | "license": "0BSD" 1898 | }, 1899 | "node_modules/tunnel": { 1900 | "version": "0.0.6", 1901 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 1902 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", 1903 | "license": "MIT", 1904 | "engines": { 1905 | "node": ">=0.6.11 <=0.7.0 || >=0.7.3" 1906 | } 1907 | }, 1908 | "node_modules/type-check": { 1909 | "version": "0.4.0", 1910 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 1911 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 1912 | "dev": true, 1913 | "license": "MIT", 1914 | "dependencies": { 1915 | "prelude-ls": "^1.2.1" 1916 | }, 1917 | "engines": { 1918 | "node": ">= 0.8.0" 1919 | } 1920 | }, 1921 | "node_modules/typescript": { 1922 | "version": "5.7.3", 1923 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", 1924 | "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", 1925 | "dev": true, 1926 | "license": "Apache-2.0", 1927 | "bin": { 1928 | "tsc": "bin/tsc", 1929 | "tsserver": "bin/tsserver" 1930 | }, 1931 | "engines": { 1932 | "node": ">=14.17" 1933 | } 1934 | }, 1935 | "node_modules/typescript-eslint": { 1936 | "version": "8.22.0", 1937 | "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.22.0.tgz", 1938 | "integrity": "sha512-Y2rj210FW1Wb6TWXzQc5+P+EWI9/zdS57hLEc0gnyuvdzWo8+Y8brKlbj0muejonhMI/xAZCnZZwjbIfv1CkOw==", 1939 | "dev": true, 1940 | "license": "MIT", 1941 | "dependencies": { 1942 | "@typescript-eslint/eslint-plugin": "8.22.0", 1943 | "@typescript-eslint/parser": "8.22.0", 1944 | "@typescript-eslint/utils": "8.22.0" 1945 | }, 1946 | "engines": { 1947 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1948 | }, 1949 | "funding": { 1950 | "type": "opencollective", 1951 | "url": "https://opencollective.com/typescript-eslint" 1952 | }, 1953 | "peerDependencies": { 1954 | "eslint": "^8.57.0 || ^9.0.0", 1955 | "typescript": ">=4.8.4 <5.8.0" 1956 | } 1957 | }, 1958 | "node_modules/undici": { 1959 | "version": "5.29.0", 1960 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", 1961 | "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", 1962 | "license": "MIT", 1963 | "dependencies": { 1964 | "@fastify/busboy": "^2.0.0" 1965 | }, 1966 | "engines": { 1967 | "node": ">=14.0" 1968 | } 1969 | }, 1970 | "node_modules/undici-types": { 1971 | "version": "6.20.0", 1972 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", 1973 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", 1974 | "dev": true, 1975 | "license": "MIT" 1976 | }, 1977 | "node_modules/uri-js": { 1978 | "version": "4.4.1", 1979 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1980 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1981 | "dev": true, 1982 | "license": "BSD-2-Clause", 1983 | "dependencies": { 1984 | "punycode": "^2.1.0" 1985 | } 1986 | }, 1987 | "node_modules/v8-compile-cache-lib": { 1988 | "version": "3.0.1", 1989 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 1990 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 1991 | "dev": true, 1992 | "license": "MIT" 1993 | }, 1994 | "node_modules/which": { 1995 | "version": "2.0.2", 1996 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1997 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1998 | "dev": true, 1999 | "license": "ISC", 2000 | "dependencies": { 2001 | "isexe": "^2.0.0" 2002 | }, 2003 | "bin": { 2004 | "node-which": "bin/node-which" 2005 | }, 2006 | "engines": { 2007 | "node": ">= 8" 2008 | } 2009 | }, 2010 | "node_modules/word-wrap": { 2011 | "version": "1.2.5", 2012 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", 2013 | "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", 2014 | "dev": true, 2015 | "license": "MIT", 2016 | "engines": { 2017 | "node": ">=0.10.0" 2018 | } 2019 | }, 2020 | "node_modules/yaml": { 2021 | "version": "2.7.0", 2022 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", 2023 | "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", 2024 | "license": "ISC", 2025 | "bin": { 2026 | "yaml": "bin.mjs" 2027 | }, 2028 | "engines": { 2029 | "node": ">= 14" 2030 | } 2031 | }, 2032 | "node_modules/yn": { 2033 | "version": "3.1.1", 2034 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 2035 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 2036 | "dev": true, 2037 | "license": "MIT", 2038 | "engines": { 2039 | "node": ">=6" 2040 | } 2041 | }, 2042 | "node_modules/yocto-queue": { 2043 | "version": "0.1.0", 2044 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 2045 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 2046 | "dev": true, 2047 | "license": "MIT", 2048 | "engines": { 2049 | "node": ">=10" 2050 | }, 2051 | "funding": { 2052 | "url": "https://github.com/sponsors/sindresorhus" 2053 | } 2054 | } 2055 | } 2056 | } 2057 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deploy-appengine", 3 | "version": "2.1.5", 4 | "description": "Github Action: Deploy to Google App Engine", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "ncc build -m src/main.ts", 8 | "lint": "eslint .", 9 | "format": "eslint . --fix", 10 | "test": "bash ./bin/runTests.sh" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/google-github-actions/deploy-appengine" 15 | }, 16 | "keywords": [ 17 | "actions", 18 | "google cloud", 19 | "app engine", 20 | "deploy", 21 | "app" 22 | ], 23 | "author": "Google LLC", 24 | "license": "Apache-2.0", 25 | "dependencies": { 26 | "@actions/core": "^1.11.1", 27 | "@actions/exec": "^1.1.1", 28 | "@google-github-actions/actions-utils": "^0.8.6", 29 | "@google-github-actions/setup-cloud-sdk": "^1.1.9", 30 | "yaml": "^2.7.0" 31 | }, 32 | "devDependencies": { 33 | "@eslint/eslintrc": "^3.2.0", 34 | "@eslint/js": "^9.19.0", 35 | "@types/node": "^22.13.0", 36 | "@typescript-eslint/eslint-plugin": "^8.22.0", 37 | "@typescript-eslint/parser": "^8.22.0", 38 | "@vercel/ncc": "^0.38.3", 39 | "eslint-config-prettier": "^10.0.1", 40 | "eslint-plugin-prettier": "^5.2.3", 41 | "eslint": "^9.19.0", 42 | "prettier": "^3.4.2", 43 | "ts-node": "^10.9.2", 44 | "typescript-eslint": "^8.22.0", 45 | "typescript": "^5.7.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { promises as fs } from 'fs'; 18 | import path from 'path'; 19 | 20 | import YAML from 'yaml'; 21 | 22 | import { 23 | addPath, 24 | debug as logDebug, 25 | getInput, 26 | info as logInfo, 27 | setFailed, 28 | setOutput, 29 | warning as logWarning, 30 | } from '@actions/core'; 31 | import { getExecOutput } from '@actions/exec'; 32 | import * as toolCache from '@actions/tool-cache'; 33 | 34 | import { 35 | authenticateGcloudSDK, 36 | getLatestGcloudSDKVersion, 37 | getToolCommand, 38 | installComponent as installGcloudComponent, 39 | installGcloudSDK, 40 | isInstalled as isGcloudInstalled, 41 | } from '@google-github-actions/setup-cloud-sdk'; 42 | 43 | import { 44 | errorMessage, 45 | isPinnedToHead, 46 | KVPair, 47 | parseBoolean, 48 | parseCSV, 49 | parseFlags, 50 | parseKVString, 51 | pinnedToHeadWarning, 52 | presence, 53 | } from '@google-github-actions/actions-utils'; 54 | 55 | import { parseDeployResponse, parseDescribeResponse } from './output-parser'; 56 | 57 | // Do not listen to the linter - this can NOT be rewritten as an ES6 import 58 | // statement. 59 | const { version: appVersion } = require('../package.json'); 60 | 61 | // isDebug returns true if runner debugging or step debugging is enabled. 62 | const isDebug = 63 | parseBoolean(process.env.ACTIONS_RUNNER_DEBUG) || parseBoolean(process.env.ACTIONS_STEP_DEBUG); 64 | 65 | // originalAppYamlContents and originalAppYamlPath is a reference to the 66 | // original app.yaml contents and path. 67 | let originalAppYamlContents: string, originalAppYamlPath: string; 68 | 69 | /** 70 | * Executes the main action. It includes the main business logic and is the 71 | * primary entry point. It is documented inline. 72 | */ 73 | export async function run(): Promise { 74 | // Register metrics 75 | process.env.CLOUDSDK_CORE_DISABLE_PROMPTS = '1'; 76 | process.env.CLOUDSDK_METRICS_ENVIRONMENT = 'github-actions-deploy-cloudrun'; 77 | process.env.CLOUDSDK_METRICS_ENVIRONMENT_VERSION = appVersion; 78 | process.env.GOOGLE_APIS_USER_AGENT = `google-github-actions:deploy-appengine/${appVersion}`; 79 | 80 | // Warn if pinned to HEAD 81 | if (isPinnedToHead()) { 82 | logWarning(pinnedToHeadWarning('v1')); 83 | } 84 | 85 | try { 86 | // Get action inputs. 87 | const projectId = presence(getInput('project_id')); 88 | const cwd = presence(getInput('working_directory')); 89 | const deliverables = parseDeliverables(getInput('deliverables') || 'app.yaml'); 90 | const buildEnvVars = parseKVString(getInput('build_env_vars')); 91 | const envVars = parseKVString(getInput('env_vars')); 92 | const imageUrl = presence(getInput('image_url')); 93 | const version = presence(getInput('version')); 94 | const promote = parseBoolean(getInput('promote'), true); 95 | const flags = presence(getInput('flags')); 96 | const gcloudVersion = await computeGcloudVersion(getInput('gcloud_version')); 97 | const gcloudComponent = presence(getInput('gcloud_component')); 98 | 99 | // Validate gcloud component input 100 | if (gcloudComponent && gcloudComponent !== 'alpha' && gcloudComponent !== 'beta') { 101 | throw new Error(`invalid value for gcloud_component: ${gcloudComponent}`); 102 | } 103 | 104 | // Change working directory 105 | if (cwd) { 106 | logInfo(`Changing into working directory: ${cwd}`); 107 | process.chdir(cwd.trim()); 108 | } 109 | 110 | // Validate deliverables 111 | await Promise.all( 112 | deliverables.map((deliverable) => { 113 | return new Promise((resolve, reject) => { 114 | fs.access(deliverable) 115 | .then(resolve) 116 | .catch((err) => { 117 | const rejection = 118 | `Deliverable ${deliverable} not found or the ` + 119 | `caller does not have permission, check "working_directory" ` + 120 | `and "deliverables" inputs: ${err}`; 121 | reject(new Error(rejection)); 122 | }); 123 | }); 124 | }), 125 | ); 126 | 127 | // Modify app.yaml if envvars were given. 128 | if ( 129 | (envVars && Object.keys(envVars).length > 0) || 130 | (buildEnvVars && Object.keys(buildEnvVars).length > 0) 131 | ) { 132 | logDebug(`Updating env_variables or build_env_variables`); 133 | 134 | originalAppYamlPath = await findAppYaml(deliverables); 135 | originalAppYamlContents = await fs.readFile(originalAppYamlPath, 'utf8'); 136 | const parsed = YAML.parse(originalAppYamlContents); 137 | 138 | parsed.build_env_variables = updateEnvVars(parsed.build_env_variables, buildEnvVars); 139 | if (!Object.keys(parsed.build_env_variables).length) { 140 | delete parsed.build_env_variables; 141 | } 142 | 143 | parsed.env_variables = updateEnvVars(parsed.env_variables, envVars); 144 | if (!Object.keys(parsed.env_variables).length) { 145 | delete parsed.env_variables; 146 | } 147 | 148 | const newAppYaml = YAML.stringify(parsed); 149 | logDebug(`Updated ${originalAppYamlPath}:\n\n${newAppYaml}\n`); 150 | await fs.writeFile(originalAppYamlPath, newAppYaml, { flag: 'w' }); 151 | } 152 | 153 | const toolCommand = getToolCommand(); 154 | 155 | // Create app engine gcloud cmd. 156 | let appDeployCmd = ['app', 'deploy', '--format', 'json', ...deliverables]; 157 | 158 | // Add gcloud flags. 159 | if (projectId) { 160 | appDeployCmd.push('--project', projectId); 161 | } 162 | if (imageUrl) { 163 | appDeployCmd.push('--image-url', imageUrl); 164 | } 165 | if (version) { 166 | appDeployCmd.push('--version', version); 167 | } 168 | if (promote) { 169 | appDeployCmd.push('--promote'); 170 | } else { 171 | appDeployCmd.push('--no-promote'); 172 | } 173 | 174 | // Add optional flags 175 | if (flags) { 176 | const flagList = parseFlags(flags); 177 | if (flagList) appDeployCmd = appDeployCmd.concat(flagList); 178 | } 179 | 180 | // Install gcloud if not already installed. 181 | if (!isGcloudInstalled(gcloudVersion)) { 182 | await installGcloudSDK(gcloudVersion); 183 | } else { 184 | const toolPath = toolCache.find('gcloud', gcloudVersion); 185 | addPath(path.join(toolPath, 'bin')); 186 | } 187 | 188 | // Install gcloud component if needed and prepend the command 189 | if (gcloudComponent) { 190 | await installGcloudComponent(gcloudComponent); 191 | appDeployCmd.unshift(gcloudComponent); 192 | } 193 | 194 | // Authenticate - this comes from google-github-actions/auth. 195 | const credFile = process.env.GOOGLE_GHA_CREDS_PATH; 196 | if (credFile) { 197 | await authenticateGcloudSDK(credFile); 198 | logInfo('Successfully authenticated'); 199 | } else { 200 | logWarning('No authentication found, authenticate with `google-github-actions/auth`.'); 201 | } 202 | 203 | const options = { silent: !isDebug, ignoreReturnCode: true }; 204 | const deployCommandString = `${toolCommand} ${appDeployCmd.join(' ')}`; 205 | logInfo(`Running: ${deployCommandString}`); 206 | 207 | // Get output of gcloud cmd. 208 | const deployOutput = await getExecOutput(toolCommand, appDeployCmd, options); 209 | if (deployOutput.exitCode !== 0) { 210 | const errMsg = 211 | deployOutput.stderr || `command exited ${deployOutput.exitCode}, but stderr had no output`; 212 | throw new Error(`failed to execute gcloud command \`${deployCommandString}\`: ${errMsg}`); 213 | } 214 | 215 | // Extract the version from the response. 216 | const deployResponse = parseDeployResponse(deployOutput.stdout); 217 | logDebug(`Deployed new version: ${JSON.stringify(deployResponse)}`); 218 | 219 | // Look up the new version to get metadata. 220 | const appVersionsDescribeCmd = ['app', 'versions', 'describe', '--format', 'json']; 221 | appVersionsDescribeCmd.push('--project', deployResponse.project); 222 | appVersionsDescribeCmd.push('--service', deployResponse.service); 223 | appVersionsDescribeCmd.push(deployResponse.versionID); 224 | 225 | // Prepend component to command (it was already installed above) 226 | if (gcloudComponent) { 227 | appVersionsDescribeCmd.unshift(gcloudComponent); 228 | } 229 | 230 | const describeCommandString = `${toolCommand} ${appVersionsDescribeCmd.join(' ')}`; 231 | logInfo(`Running: ${describeCommandString}`); 232 | 233 | const describeOutput = await getExecOutput(toolCommand, appVersionsDescribeCmd, options); 234 | if (describeOutput.exitCode !== 0) { 235 | const errMsg = 236 | describeOutput.stderr || 237 | `command exited ${describeOutput.exitCode}, but stderr had no output`; 238 | throw new Error(`failed to execute gcloud command \`${describeCommandString}\`: ${errMsg}`); 239 | } 240 | 241 | // Parse the describe response. 242 | const describeResponse = parseDescribeResponse(describeOutput.stdout); 243 | 244 | // Set outputs. 245 | setOutput('name', describeResponse.name); 246 | setOutput('runtime', describeResponse.runtime); 247 | setOutput('service_account_email', describeResponse.serviceAccountEmail); 248 | setOutput('serving_status', describeResponse.servingStatus); 249 | setOutput('version_id', describeResponse.versionID); 250 | setOutput('version_url', describeResponse.versionURL); 251 | 252 | // Backwards compatability. 253 | setOutput('serviceAccountEmail', describeResponse.serviceAccountEmail); 254 | setOutput('versionURL', describeResponse.versionURL); 255 | setOutput('url', describeResponse.versionURL); 256 | } catch (err) { 257 | const msg = errorMessage(err); 258 | setFailed(`google-github-actions/deploy-appengine failed with: ${msg}`); 259 | } finally { 260 | if (originalAppYamlPath && originalAppYamlContents) { 261 | logDebug(`Restoring original ${originalAppYamlPath} contents`); 262 | await fs.writeFile(originalAppYamlPath, originalAppYamlContents, { flag: 'w' }); 263 | } 264 | } 265 | } 266 | 267 | /** 268 | * computeGcloudVersion computes the appropriate gcloud version for the given 269 | * string. 270 | */ 271 | async function computeGcloudVersion(str: string): Promise { 272 | str = (str || '').trim(); 273 | if (str === '' || str === 'latest') { 274 | return await getLatestGcloudSDKVersion(); 275 | } 276 | return str; 277 | } 278 | 279 | /** 280 | * findAppYaml finds the best app.yaml or app.yml file in the list of 281 | * deliverables. It returns the file's path. If no file is found, it throws an 282 | * error. 283 | * 284 | * @return [string] 285 | */ 286 | export async function findAppYaml(list: string[]): Promise { 287 | for (let i = 0; i < list.length; i++) { 288 | const pth = list[i]; 289 | 290 | try { 291 | const contents = await fs.readFile(pth, 'utf8'); 292 | const parsed = YAML.parse(contents); 293 | 294 | // Per https://cloud.google.com/appengine/docs/standard/reference/app-yaml, 295 | // the only required field is "runtime". 296 | if (parsed && parsed['runtime']) { 297 | return pth; 298 | } 299 | } catch (err) { 300 | const msg = errorMessage(err); 301 | logDebug(`Failed to parse ${pth} as YAML: ${msg}`); 302 | } 303 | } 304 | 305 | throw new Error(`Could not find an appyaml in [${list.join(', ')}]`); 306 | } 307 | 308 | /** 309 | * updateEnvVars updates the environment variables and returns the modified 310 | * contents. The incoming environment variables take precendence over the old 311 | * ones. 312 | * 313 | * @param existing The existing KEY=VALUE pairs to parse. 314 | * @param envVars The input environment variables. 315 | */ 316 | export function updateEnvVars(existing: KVPair | undefined, envVars: KVPair | undefined): KVPair { 317 | return Object.assign({}, existing, envVars); 318 | } 319 | 320 | /** 321 | * parseDeliverables parses the given input string as a space-separated or 322 | * comma-separated list of deliverables. 323 | * 324 | * @param input The given input 325 | * @return [string[]] 326 | */ 327 | export function parseDeliverables(input: string): string[] { 328 | const onSpaces = input.split(' '); 329 | 330 | const final: string[] = []; 331 | for (let i = 0; i < onSpaces.length; i++) { 332 | const entry = onSpaces[i].trim(); 333 | if (entry !== '') { 334 | const entries = parseCSV(entry); 335 | for (let j = 0; j < entries.length; j++) { 336 | const csvEntry = entries[j]; 337 | if (csvEntry !== '') { 338 | final.push(csvEntry); 339 | } 340 | } 341 | } 342 | } 343 | return final; 344 | } 345 | 346 | // Execute this as the entrypoint when requested. 347 | if (require.main === module) { 348 | run(); 349 | } 350 | -------------------------------------------------------------------------------- /src/output-parser.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { errorMessage, presence } from '@google-github-actions/actions-utils'; 18 | 19 | /** 20 | * DeployResponse is the output from a "gcloud app deploy". 21 | */ 22 | export interface DeployResponse { 23 | // project is the project ID returned from the deployment. 24 | project: string; 25 | 26 | // service is the name of the deployed service. 27 | service: string; 28 | 29 | // versionID is the unique version ID. 30 | versionID: string; 31 | } 32 | 33 | /** 34 | * parseDeployResponse parses the JSON stdout from a deployment. 35 | * 36 | * @param string Standard output in JSON format. 37 | */ 38 | export function parseDeployResponse(stdout: string | undefined): DeployResponse { 39 | try { 40 | stdout = presence(stdout); 41 | if (!stdout) { 42 | throw new Error(`empty response`); 43 | } 44 | 45 | const outputJSON = JSON.parse(stdout); 46 | const version = outputJSON?.versions?.at(0); 47 | if (!version) { 48 | throw new Error(`missing or empty "versions"`); 49 | } 50 | 51 | return { 52 | project: version['project'], 53 | service: version['service'], 54 | versionID: version['id'], 55 | }; 56 | } catch (err) { 57 | const msg = errorMessage(err); 58 | throw new Error(`failed to parse deploy response: ${msg}, stdout: ${stdout}`); 59 | } 60 | } 61 | 62 | /** 63 | * DescribeResponse is the response from a "gcloud app versions describe". 64 | */ 65 | export interface DescribeResponse { 66 | // name is the full resource name of the deployment (e.g. 67 | // projects/p/services/default/versions/123). 68 | name: string; 69 | 70 | // runtime is the decided runtime. 71 | runtime: string; 72 | 73 | // serviceAccountEmail is the email address of the runtime service account for 74 | // the deployment. 75 | serviceAccountEmail: string; 76 | 77 | // servingStatus is the current serving status. 78 | servingStatus: string; 79 | 80 | // id is the unique version ID. 81 | versionID: string; 82 | 83 | // versionURL is the full HTTPS URL to the version. 84 | versionURL: string; 85 | } 86 | 87 | /** 88 | * parseDescribeResponse parses the output from a description. 89 | * 90 | * @param string Standard output in JSON format. 91 | */ 92 | export function parseDescribeResponse(stdout: string | undefined): DescribeResponse { 93 | try { 94 | stdout = presence(stdout); 95 | if (!stdout || stdout === '{}' || stdout === '[]') { 96 | throw new Error(`empty response`); 97 | } 98 | 99 | const version = JSON.parse(stdout); 100 | if (!version) { 101 | throw new Error(`empty JSON response`); 102 | } 103 | 104 | return { 105 | name: version['name'], 106 | runtime: version['runtime'], 107 | serviceAccountEmail: version['serviceAccount'], 108 | servingStatus: version['servingStatus'], 109 | versionID: version['id'], 110 | versionURL: version['versionUrl'], 111 | }; 112 | } catch (err) { 113 | const msg = errorMessage(err); 114 | throw new Error(`failed to parse describe response: ${msg}, stdout: ${stdout}`); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /tests/main.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { mock, test } from 'node:test'; 18 | import assert from 'node:assert'; 19 | 20 | import YAML from 'yaml'; 21 | import * as path from 'path'; 22 | import * as fs from 'fs/promises'; 23 | 24 | import * as core from '@actions/core'; 25 | import * as exec from '@actions/exec'; 26 | import * as setupGcloud from '@google-github-actions/setup-cloud-sdk'; 27 | import { TestToolCache } from '@google-github-actions/setup-cloud-sdk'; 28 | import { 29 | assertMembers, 30 | forceRemove, 31 | KVPair, 32 | randomFilepath, 33 | writeSecureFile, 34 | } from '@google-github-actions/actions-utils'; 35 | 36 | import { run, findAppYaml, updateEnvVars, parseDeliverables } from '../src/main'; 37 | import * as outputParser from '../src/output-parser'; 38 | 39 | // These are mock data for github actions inputs, where camel case is expected. 40 | const fakeInputs = { 41 | project_id: '', 42 | working_directory: '', 43 | deliverables: 'example-app/app.yaml', 44 | image_url: '', 45 | env_vars: '', 46 | version: '', 47 | promote: '', 48 | flags: '', 49 | }; 50 | 51 | const defaultMocks = ( 52 | m: typeof mock, 53 | overrideInputs?: Record, 54 | ): Record => { 55 | const inputs = Object.assign({}, fakeInputs, overrideInputs); 56 | return { 57 | startGroup: m.method(core, 'startGroup', () => {}), 58 | endGroup: m.method(core, 'endGroup', () => {}), 59 | group: m.method(core, 'group', () => {}), 60 | logDebug: m.method(core, 'debug', () => {}), 61 | logError: m.method(core, 'error', () => {}), 62 | logInfo: m.method(core, 'info', () => {}), 63 | logNotice: m.method(core, 'notice', () => {}), 64 | logWarning: m.method(core, 'warning', () => {}), 65 | exportVariable: m.method(core, 'exportVariable', () => {}), 66 | setSecret: m.method(core, 'setSecret', () => {}), 67 | addPath: m.method(core, 'addPath', () => {}), 68 | setOutput: m.method(core, 'setOutput', () => {}), 69 | setFailed: m.method(core, 'setFailed', (msg: string) => { 70 | throw new Error(msg); 71 | }), 72 | getBooleanInput: m.method(core, 'getBooleanInput', (name: string) => { 73 | return !!inputs[name]; 74 | }), 75 | getMultilineInput: m.method(core, 'getMultilineInput', (name: string) => { 76 | return inputs[name]; 77 | }), 78 | getInput: m.method(core, 'getInput', (name: string) => { 79 | return inputs[name]; 80 | }), 81 | 82 | authenticateGcloudSDK: m.method(setupGcloud, 'authenticateGcloudSDK', () => {}), 83 | isInstalled: m.method(setupGcloud, 'isInstalled', () => { 84 | return true; 85 | }), 86 | installGcloudSDK: m.method(setupGcloud, 'installGcloudSDK', async () => { 87 | return '1.2.3'; 88 | }), 89 | installComponent: m.method(setupGcloud, 'installComponent', () => {}), 90 | getLatestGcloudSDKVersion: m.method(setupGcloud, 'getLatestGcloudSDKVersion', () => { 91 | return '1.2.3'; 92 | }), 93 | 94 | getExecOutput: m.method(exec, 'getExecOutput', async () => { 95 | return { 96 | exitCode: 0, 97 | stderr: '', 98 | stdout: '{}', 99 | }; 100 | }), 101 | 102 | parseDeployResponse: m.method(outputParser, 'parseDeployResponse', async () => { 103 | return { 104 | exitCode: 0, 105 | stderr: '', 106 | name: 'a', 107 | link: 'b', 108 | }; 109 | }), 110 | 111 | parseDescribeResponse: m.method(outputParser, 'parseDescribeResponse', async () => { 112 | return { 113 | exitCode: 0, 114 | stderr: '', 115 | name: 'a', 116 | link: 'b', 117 | }; 118 | }), 119 | }; 120 | }; 121 | 122 | test('#run', { concurrency: true }, async (suite) => { 123 | suite.beforeEach(async () => { 124 | await TestToolCache.start(); 125 | }); 126 | 127 | suite.afterEach(async () => { 128 | await TestToolCache.stop(); 129 | }); 130 | 131 | await suite.test('installs the gcloud SDK if it is not already installed', async (t) => { 132 | const mocks = defaultMocks(t.mock); 133 | t.mock.method(setupGcloud, 'isInstalled', () => { 134 | return false; 135 | }); 136 | 137 | await run(); 138 | 139 | assert.deepStrictEqual(mocks.installGcloudSDK.mock.callCount(), 1); 140 | }); 141 | 142 | await suite.test('uses the cached gcloud SDK if it was already installed', async (t) => { 143 | const mocks = defaultMocks(t.mock); 144 | t.mock.method(setupGcloud, 'isInstalled', () => { 145 | return true; 146 | }); 147 | 148 | await run(); 149 | 150 | assert.deepStrictEqual(mocks.installGcloudSDK.mock.callCount(), 0); 151 | }); 152 | 153 | await suite.test('uses default components without gcloud_component flag', async (t) => { 154 | const mocks = defaultMocks(t.mock); 155 | await run(); 156 | assert.deepStrictEqual(mocks.installComponent.mock.callCount(), 0); 157 | }); 158 | 159 | await suite.test('throws error with invalid gcloud component flag', async (t) => { 160 | defaultMocks(t.mock, { 161 | gcloud_component: 'wrong_value', 162 | }); 163 | await assert.rejects(run, 'invalid input received for gcloud_component: wrong_value'); 164 | }); 165 | 166 | await suite.test('installs alpha component with alpha flag', async (t) => { 167 | const mocks = defaultMocks(t.mock, { 168 | gcloud_component: 'alpha', 169 | }); 170 | 171 | await run(); 172 | 173 | assertMembers(mocks.installComponent.mock.calls?.at(0)?.arguments, ['alpha']); 174 | }); 175 | 176 | await suite.test('installs beta component with beta flag', async (t) => { 177 | const mocks = defaultMocks(t.mock, { 178 | gcloud_component: 'beta', 179 | }); 180 | 181 | await run(); 182 | 183 | assertMembers(mocks.installComponent.mock.calls?.at(0)?.arguments, ['beta']); 184 | }); 185 | 186 | await suite.test('sets project if given', async (t) => { 187 | const mocks = defaultMocks(t.mock, { 188 | project_id: 'my-test-project', 189 | }); 190 | 191 | await run(); 192 | 193 | assertMembers(mocks.getExecOutput.mock.calls?.at(0)?.arguments?.at(1), [ 194 | '--project', 195 | 'my-test-project', 196 | ]); 197 | }); 198 | 199 | await suite.test('sets image-url if given', async (t) => { 200 | const mocks = defaultMocks(t.mock, { 201 | image_url: 'gcr.io/foo/bar', 202 | }); 203 | 204 | await run(); 205 | 206 | assertMembers(mocks.getExecOutput.mock.calls?.at(0)?.arguments?.at(1), [ 207 | '--image-url', 208 | 'gcr.io/foo/bar', 209 | ]); 210 | }); 211 | 212 | await suite.test('sets version if given', async (t) => { 213 | const mocks = defaultMocks(t.mock, { 214 | version: '123', 215 | }); 216 | 217 | await run(); 218 | 219 | assertMembers(mocks.getExecOutput.mock.calls?.at(0)?.arguments?.at(1), ['--version', '123']); 220 | }); 221 | 222 | await suite.test('sets promote if given', async (t) => { 223 | const mocks = defaultMocks(t.mock, { 224 | promote: 'true', 225 | }); 226 | 227 | await run(); 228 | 229 | assertMembers(mocks.getExecOutput.mock.calls?.at(0)?.arguments?.at(1), ['--promote']); 230 | }); 231 | 232 | await suite.test('sets promote if given the empty string', async (t) => { 233 | const mocks = defaultMocks(t.mock, { 234 | promote: '', 235 | }); 236 | 237 | await run(); 238 | 239 | assertMembers(mocks.getExecOutput.mock.calls?.at(0)?.arguments?.at(1), ['--promote']); 240 | }); 241 | 242 | await suite.test('sets no-promote if given', async (t) => { 243 | const mocks = defaultMocks(t.mock, { 244 | promote: 'false', 245 | }); 246 | 247 | await run(); 248 | 249 | assertMembers(mocks.getExecOutput.mock.calls?.at(0)?.arguments?.at(1), ['--no-promote']); 250 | }); 251 | 252 | await suite.test('sets flags if given', async (t) => { 253 | const mocks = defaultMocks(t.mock, { 254 | flags: '--log-http --foo=bar', 255 | }); 256 | 257 | await run(); 258 | 259 | assertMembers(mocks.getExecOutput.mock.calls?.at(0)?.arguments?.at(1), [ 260 | '--log-http', 261 | '--foo', 262 | 'bar', 263 | ]); 264 | }); 265 | 266 | await suite.test('sets outputs', async (t) => { 267 | const mocks = defaultMocks(t.mock); 268 | 269 | t.mock.method(outputParser, 'parseDescribeResponse', () => { 270 | return { 271 | name: 'test-name', 272 | }; 273 | }); 274 | 275 | await run(); 276 | 277 | const args = mocks.setOutput.mock.calls[0].arguments; 278 | assert.deepStrictEqual(args, ['name', 'test-name']); 279 | }); 280 | }); 281 | 282 | test('#findAppYaml', { concurrency: true }, async (suite) => { 283 | let parent: string; 284 | 285 | suite.beforeEach(async () => { 286 | parent = randomFilepath(); 287 | await fs.mkdir(parent, { recursive: true }); 288 | }); 289 | 290 | suite.afterEach(async () => { 291 | forceRemove(parent); 292 | }); 293 | 294 | const cases: { 295 | name: string; 296 | files: Record; 297 | expected?: string; 298 | error?: string; 299 | }[] = [ 300 | { 301 | name: 'no deployables', 302 | files: {}, 303 | error: 'could not find an appyaml', 304 | }, 305 | { 306 | name: 'no appyaml single', 307 | files: { 308 | 'my-file': ` 309 | this is a file 310 | `, 311 | }, 312 | error: 'could not find an appyaml', 313 | }, 314 | { 315 | name: 'no appyaml multiple', 316 | files: { 317 | 'my-file': ` 318 | this is a file 319 | `, 320 | 'my-other-file': ` 321 | this is another file 322 | `, 323 | }, 324 | error: 'could not find an appyaml', 325 | }, 326 | { 327 | name: 'single appyaml', 328 | files: { 329 | 'app-dev.yaml': ` 330 | runtime: 'node' 331 | `, 332 | }, 333 | expected: 'app-dev.yaml', 334 | }, 335 | { 336 | name: 'multiple files with appyaml', 337 | files: { 338 | 'my-file': ` 339 | this is a file 340 | `, 341 | 'my-other-file': ` 342 | this is another file 343 | `, 344 | 'app-prod.yaml': ` 345 | runtime: 'node' 346 | `, 347 | }, 348 | expected: 'app-prod.yaml', 349 | }, 350 | { 351 | name: 'multiple appyaml uses first', 352 | files: { 353 | 'app.yaml': ` 354 | runtime: 'node' 355 | service: 'my-service' 356 | `, 357 | 'app-dev.yaml': ` 358 | runtime: 'node' 359 | service: 'my-service' 360 | env: 'flex' 361 | `, 362 | 'app-prod.yaml': ` 363 | runtime: 'node' 364 | service: 'my-service' 365 | env: 'standard' 366 | `, 367 | }, 368 | expected: 'app.yaml', 369 | }, 370 | ]; 371 | 372 | for await (const tc of cases) { 373 | await suite.test(tc.name, async () => { 374 | Object.keys(tc.files).map((key) => { 375 | const newKey = path.join(parent, key); 376 | tc.files[newKey] = tc.files[key]; 377 | delete tc.files[key]; 378 | }); 379 | 380 | await Promise.all( 381 | Object.entries(tc.files).map(async ([pth, contents]) => { 382 | await writeSecureFile(pth, contents); 383 | }), 384 | ); 385 | 386 | const filepaths = Object.keys(tc.files); 387 | if (tc.error) { 388 | await assert.rejects(async () => { 389 | await findAppYaml(filepaths); 390 | }, tc.error); 391 | } else if (tc.expected) { 392 | const expected = path.join(parent, tc.expected); 393 | const result = await findAppYaml(filepaths); 394 | assert.deepStrictEqual(result, expected); 395 | } 396 | }); 397 | } 398 | }); 399 | 400 | test('#updateEnvVars', { concurrency: true }, async (suite) => { 401 | const cases: { 402 | name: string; 403 | existing: KVPair; 404 | envVars: KVPair; 405 | expected: KVPair; 406 | }[] = [ 407 | { 408 | name: 'empty existing, empty input', 409 | existing: {}, 410 | envVars: {}, 411 | expected: {}, 412 | }, 413 | { 414 | name: 'empty existing, given input', 415 | existing: {}, 416 | envVars: { 417 | FOO: 'bar', 418 | ZIP: 'zap', 419 | }, 420 | expected: { 421 | FOO: 'bar', 422 | ZIP: 'zap', 423 | }, 424 | }, 425 | { 426 | name: 'existing, given input', 427 | existing: { 428 | EXISTING: 'one', 429 | }, 430 | envVars: { 431 | FOO: 'bar', 432 | ZIP: 'zap', 433 | }, 434 | expected: { 435 | EXISTING: 'one', 436 | FOO: 'bar', 437 | ZIP: 'zap', 438 | }, 439 | }, 440 | { 441 | name: 'overwrites', 442 | existing: { 443 | FOO: 'bar', 444 | }, 445 | envVars: { 446 | FOO: 'zip', 447 | }, 448 | expected: { 449 | FOO: 'zip', 450 | }, 451 | }, 452 | ]; 453 | 454 | for await (const tc of cases) { 455 | await suite.test(tc.name, async () => { 456 | const result = updateEnvVars(tc.existing, tc.envVars); 457 | assert.deepStrictEqual(result, tc.expected); 458 | }); 459 | } 460 | 461 | await suite.test('handles an yaml with variables', async () => { 462 | const parsed = YAML.parse(` 463 | env_variables: 464 | FOO: 'bar' 465 | `); 466 | 467 | const result = updateEnvVars(parsed.env_variables, { ZIP: 'zap' }); 468 | assert.deepStrictEqual(result, { 469 | FOO: 'bar', 470 | ZIP: 'zap', 471 | }); 472 | }); 473 | 474 | await suite.test('handles an yaml without variables', async () => { 475 | const parsed = YAML.parse(`{}`); 476 | 477 | const result = updateEnvVars(parsed.env_variables, { ZIP: 'zap' }); 478 | assert.deepStrictEqual(result, { 479 | ZIP: 'zap', 480 | }); 481 | }); 482 | }); 483 | 484 | test('#parseDeliverables', { concurrency: true }, async (suite) => { 485 | const cases = [ 486 | { 487 | name: 'empty', 488 | input: '', 489 | expected: [], 490 | }, 491 | { 492 | name: 'single', 493 | input: 'app.yaml', 494 | expected: ['app.yaml'], 495 | }, 496 | { 497 | name: 'multi space', 498 | input: 'app.yaml foo.yaml', 499 | expected: ['app.yaml', 'foo.yaml'], 500 | }, 501 | { 502 | name: 'multi comma', 503 | input: 'app.yaml, foo.yaml', 504 | expected: ['app.yaml', 'foo.yaml'], 505 | }, 506 | { 507 | name: 'multi comma space', 508 | input: 'app.yaml,foo.yaml, bar.yaml', 509 | expected: ['app.yaml', 'foo.yaml', 'bar.yaml'], 510 | }, 511 | { 512 | name: 'multi-line comma space', 513 | input: 'app.yaml,\nfoo.yaml, bar.yaml', 514 | expected: ['app.yaml', 'foo.yaml', 'bar.yaml'], 515 | }, 516 | ]; 517 | 518 | for await (const tc of cases) { 519 | await suite.test(tc.name, async () => { 520 | const result = parseDeliverables(tc.input); 521 | assert.deepStrictEqual(result, tc.expected); 522 | }); 523 | } 524 | }); 525 | -------------------------------------------------------------------------------- /tests/output-parser.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { test } from 'node:test'; 18 | import assert from 'node:assert'; 19 | 20 | import { parseDeployResponse, parseDescribeResponse } from '../src/output-parser'; 21 | 22 | test('#parseDeployResponse', { concurrency: true }, async (suite) => { 23 | const cases = [ 24 | { 25 | name: 'with promote', 26 | stdout: ` 27 | { 28 | "configs": [], 29 | "versions": [ 30 | { 31 | "environment": null, 32 | "id": "20221117t121206", 33 | "last_deployed_time": null, 34 | "project": "my-project", 35 | "service": "default", 36 | "service_account": null, 37 | "traffic_split": null, 38 | "version": { 39 | "createTime": "2022-11-17T17:14:10Z", 40 | "createdBy": "foo@bar.com", 41 | "deployment": { 42 | "files": { 43 | ".gcloudignore": { 44 | "sha1Sum": "8c826ff92b4fb4374cd1f482438a2492a7b62444", 45 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/8c826ff92b4fb4374cd1f482438a2492a7b62444" 46 | }, 47 | "app.yaml": { 48 | "sha1Sum": "84a6883be145d40d7f34901050f403f51faba608", 49 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/84a6883be145d40d7f34901050f403f51faba608" 50 | }, 51 | "index.js": { 52 | "sha1Sum": "4314a54ca7a14bc00f48959c620dc784c87d1c11", 53 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/4314a54ca7a14bc00f48959c620dc784c87d1c11" 54 | }, 55 | "package-lock.json": { 56 | "sha1Sum": "4e28e642ad76490edd5a9c390557dc3319f59f8e", 57 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/4e28e642ad76490edd5a9c390557dc3319f59f8e" 58 | }, 59 | "package.json": { 60 | "sha1Sum": "c5ad06c6ba994ae32e2ba71c9d5c861f6ff12389", 61 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/c5ad06c6ba994ae32e2ba71c9d5c861f6ff12389" 62 | }, 63 | "source-context.json": { 64 | "sha1Sum": "0f90a4df44bdad2786bbd635b25c70faf2b8bc8f", 65 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/0f90a4df44bdad2786bbd635b25c70faf2b8bc8f" 66 | } 67 | } 68 | }, 69 | "diskUsageBytes": "4180802", 70 | "env": "standard", 71 | "handlers": [ 72 | { 73 | "authFailAction": "AUTH_FAIL_ACTION_REDIRECT", 74 | "login": "LOGIN_OPTIONAL", 75 | "script": { 76 | "scriptPath": "auto" 77 | }, 78 | "securityLevel": "SECURE_OPTIONAL", 79 | "urlRegex": ".*" 80 | } 81 | ], 82 | "id": "20221117t121206", 83 | "instanceClass": "F1", 84 | "name": "apps/my-project/services/default/versions/20221117t121206", 85 | "network": {}, 86 | "runtime": "nodejs20", 87 | "runtimeChannel": "default", 88 | "serviceAccount": "my-project@appspot.gserviceaccount.com", 89 | "servingStatus": "SERVING", 90 | "threadsafe": true, 91 | "versionUrl": "https://20221117t121206-dot-my-project.appspot.com" 92 | } 93 | } 94 | ] 95 | } 96 | `, 97 | expected: { 98 | project: 'my-project', 99 | service: 'default', 100 | versionID: '20221117t121206', 101 | }, 102 | }, 103 | { 104 | name: 'with --version', 105 | stdout: ` 106 | { 107 | "configs": [], 108 | "versions": [ 109 | { 110 | "environment": null, 111 | "id": "123", 112 | "last_deployed_time": null, 113 | "project": "my-project", 114 | "service": "default", 115 | "service_account": null, 116 | "traffic_split": null, 117 | "version": { 118 | "createTime": "2022-11-17T17:18:16Z", 119 | "createdBy": "foo@bar.com", 120 | "deployment": { 121 | "files": { 122 | "app.yaml": { 123 | "sha1Sum": "84a6883be145d40d7f34901050f403f51faba608", 124 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/84a6883be145d40d7f34901050f403f51faba608" 125 | } 126 | } 127 | }, 128 | "diskUsageBytes": "4197856", 129 | "env": "standard", 130 | "handlers": [ 131 | { 132 | "authFailAction": "AUTH_FAIL_ACTION_REDIRECT", 133 | "login": "LOGIN_OPTIONAL", 134 | "script": { 135 | "scriptPath": "auto" 136 | }, 137 | "securityLevel": "SECURE_OPTIONAL", 138 | "urlRegex": ".*" 139 | } 140 | ], 141 | "id": "123", 142 | "instanceClass": "F1", 143 | "name": "apps/my-project/services/default/versions/123", 144 | "network": {}, 145 | "runtime": "nodejs20", 146 | "runtimeChannel": "default", 147 | "serviceAccount": "my-project@appspot.gserviceaccount.com", 148 | "servingStatus": "SERVING", 149 | "threadsafe": true, 150 | "versionUrl": "https://123-dot-my-project.appspot.com" 151 | } 152 | } 153 | ] 154 | } 155 | `, 156 | expected: { 157 | project: 'my-project', 158 | service: 'default', 159 | versionID: '123', 160 | }, 161 | }, 162 | { 163 | name: 'with --no-promote', 164 | stdout: ` 165 | { 166 | "configs": [], 167 | "versions": [ 168 | { 169 | "environment": null, 170 | "id": "123", 171 | "last_deployed_time": null, 172 | "project": "my-project", 173 | "service": "default", 174 | "service_account": null, 175 | "traffic_split": null, 176 | "version": null 177 | } 178 | ] 179 | } 180 | `, 181 | expected: { 182 | project: 'my-project', 183 | service: 'default', 184 | versionID: '123', 185 | }, 186 | }, 187 | { 188 | name: 'empty stdout', 189 | stdout: ``, 190 | error: `empty response`, 191 | }, 192 | { 193 | name: 'empty array from stdout', 194 | stdout: `[]`, 195 | error: `missing or empty "versions"`, 196 | }, 197 | { 198 | name: 'empty object from stdout', 199 | stdout: `{}`, 200 | error: `missing or empty "versions"`, 201 | }, 202 | { 203 | name: 'invalid text from stdout', 204 | stdout: `Some text to fail`, 205 | error: `failed to parse deploy response: unexpected token`, 206 | }, 207 | ]; 208 | 209 | for await (const tc of cases) { 210 | await suite.test(tc.name, async () => { 211 | if (tc.error) { 212 | assert.throws(() => { 213 | parseDeployResponse(tc.stdout); 214 | }, tc.error); 215 | } else { 216 | const result = parseDeployResponse(tc.stdout); 217 | assert.deepStrictEqual(result, tc.expected); 218 | } 219 | }); 220 | } 221 | }); 222 | 223 | test('#parseDescribeResponse', { concurrency: true }, async (suite) => { 224 | const cases = [ 225 | { 226 | name: 'with response', 227 | stdout: ` 228 | { 229 | "createTime": "2022-12-15T15:26:11Z", 230 | "createdBy": "foo@bar.com", 231 | "deployment": { 232 | "files": { 233 | "app.yaml": { 234 | "sha1Sum": "84a6883be145d40d7f34901050f403f51faba608", 235 | "sourceUrl": "https://storage.googleapis.com/staging.my-project.appspot.com/84a6883be145d40d7f34901050f403f51faba608" 236 | } 237 | } 238 | }, 239 | "diskUsageBytes": "4288402", 240 | "env": "standard", 241 | "id": "20221215t102539", 242 | "instanceClass": "F1", 243 | "name": "apps/my-project/services/default/versions/20221215t102539", 244 | "network": {}, 245 | "runtime": "nodejs20", 246 | "runtimeChannel": "default", 247 | "serviceAccount": "my-project@appspot.gserviceaccount.com", 248 | "servingStatus": "SERVING", 249 | "threadsafe": true, 250 | "versionUrl": "https://20221215t102539-dot-my-project.appspot.com" 251 | } 252 | `, 253 | expected: { 254 | name: 'apps/my-project/services/default/versions/20221215t102539', 255 | runtime: 'nodejs20', 256 | serviceAccountEmail: 'my-project@appspot.gserviceaccount.com', 257 | servingStatus: 'SERVING', 258 | versionID: '20221215t102539', 259 | versionURL: 'https://20221215t102539-dot-my-project.appspot.com', 260 | }, 261 | }, 262 | { 263 | name: 'empty stdout', 264 | stdout: ``, 265 | error: `empty response`, 266 | }, 267 | { 268 | name: 'empty array from stdout', 269 | stdout: `[]`, 270 | error: `empty response`, 271 | }, 272 | { 273 | name: 'empty object from stdout', 274 | stdout: `{}`, 275 | error: `empty response`, 276 | }, 277 | { 278 | name: 'invalid text from stdout', 279 | stdout: `Some text to fail`, 280 | error: `failed to parse describe response: unexpected token`, 281 | }, 282 | ]; 283 | 284 | for await (const tc of cases) { 285 | await suite.test(tc.name, () => { 286 | if (tc.error) { 287 | assert.throws(() => { 288 | parseDescribeResponse(tc.stdout); 289 | }, tc.error); 290 | } else { 291 | const result = parseDescribeResponse(tc.stdout); 292 | assert.deepStrictEqual(result, tc.expected); 293 | } 294 | }); 295 | } 296 | }); 297 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | { 17 | "compilerOptions": { 18 | "alwaysStrict": true, 19 | "target": "es6", 20 | "module": "commonjs", 21 | "lib": [ 22 | "es6" 23 | ], 24 | "outDir": "./dist", 25 | "rootDir": "./src", 26 | "strict": true, 27 | "noImplicitAny": true, 28 | "esModuleInterop": true 29 | }, 30 | "exclude": ["node_modules/", "tests/"] 31 | } 32 | --------------------------------------------------------------------------------