├── .eslintrc.js ├── .github └── workflows │ ├── build-test.yaml │ ├── echo-1.yaml │ ├── echo-2.yaml │ ├── failing.yml │ ├── long-running.yml │ ├── named-run.yml │ ├── retrieve-logs.yml │ └── timeout.yml ├── .gitignore ├── .nvmrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── action.yaml ├── dist └── index.js ├── package.json ├── src ├── debug.ts ├── main.ts ├── utils.ts ├── workflow-handler.ts └── workflow-logs-handler.ts ├── tsconfig.json └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es6: true 4 | }, 5 | extends: [ 6 | 'eslint:recommended', 7 | 'plugin:@typescript-eslint/eslint-recommended', 8 | 'plugin:@typescript-eslint/recommended' 9 | ], 10 | parser: '@typescript-eslint/parser', 11 | parserOptions: { 12 | 'project': 'tsconfig.json', 13 | 'sourceType': 'module' 14 | }, 15 | plugins: [ 16 | '@typescript-eslint' 17 | ], 18 | rules: { 19 | 'no-trailing-spaces': 'error', 20 | 'no-console': 'off', 21 | 22 | '@typescript-eslint/semi': ['error', 'never'], 23 | '@typescript-eslint/indent': ['error', 2], 24 | '@typescript-eslint/member-delimiter-style': 'off', 25 | '@typescript-eslint/no-explicit-any': 'warn', 26 | '@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': 'next|res|req' }], 27 | 28 | 'func-call-spacing': 'off', 29 | '@typescript-eslint/func-call-spacing': 'error', 30 | 31 | 'quotes': 'off', 32 | '@typescript-eslint/quotes': ['error', 'single'], 33 | 34 | 'comma-spacing': 'off', 35 | '@typescript-eslint/comma-spacing': ['error'] 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yaml: -------------------------------------------------------------------------------- 1 | name: Build & Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out repository 13 | uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: '20' 17 | - name: Build with ncc 18 | run: | 19 | npm install -g yarn 20 | yarn install 21 | yarn run build 22 | - name: Archive dist 23 | uses: actions/upload-artifact@v3 24 | with: 25 | name: build 26 | path: dist 27 | 28 | echo-1-test: 29 | needs: [build] 30 | runs-on: ubuntu-latest 31 | name: "echo-1-test [trigger|by workflow name]" 32 | steps: 33 | - name: Check out repository 34 | uses: actions/checkout@v3 35 | - name: Download dist 36 | uses: actions/download-artifact@v3 37 | with: 38 | name: build 39 | path: dist 40 | - name: Invoke echo 1 workflow using this action (do not wait for completion) 41 | uses: ./ 42 | with: 43 | workflow: Message Echo 1 44 | token: ${{ secrets.PERSONAL_TOKEN }} 45 | inputs: '{"message": "blah blah"}' 46 | wait-for-completion: false 47 | 48 | echo-2-test: 49 | needs: [build] 50 | runs-on: ubuntu-latest 51 | name: "echo-2-test [trigger|by workflow filename]" 52 | steps: 53 | - name: Check out repository 54 | uses: actions/checkout@v3 55 | - name: Download dist 56 | uses: actions/download-artifact@v3 57 | with: 58 | name: build 59 | path: dist 60 | - name: Invoke echo 2 workflow using this action 61 | uses: ./ 62 | with: 63 | workflow: echo-2.yaml 64 | token: ${{ secrets.PERSONAL_TOKEN }} 65 | wait-for-completion: false 66 | 67 | # - name: Invoke echo 1 workflow by id 68 | # uses: ./ 69 | # with: 70 | # workflow: '1854247' 71 | # token: ${{ secrets.PERSONAL_TOKEN }} 72 | # inputs: '{"message": "Mango jam"}' 73 | # wait-for-completion: false 74 | 75 | long-running-test: 76 | needs: [build] 77 | runs-on: ubuntu-latest 78 | name: "long-running-test [trigger+wait|by workflow filename|shoud succeed]" 79 | steps: 80 | - name: Check out repository 81 | uses: actions/checkout@v3 82 | - name: Download dist 83 | uses: actions/download-artifact@v3 84 | with: 85 | name: build 86 | path: dist 87 | - name: Invoke 'long-running' workflow and wait for result using this action 88 | id: long-running-workflow 89 | uses: ./ 90 | with: 91 | workflow: long-running.yml 92 | token: ${{ secrets.PERSONAL_TOKEN }} 93 | wait-for-completion-interval: 10s 94 | wait-for-completion-timeout: 5m 95 | display-workflow-run-url-interval: 10s 96 | display-workflow-run-url-timeout: 5m 97 | continue-on-error: true 98 | - uses: nick-invision/assert-action@v1 99 | with: 100 | expected: success 101 | actual: ${{ steps.long-running-workflow.outputs.workflow-conclusion }} 102 | - uses: nick-invision/assert-action@v1 103 | with: 104 | expected: success 105 | actual: ${{ steps.long-running-workflow.outcome }} 106 | 107 | failing-test: 108 | needs: [build] 109 | runs-on: ubuntu-latest 110 | name: "failing-test [trigger+wait|by workflow filename|should report failure]" 111 | steps: 112 | - name: Check out repository 113 | uses: actions/checkout@v3 114 | - name: Download dist 115 | uses: actions/download-artifact@v3 116 | with: 117 | name: build 118 | path: dist 119 | - name: Invoke 'failing' workflow and wait for result using this action 120 | id: failing-workflow 121 | uses: ./ 122 | with: 123 | workflow: failing.yml 124 | token: ${{ secrets.PERSONAL_TOKEN }} 125 | wait-for-completion-interval: 10s 126 | wait-for-completion-timeout: 60s 127 | display-workflow-run-url-interval: 10s 128 | display-workflow-run-url-timeout: 60s 129 | continue-on-error: true 130 | - run: echo "worflow-conclusion=${{ steps.failing-workflow.outputs.workflow-conclusion }}" 131 | - uses: nick-invision/assert-action@v1 132 | with: 133 | expected: failure 134 | actual: ${{ steps.failing-workflow.outputs.workflow-conclusion }} 135 | - uses: nick-invision/assert-action@v1 136 | with: 137 | expected: failure 138 | actual: ${{ steps.failing-workflow.outcome }} 139 | 140 | timeout-test: 141 | needs: [build] 142 | runs-on: ubuntu-latest 143 | name: "timeout-test [trigger+wait|by workflow filename|should report timed_out]" 144 | steps: 145 | - name: Check out repository 146 | uses: actions/checkout@v3 147 | - name: Download dist 148 | uses: actions/download-artifact@v3 149 | with: 150 | name: build 151 | path: dist 152 | - name: Invoke 'timeout' workflow and wait for result using this action 153 | id: timeout-workflow 154 | uses: ./ 155 | with: 156 | workflow: timeout.yml 157 | token: ${{ secrets.PERSONAL_TOKEN }} 158 | wait-for-completion-interval: 10s 159 | wait-for-completion-timeout: 30s 160 | display-workflow-run-url-interval: 10s 161 | display-workflow-run-url-timeout: 30s 162 | continue-on-error: true 163 | - uses: nick-invision/assert-action@v1 164 | with: 165 | expected: timed_out 166 | actual: ${{ steps.timeout-workflow.outputs.workflow-conclusion }} 167 | - uses: nick-invision/assert-action@v1 168 | with: 169 | expected: failure 170 | actual: ${{ steps.timeout-workflow.outcome }} 171 | 172 | print-workflow-logs-test: 173 | needs: [build] 174 | runs-on: ubuntu-latest 175 | name: "print-workflow-logs-test [trigger+wait|by workflow filename|print logs|should report timed_out]" 176 | steps: 177 | - name: Check out repository 178 | uses: actions/checkout@v3 179 | - name: Download dist 180 | uses: actions/download-artifact@v3 181 | with: 182 | name: build 183 | path: dist 184 | - name: Invoke 'retrieve-logs' workflow and wait for result using this action 185 | id: print-workflow-logs 186 | uses: ./ 187 | with: 188 | workflow: retrieve-logs.yml 189 | token: ${{ secrets.PERSONAL_TOKEN }} 190 | wait-for-completion-interval: 10s 191 | wait-for-completion-timeout: 120s 192 | display-workflow-run-url-interval: 10s 193 | display-workflow-run-url-timeout: 120s 194 | workflow-logs: print 195 | continue-on-error: true 196 | - uses: nick-invision/assert-action@v1 197 | with: 198 | expected: timed_out 199 | actual: ${{ steps.print-workflow-logs.outputs.workflow-conclusion }} 200 | - uses: nick-invision/assert-action@v1 201 | with: 202 | expected: failure 203 | actual: ${{ steps.print-workflow-logs.outcome }} 204 | # TODO: add assertions on logs 205 | 206 | # - name: Invoke external workflow using this action 207 | # uses: ./ 208 | # with: 209 | # workflow: Deploy To Kubernetes 210 | # repo: benc-uk/dapr-store 211 | # token: ${{ secrets.PERSONAL_TOKEN }} 212 | # ref: master 213 | 214 | parallel-runs-test: 215 | needs: [build] 216 | runs-on: ubuntu-latest 217 | name: "parallel-runs-test [trigger+wait|by workflow filename|should succeed]" 218 | strategy: 219 | fail-fast: false 220 | matrix: 221 | environment: 222 | - trunk 223 | - staging 224 | env: 225 | RUN_NAME: ${{ github.repository }}/actions/runs/${{ github.run_id }}/envs/${{ matrix.environment }} 226 | steps: 227 | - name: Check out repository 228 | uses: actions/checkout@v3 229 | - name: Download dist 230 | uses: actions/download-artifact@v3 231 | with: 232 | name: build 233 | path: dist 234 | - name: Invoke 'named-run' workflow for this environment and wait for result using this action 235 | id: named-run-workflow 236 | uses: ./ 237 | with: 238 | workflow: named-run.yml 239 | token: ${{ secrets.PERSONAL_TOKEN }} 240 | run-name: ${{ env.RUN_NAME }} 241 | wait-for-completion-interval: 10s 242 | wait-for-completion-timeout: 120s 243 | display-workflow-run-url-interval: 10s 244 | display-workflow-run-url-timeout: 120s 245 | workflow-logs: json-output 246 | inputs: >- 247 | { 248 | "run-name": "${{ env.RUN_NAME }}", 249 | "environment": "${{ matrix.environment }}" 250 | } 251 | continue-on-error: true 252 | - uses: nick-invision/assert-action@v1 253 | with: 254 | expected: success 255 | actual: ${{ steps.named-run-workflow.outputs.workflow-conclusion }} 256 | - uses: nick-invision/assert-action@v1 257 | with: 258 | expected: success 259 | actual: ${{ steps.named-run-workflow.outcome }} 260 | - uses: nick-invision/assert-action@v1 261 | env: 262 | EXPECTED_LOG_MESSAGE: "### Env: ${{ matrix.environment }} ###" 263 | with: 264 | expected: true 265 | actual: ${{ contains(fromJson(steps.named-run-workflow.outputs.workflow-logs).echo.*.message, env.EXPECTED_LOG_MESSAGE) }} 266 | 267 | deploy: 268 | needs: 269 | - echo-1-test 270 | - echo-2-test 271 | - long-running-test 272 | - failing-test 273 | - timeout-test 274 | - print-workflow-logs-test 275 | - parallel-runs-test 276 | runs-on: ubuntu-latest 277 | steps: 278 | - name: Check out repository 279 | uses: actions/checkout@v3 280 | - name: Download dist 281 | uses: actions/download-artifact@v3 282 | with: 283 | name: build 284 | path: dist 285 | - name: Update repo with build 286 | uses: mikeal/publish-to-github-action@master 287 | env: 288 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 289 | 290 | -------------------------------------------------------------------------------- /.github/workflows/echo-1.yaml: -------------------------------------------------------------------------------- 1 | name: Message Echo 1 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | message: 7 | description: "Message to echo" 8 | required: true 9 | # No default 10 | 11 | jobs: 12 | echo: 13 | runs-on: ubuntu-latest 14 | environment: 15 | name: foo 16 | url: www.google.com 17 | steps: 18 | - name: Echo message 19 | run: echo '${{ github.event.inputs.message }}' 20 | -------------------------------------------------------------------------------- /.github/workflows/echo-2.yaml: -------------------------------------------------------------------------------- 1 | name: Message Echo 2 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | message: 7 | description: "Message to echo" 8 | required: false 9 | default: "this is echo 2" 10 | 11 | jobs: 12 | echo: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Echo message 16 | run: echo '${{ github.event.inputs.message }}' 17 | -------------------------------------------------------------------------------- /.github/workflows/failing.yml: -------------------------------------------------------------------------------- 1 | name: Failing 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | echo: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Fail 11 | run: exit 1 12 | -------------------------------------------------------------------------------- /.github/workflows/long-running.yml: -------------------------------------------------------------------------------- 1 | name: Long running 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | echo: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Sleep 11 | run: sleep 10s 12 | -------------------------------------------------------------------------------- /.github/workflows/named-run.yml: -------------------------------------------------------------------------------- 1 | name: Named run 2 | run-name: ${{ inputs.run-name }} 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | run-name: 8 | description: 'The distinct run name used to retrieve the run ID. Defaults to the workflow name' 9 | type: string 10 | required: false 11 | environment: 12 | description: 'The environment name' 13 | type: string 14 | required: true 15 | 16 | jobs: 17 | echo: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Sleep 21 | run: sleep 10s 22 | - name: Echo message 23 | run: | 24 | echo '### Env: ${{ github.event.inputs.environment }} ###' 25 | -------------------------------------------------------------------------------- /.github/workflows/retrieve-logs.yml: -------------------------------------------------------------------------------- 1 | name: Retrieve logs 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | echo: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Echo message 11 | run: | 12 | for i in {1..500} 13 | do 14 | echo "Hello $i" 15 | sleep 0.1 16 | done 17 | 18 | timeout: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Sleep 22 | run: sleep 1200s 23 | 24 | more-real-example: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/setup-node@v3 28 | with: 29 | node-version: '20' 30 | - name: Some command with npx 31 | run: | 32 | npx create-react-app example-app 33 | -------------------------------------------------------------------------------- /.github/workflows/timeout.yml: -------------------------------------------------------------------------------- 1 | name: Timeout 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | wait: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Sleep 11 | run: sleep 120s 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | .idea -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": "explicit" 4 | }, 5 | "eslint.format.enable": true, 6 | "[typescript]": { 7 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 8 | } 9 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Ben Coleman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action for Dispatching Workflows 2 | 3 | This action triggers another GitHub Actions workflow, using the `workflow_dispatch` event. 4 | The workflow must be configured for this event type e.g. `on: [workflow_dispatch]` 5 | 6 | This allows you to chain workflows, the classic use case is have a CI build workflow, trigger a CD release/deploy workflow when it completes. Allowing you to maintain separate workflows for CI and CD, and pass data between them as required. 7 | 8 | For details of the `workflow_dispatch` even see [this blog post introducing this type of trigger](https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/) 9 | 10 | *Note 1.* The GitHub UI will report flows triggered by this action as "manually triggered" even though they have been run programmatically via another workflow and the API 11 | 12 | *Note 2.* If you want to reference the target workflow by ID, you will need to list them with the following REST API call `curl https://api.github.com/repos/{{owner}}/{{repo}}/actions/workflows -H "Authorization: token {{pat-token}}"` 13 | 14 | *This action is a fork of `aurelien-baudet/workflow-dispatch` with a better management of run-name option and node20 support.* 15 | 16 | ## Inputs 17 | 18 | ### `workflow` 19 | 20 | > **Required.** The name or the filename or ID of the workflow to trigger and run. 21 | 22 | ### `token` 23 | 24 | > **Required.** A GitHub access token (PAT) with write access to the repo in question. 25 | > 26 | > **NOTE.** The automatically provided token e.g. `${{ secrets.GITHUB_TOKEN }}` can not be used, GitHub prevents this token from being able to fire the `workflow_dispatch` and `repository_dispatch` event. [The reasons are explained in the docs](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token). 27 | > The solution is to manually create a PAT and store it as a secret e.g. `${{ secrets.PERSONAL_TOKEN }}` 28 | 29 | ### `inputs` 30 | 31 | > **Optional.** The inputs to pass to the workflow (if any are configured), this must be a JSON encoded string, e.g. `{ "myInput": "foobar" }`. 32 | > 33 | > All values must be strings (even if they are used as booleans or numbers in the triggered workflow). The triggered workflow should use `fromJson` function to get the right type 34 | 35 | ### `ref` 36 | 37 | > **Optional.** The Git reference used with the triggered workflow run. The reference can be a branch, tag, or a commit SHA. If omitted the context ref of the triggering workflow is used. If you want to trigger on pull requests and run the target workflow in the context of the pull request branch, set the ref to `${{ github.event.pull_request.head.ref }}` 38 | 39 | ### `repo` 40 | 41 | > **Optional.** The default behavior is to trigger workflows in the same repo as the triggering workflow, if you wish to trigger in another GitHub repo "externally", then provide the owner + repo name with slash between them e.g. `microsoft/vscode` 42 | 43 | ### `run-name` (since 3.0.0) 44 | 45 | > **Optional.** The default behavior is to get the remote run ID based on the latest workflow name and date, if you have multiple of the same workflow running at the same time it can point to an incorrect run id. 46 | > To prevent from this, you can specify a unique run name to fetch the concerned run ID. It will also requires you to set that same value as an input for your remote workflow (See the [corresponding example](#invoke-workflow-with-a-unique-run-name-since-300)) 47 | 48 | ### `wait-for-completion` 49 | 50 | > **Optional.** If `true`, this action will actively poll the workflow run to get the result of the triggered workflow. It is enabled by default. If the triggered workflow fails due to either `failure`, `timed_out` or `cancelled` then the step that has triggered the other workflow will be marked as failed too. 51 | 52 | ### `wait-for-completion-timeout` 53 | 54 | > **Optional.** The time to wait to mark triggered workflow has timed out. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `wait-for-completion` is `false`. Default is `1h` 55 | 56 | ### `wait-for-completion-interval` 57 | 58 | > **Optional.** The time to wait between two polls for getting run status. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `wait-for-completion` is `false`. Default is `1m`. 59 | > 60 | > **/!\ Do not use a value that is too small to avoid `API Rate limit exceeded`** 61 | 62 | ### `display-workflow-run-url` 63 | 64 | > **Optional.** If `true`, it displays in logs the URL of the triggered workflow. It is useful to follow the progress of the triggered workflow. It is enabled by default. 65 | 66 | ### `display-workflow-run-url-timeout` 67 | 68 | > **Optional.** The time to wait for getting the workflow run URL. If the timeout is reached, it doesn't fail and continues. Displaying the workflow URL is just for information purpose. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `display-workflow-run-url` is `false`. Default is `10m` 69 | 70 | ### `display-workflow-run-url-interval` 71 | 72 | > **Optional.** The time to wait between two polls for getting workflow run URL. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `display-workflow-run-url` is `false`. Default is `1m`. 73 | > 74 | > **/!\ Do not use a value that is too small to avoid `API Rate limit exceeded`** 75 | 76 | ### `workflow-logs` 77 | 78 | > **Optional.** Indicate what to do with logs of the triggered workflow: 79 | > 80 | > * `print`: Retrieve the logs for each job of the triggered workflow and print into the logs of the job that triggered the workflow. 81 | > * `ignore`: Do not retrieve log of triggered workflow at all (default). 82 | > 83 | > Only available when `wait-for-completion` is `true`. 84 | > 85 | > Default is `ignore`. 86 | 87 | ## Outputs 88 | 89 | ### `workflow-id` 90 | 91 | > The ID of the worflow run that has been triggered. 92 | 93 | ### `workflow-url` 94 | 95 | > The URL of the workflow run that has been triggered. It may be undefined if the URL couldn't be retrieved (timeout reached) or if `wait-for-completion` and `display-workflow-run-url` are > both `false` 96 | 97 | ### `workflow-conclusion` 98 | 99 | > The result of the triggered workflow. May be one of `success`, `failure`, `cancelled`, `timed_out`, `skipped`, `neutral`, `action_required`. The step in your workflow will fail if the triggered workflow completes with `failure`, `cancelled` or `timed_out`. Other workflow conlusion are considered success. 100 | > Only available if `wait-for-completion` is `true` 101 | 102 | ### `workflow-logs` 103 | 104 | > The logs of the triggered workflow based if `inputs.workflow-logs` is set to either `output`, or `json-output`. 105 | > Based on the value, result will be: 106 | > 107 | > * `output`: Multiline string 108 | > 109 | > ```log 110 | > | 111 | > | 112 | > ... 113 | > ``` 114 | > 115 | > * `json-output`: JSON string 116 | > 117 | > ```json 118 | > { 119 | > "": [ 120 | > { 121 | > "datetime": "", 122 | > "message": "" 123 | > }, 124 | > { 125 | > "datetime": "", 126 | > "message": "" 127 | > } 128 | > ] 129 | > } 130 | > ``` 131 | 132 | ## Example usage 133 | 134 | ### Invoke workflow without inputs. Wait for result 135 | 136 | ```yaml 137 | - name: Invoke workflow without inputs. Wait for result 138 | uses: the-actions-org/workflow-dispatch@v4 139 | with: 140 | workflow: My Workflow 141 | token: ${{ secrets.PERSONAL_TOKEN }} 142 | ``` 143 | 144 | ### Invoke workflow without inputs. Don't wait for result 145 | 146 | ```yaml 147 | - name: Invoke workflow without inputs. Don't wait for result 148 | uses: the-actions-org/workflow-dispatch@v4 149 | with: 150 | workflow: My Workflow 151 | token: ${{ secrets.PERSONAL_TOKEN }} 152 | wait-for-completion: false 153 | ``` 154 | 155 | ### Invoke workflow with inputs 156 | 157 | ```yaml 158 | - name: Invoke workflow with inputs 159 | uses: the-actions-org/workflow-dispatch@v4 160 | with: 161 | workflow: Another Workflow 162 | token: ${{ secrets.PERSONAL_TOKEN }} 163 | inputs: '{ "message": "blah blah", "debug": true }' 164 | ``` 165 | 166 | ### Invoke workflow in another repo with inputs 167 | 168 | ```yaml 169 | - name: Invoke workflow in another repo with inputs 170 | uses: the-actions-org/workflow-dispatch@v4 171 | with: 172 | workflow: Some Workflow 173 | repo: benc-uk/example 174 | token: ${{ secrets.PERSONAL_TOKEN }} 175 | inputs: '{ "message": "blah blah", "debug": true }' 176 | ``` 177 | 178 | ### Invoke workflow and handle result 179 | 180 | ```yaml 181 | - name: Invoke workflow and handle result 182 | id: trigger-step 183 | uses: the-actions-org/workflow-dispatch@v4 184 | with: 185 | workflow: Another Workflow 186 | token: ${{ secrets.PERSONAL_TOKEN }} 187 | - name: Another step that can handle the result 188 | if: always() 189 | run: echo "Another Workflow conclusion: ${{ steps.trigger-step.outputs.workflow-conclusion }}" 190 | ``` 191 | 192 | ### Invoke workflow and scrap output 193 | 194 | ```yaml 195 | - name: Invoke workflow and scrap output 196 | id: trigger-step 197 | uses: the-actions-org/workflow-dispatch@v4 198 | with: 199 | workflow: Another Workflow 200 | token: ${{ secrets.PERSONAL_TOKEN }} 201 | workflow-logs: json-output 202 | - name: Another step that can handle the result 203 | if: always() 204 | run: echo '${{ fromJSON(steps.trigger-step.outputs.workflow-logs).my-remote-job }}' 205 | ``` 206 | 207 | ```yaml 208 | name: Another Workflow 209 | 210 | on: 211 | workflow_dispatch: 212 | 213 | jobs: 214 | my-remote-job: 215 | - run: echo "Hello world!" 216 | ``` 217 | 218 | ### Invoke workflow with a unique run name (since 3.0.0) 219 | 220 | ```yaml 221 | - name: Invoke workflow and handle result 222 | id: trigger-step 223 | uses: the-actions-org/workflow-dispatch@v4 224 | env: 225 | RUN_NAME: ${{ github.repository }}/actions/runs/${{ github.run_id }} 226 | with: 227 | run-name: ${{ env.RUN_NAME }} 228 | workflow: Another Workflow 229 | token: ${{ secrets.PERSONAL_TOKEN }} 230 | inputs: >- 231 | { 232 | "run-name": "${{ env.RUN_NAME }}" 233 | } 234 | ``` 235 | 236 | :warning: In you remote workflow, you will need to forward and use the `run-name` input (See [GitHub Action run-name](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#run-name)) 237 | 238 | ```yaml 239 | name: Another Workflow 240 | run-name: ${{ inputs.run-name }} 241 | 242 | on: 243 | workflow_dispatch: 244 | inputs: 245 | run-name: 246 | description: 'The distinct run name used to retrieve the run ID. Defaults to the workflow name' 247 | type: string 248 | required: false 249 | ``` 250 | 251 | ## Contributions 252 | 253 | Thanks to: 254 | 255 | * [LudovicTOURMAN](https://github.com/LudovicTOURMAN ) 256 | * [Djontleman](https://github.com/Djontleman) 257 | * [aurelien-baudet](https://github.com/aurelien-baudet) 258 | * [samirergaibi](https://github.com/samirergaibi) 259 | * [rui-ferreira](https://github.com/rui-ferreira) 260 | * [robbertvdg](https://github.com/robbertvdg) 261 | * [samit2040](https://github.com/samit2040) 262 | * [jonas-schievink](https://github.com/jonas-schievink) 263 | -------------------------------------------------------------------------------- /action.yaml: -------------------------------------------------------------------------------- 1 | name: 'Workflow Dispatch and wait' 2 | description: 'Trigger and chain GitHub Actions workflows with workflow_dispatch events and wait for result' 3 | 4 | inputs: 5 | workflow: 6 | description: 'Name or ID of workflow to run' 7 | required: true 8 | token: 9 | description: 'GitHub token with repo write access, can NOT use secrets.GITHUB_TOKEN, see readme' 10 | required: true 11 | inputs: 12 | description: 'Inputs to pass to the workflow, must be a JSON string. All values must be strings (even if used as boolean or number)' 13 | required: false 14 | ref: 15 | description: 'The reference of the workflow run. The reference can be a branch, tag, or a commit SHA' 16 | required: false 17 | repo: 18 | description: 'Repo owner & name, slash separated, only set if invoking a workflow in a different repo' 19 | required: false 20 | run-name: 21 | description: 'If specified will select the run ID based on the run name' 22 | required: false 23 | display-workflow-run-url: 24 | description: 'Get the URL of the triggered workflow and display it in logs (useful to follow the progress of the triggered workflow)' 25 | required: false 26 | default: true 27 | display-workflow-run-url-interval: 28 | description: 'The time to wait (+unit) between two polls to get the URL of the workflow run' 29 | required: false 30 | default: 1m 31 | display-workflow-run-url-timeout: 32 | description: 'Maximum amount of time (+unit) to wait for the URL of the workflow run. If the timeout is reached, it is just ignored' 33 | required: false 34 | default: 10m 35 | wait-for-completion: 36 | description: 'Block until the triggered workflow has finished' 37 | required: false 38 | default: true 39 | wait-for-completion-timeout: 40 | description: 'Maximum amount of time (+unit) to wait to mark workflow as timed out' 41 | required: false 42 | default: 1h 43 | wait-for-completion-interval: 44 | description: 'Time to wait (+unit) between two polls to get run status' 45 | required: false 46 | default: 1m 47 | workflow-logs: 48 | description: >- 49 | Indicate what to do with logs of the triggered workflow. 50 | `ignore` do not retrieve logs from tiggered workflow. 51 | `print` retrieves logs from triggered workflow and print in the workflow that triggered the other workflow. 52 | `output` retrieves logs from triggered workflow and set them as `workflow-logs` output. 53 | `json-output` retrieves logs from triggered workflow and return a json array groupped by job name. 54 | required: false 55 | default: ignore 56 | 57 | outputs: 58 | workflow-conclusion: 59 | description: 'Conclusion of the triggered workflow' 60 | workflow-id: 61 | description: 'ID of the triggered workflow' 62 | workflow-url: 63 | description: 'URL of the triggered workflow' 64 | workflow-logs: 65 | description: | 66 | Logs of the triggered workflow. Based on `inputs.workflow-logs`, format is set to: 67 | - `output`: Multiline logs formatted as: ' | ' 68 | - `json-output`: JSON logs formatted as: '{"": [{"": ""}]' 69 | 70 | runs: 71 | using: 'node20' 72 | main: 'dist/index.js' 73 | 74 | branding: 75 | color: purple 76 | icon: send 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workflow-dispatch-and-wait", 3 | "version": "4.0.0", 4 | "description": "Trigger running GitHub Actions workflows and wait for result", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "ncc build src/main.ts -o dist", 8 | "lint": "eslint src/", 9 | "lint-fix": "eslint src/ --fix" 10 | }, 11 | "keywords": [ 12 | "github", 13 | "actions", 14 | "worflow", 15 | "trigger" 16 | ], 17 | "author": "Aurélien Baudet", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "@actions/core": "1.10.1", 21 | "@actions/github": "6.0.0", 22 | "@typescript-eslint/eslint-plugin": "7.7.0", 23 | "@typescript-eslint/parser": "7.7.0", 24 | "@vercel/ncc": "0.38.1", 25 | "eslint": "8.57.0", 26 | "typescript": "5.4.5" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/debug.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | 3 | export function debug(title: string, content: any) { 4 | if (core.isDebug()) { 5 | core.info(`::group::${title}`) 6 | try { 7 | core.debug(JSON.stringify(content, null, 3)) 8 | } catch(e) { 9 | core.debug(`Failed to serialize object, trying toString. Cause: ${e}`) 10 | core.debug(content?.toString()) 11 | } 12 | core.info('::endgroup::') 13 | } 14 | } -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Copyright (c) Ben Coleman, 2020 3 | // Licensed under the MIT License. 4 | // 5 | // Workflow Dispatch Action - Main task code 6 | // ---------------------------------------------------------------------------- 7 | 8 | import * as core from '@actions/core' 9 | import { formatDuration, getArgs, isTimedOut, sleep } from './utils' 10 | import { WorkflowHandler, WorkflowRunConclusion, WorkflowRunResult, WorkflowRunStatus } from './workflow-handler' 11 | import { handleWorkflowLogsPerJob } from './workflow-logs-handler' 12 | 13 | 14 | 15 | async function getFollowUrl(workflowHandler: WorkflowHandler, interval: number, timeout: number) { 16 | const start = Date.now() 17 | let url 18 | do { 19 | await sleep(interval) 20 | try { 21 | const result = await workflowHandler.getWorkflowRunStatus() 22 | url = result.url 23 | } catch(e: any) { 24 | core.debug(`Failed to get workflow url: ${e.message}`) 25 | } 26 | } while (!url && !isTimedOut(start, timeout)) 27 | return url 28 | } 29 | 30 | async function waitForCompletionOrTimeout(workflowHandler: WorkflowHandler, checkStatusInterval: number, waitForCompletionTimeout: number) { 31 | const start = Date.now() 32 | let status 33 | let result 34 | do { 35 | await sleep(checkStatusInterval) 36 | try { 37 | result = await workflowHandler.getWorkflowRunStatus() 38 | status = result.status 39 | core.debug(`Worflow is running for ${formatDuration(Date.now() - start)}. Current status=${status}`) 40 | } catch(e: any) { 41 | core.warning(`Failed to get workflow status: ${e.message}`) 42 | } 43 | } while (status !== WorkflowRunStatus.COMPLETED && !isTimedOut(start, waitForCompletionTimeout)) 44 | return { result, start } 45 | } 46 | 47 | function computeConclusion(start: number, waitForCompletionTimeout: number, result?: WorkflowRunResult) { 48 | if (isTimedOut(start, waitForCompletionTimeout)) { 49 | core.info('Workflow wait timed out') 50 | core.setOutput('workflow-conclusion', WorkflowRunConclusion.TIMED_OUT) 51 | throw new Error('Workflow run has failed due to timeout') 52 | } 53 | 54 | core.info(`Workflow completed with conclusion=${result?.conclusion}`) 55 | const conclusion = result?.conclusion 56 | core.setOutput('workflow-conclusion', conclusion) 57 | 58 | if (conclusion === WorkflowRunConclusion.FAILURE) throw new Error('Workflow run has failed') 59 | if (conclusion === WorkflowRunConclusion.CANCELLED) throw new Error('Workflow run was cancelled') 60 | if (conclusion === WorkflowRunConclusion.TIMED_OUT) throw new Error('Workflow run has failed due to timeout') 61 | } 62 | 63 | async function handleLogs(args: any, workflowHandler: WorkflowHandler) { 64 | try { 65 | const workflowRunId = await workflowHandler.getWorkflowRunId() 66 | await handleWorkflowLogsPerJob(args, workflowRunId) 67 | } catch(e: any) { 68 | core.error(`Failed to handle logs of triggered workflow. Cause: ${e}`) 69 | } 70 | } 71 | 72 | // 73 | // Main task function (async wrapper) 74 | // 75 | async function run(): Promise { 76 | try { 77 | const args = getArgs() 78 | const workflowHandler = new WorkflowHandler(args.token, args.workflowRef, args.owner, args.repo, args.ref, args.runName) 79 | 80 | // Trigger workflow run 81 | await workflowHandler.triggerWorkflow(args.inputs) 82 | core.info('Workflow triggered 🚀') 83 | 84 | if (args.displayWorkflowUrl) { 85 | const url = await getFollowUrl(workflowHandler, args.displayWorkflowUrlInterval, args.displayWorkflowUrlTimeout) 86 | core.info(`You can follow the running workflow here: ${url}`) 87 | core.setOutput('workflow-url', url) 88 | } 89 | 90 | if (!args.waitForCompletion) { 91 | return 92 | } 93 | 94 | core.info('Waiting for workflow completion') 95 | const { result, start } = await waitForCompletionOrTimeout(workflowHandler, args.checkStatusInterval, args.waitForCompletionTimeout) 96 | 97 | await handleLogs(args, workflowHandler) 98 | 99 | core.setOutput('workflow-id', result?.id) 100 | core.setOutput('workflow-url', result?.url) 101 | computeConclusion(start, args.waitForCompletionTimeout, result) 102 | 103 | } catch (error: any) { 104 | core.setFailed(error.message) 105 | } 106 | } 107 | 108 | // 109 | // Call the main task run function 110 | // 111 | run() 112 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import * as github from '@actions/github' 3 | 4 | enum TimeUnit { 5 | S = 1000, 6 | M = 60 * 1000, 7 | H = 60 * 60 * 1000 8 | } 9 | 10 | function toMilliseconds(timeWithUnit: string): number { 11 | const unitStr = timeWithUnit.substring(timeWithUnit.length-1) 12 | const unit = TimeUnit[unitStr.toUpperCase() as keyof typeof TimeUnit] 13 | if (!unit) { 14 | throw new Error('Unknown time unit '+unitStr) 15 | } 16 | const time = parseFloat(timeWithUnit) 17 | return time * unit 18 | } 19 | 20 | function parse(inputsJson: string) { 21 | if(inputsJson) { 22 | try { 23 | return JSON.parse(inputsJson) 24 | } catch(e) { 25 | throw new Error(`Failed to parse 'inputs' parameter. Must be a valid JSON.\nCause: ${e}`) 26 | } 27 | } 28 | return {} 29 | } 30 | export function getArgs() { 31 | // Required inputs 32 | const token = core.getInput('token') 33 | const workflowRef = core.getInput('workflow') 34 | // Optional inputs, with defaults 35 | const ref = core.getInput('ref') || github.context.ref 36 | const [owner, repo] = core.getInput('repo') 37 | ? core.getInput('repo').split('/') 38 | : [github.context.repo.owner, github.context.repo.repo] 39 | 40 | // Decode inputs, this MUST be a valid JSON string 41 | const inputs = parse(core.getInput('inputs')) 42 | 43 | const displayWorkflowUrlStr = core.getInput('display-workflow-run-url') 44 | const displayWorkflowUrl = displayWorkflowUrlStr && displayWorkflowUrlStr === 'true' 45 | const displayWorkflowUrlTimeout = toMilliseconds(core.getInput('display-workflow-run-url-timeout')) 46 | const displayWorkflowUrlInterval = toMilliseconds(core.getInput('display-workflow-run-url-interval')) 47 | 48 | const waitForCompletionStr = core.getInput('wait-for-completion') 49 | const waitForCompletion = waitForCompletionStr && waitForCompletionStr === 'true' 50 | const waitForCompletionTimeout = toMilliseconds(core.getInput('wait-for-completion-timeout')) 51 | const checkStatusInterval = toMilliseconds(core.getInput('wait-for-completion-interval')) 52 | const runName = core.getInput('run-name') 53 | const workflowLogMode = core.getInput('workflow-logs') 54 | 55 | return { 56 | token, 57 | workflowRef, 58 | ref, 59 | owner, 60 | repo, 61 | inputs, 62 | displayWorkflowUrl, 63 | displayWorkflowUrlTimeout, 64 | displayWorkflowUrlInterval, 65 | checkStatusInterval, 66 | waitForCompletion, 67 | waitForCompletionTimeout, 68 | runName, 69 | workflowLogMode 70 | } 71 | } 72 | 73 | export function sleep(ms: number) { 74 | return new Promise(resolve => setTimeout(resolve, ms)) 75 | } 76 | 77 | export function isTimedOut(start: number, waitForCompletionTimeout: number) { 78 | return Date.now() > start + waitForCompletionTimeout 79 | } 80 | 81 | export function formatDuration(duration: number) { 82 | const durationSeconds = duration / 1000 83 | const hours = Math.floor(durationSeconds / 3600) 84 | const minutes = Math.floor((durationSeconds - (hours * 3600)) / 60) 85 | const seconds = durationSeconds - (hours * 3600) - (minutes * 60) 86 | 87 | let hoursStr = hours + '' 88 | let minutesStr = minutes + '' 89 | let secondsStr = seconds + '' 90 | 91 | if (hours < 10) {hoursStr = '0'+hoursStr} 92 | if (minutes < 10) {minutesStr = '0'+minutesStr} 93 | if (seconds < 10) {secondsStr = '0'+secondsStr} 94 | return hoursStr+'h '+minutesStr+'m '+secondsStr+'s' 95 | } 96 | -------------------------------------------------------------------------------- /src/workflow-handler.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as core from '@actions/core' 3 | import * as github from '@actions/github' 4 | import { debug } from './debug' 5 | 6 | export enum WorkflowRunStatus { 7 | QUEUED = 'queued', 8 | IN_PROGRESS = 'in_progress', 9 | COMPLETED = 'completed' 10 | } 11 | 12 | const ofStatus = (status: string | null): WorkflowRunStatus => { 13 | if (!status) { 14 | return WorkflowRunStatus.QUEUED 15 | } 16 | const key = status.toUpperCase() as keyof typeof WorkflowRunStatus 17 | return WorkflowRunStatus[key] 18 | } 19 | 20 | export enum WorkflowRunConclusion { 21 | SUCCESS = 'success', 22 | FAILURE = 'failure', 23 | CANCELLED = 'cancelled', 24 | SKIPPED = 'skipped', 25 | NEUTRAL = 'neutral', 26 | TIMED_OUT = 'timed_out', 27 | ACTION_REQUIRED = 'action_required' 28 | } 29 | 30 | const ofConclusion = (conclusion: string | null): WorkflowRunConclusion => { 31 | if (!conclusion) { 32 | return WorkflowRunConclusion.NEUTRAL 33 | } 34 | const key = conclusion.toUpperCase() as keyof typeof WorkflowRunConclusion 35 | return WorkflowRunConclusion[key] 36 | } 37 | 38 | export interface WorkflowRunResult { 39 | id: number, 40 | url: string, 41 | status: WorkflowRunStatus, 42 | conclusion: WorkflowRunConclusion 43 | } 44 | 45 | 46 | export class WorkflowHandler { 47 | private octokit: any 48 | private workflowId?: number | string 49 | private workflowRunId?: number 50 | private triggerDate = 0 51 | 52 | constructor(token: string, 53 | private workflowRef: string, 54 | private owner: string, 55 | private repo: string, 56 | private ref: string, 57 | private runName: string) { 58 | // Get octokit client for making API calls 59 | this.octokit = github.getOctokit(token) 60 | } 61 | 62 | async triggerWorkflow(inputs: any) { 63 | try { 64 | const workflowId = await this.getWorkflowId() 65 | this.triggerDate = new Date().setMilliseconds(0) 66 | const dispatchResp = await this.octokit.rest.actions.createWorkflowDispatch({ 67 | owner: this.owner, 68 | repo: this.repo, 69 | workflow_id: workflowId, 70 | ref: this.ref, 71 | inputs 72 | }) 73 | debug('Workflow Dispatch', dispatchResp) 74 | } catch (error: any) { 75 | debug('Workflow Dispatch error', error.message) 76 | throw error 77 | } 78 | } 79 | 80 | async getWorkflowRunStatus(): Promise { 81 | try { 82 | const runId = await this.getWorkflowRunId() 83 | const response = await this.octokit.rest.actions.getWorkflowRun({ 84 | owner: this.owner, 85 | repo: this.repo, 86 | run_id: runId 87 | }) 88 | debug('Workflow Run status', response) 89 | 90 | return { 91 | id: runId, 92 | url: response.data.html_url, 93 | status: ofStatus(response.data.status), 94 | conclusion: ofConclusion(response.data.conclusion) 95 | } 96 | 97 | } catch (error: any) { 98 | debug('Workflow Run status error', error) 99 | throw error 100 | } 101 | } 102 | 103 | 104 | async getWorkflowRunArtifacts(): Promise { 105 | try { 106 | const runId = await this.getWorkflowRunId() 107 | const response = await this.octokit.rest.actions.getWorkflowRunArtifacts({ 108 | owner: this.owner, 109 | repo: this.repo, 110 | run_id: runId 111 | }) 112 | debug('Workflow Run artifacts', response) 113 | 114 | return { 115 | id: runId, 116 | url: response.data.html_url, 117 | status: ofStatus(response.data.status), 118 | conclusion: ofConclusion(response.data.conclusion) 119 | } 120 | 121 | } catch (error) { 122 | debug('Workflow Run artifacts error', error) 123 | throw error 124 | } 125 | } 126 | 127 | private async findAllWorkflowRuns() { 128 | try { 129 | const workflowId = await this.getWorkflowId() 130 | const response = await this.octokit.rest.actions.listWorkflowRuns({ 131 | owner: this.owner, 132 | repo: this.repo, 133 | workflow_id: workflowId, 134 | event: 'workflow_dispatch', 135 | created: `>=${new Date(this.triggerDate).toISOString()}` 136 | }) 137 | 138 | debug('List Workflow Runs', response) 139 | 140 | return response.data.workflow_runs 141 | } catch (error) { 142 | debug('Fin all workflow runs error', error) 143 | throw new Error(`Failed to list workflow runs. Cause: ${error}`) 144 | } 145 | } 146 | 147 | async getWorkflowRunId(): Promise { 148 | if (this.workflowRunId) { 149 | return this.workflowRunId 150 | } 151 | try { 152 | let runs = await this.findAllWorkflowRuns() 153 | if (this.runName) { 154 | runs = runs.filter((r: any) => r.name == this.runName) 155 | } 156 | 157 | if (runs.length == 0) { 158 | throw new Error('Run not found') 159 | } 160 | 161 | if (runs.length > 1) { 162 | core.warning(`Found ${runs.length} runs. Using the last one.`) 163 | await this.debugFoundWorkflowRuns(runs) 164 | } 165 | 166 | this.workflowRunId = runs[0].id as number 167 | 168 | return this.workflowRunId 169 | } catch (error) { 170 | debug('Get workflow run id error', error) 171 | throw error 172 | } 173 | } 174 | 175 | private async getWorkflowId(): Promise { 176 | if (this.workflowId) { 177 | return this.workflowId 178 | } 179 | if (this.isFilename(this.workflowRef)) { 180 | this.workflowId = this.workflowRef 181 | core.debug(`Workflow id is: ${this.workflowRef}`) 182 | return this.workflowId 183 | } 184 | try { 185 | const workflowsResp = await this.octokit.rest.actions.listRepoWorkflows({ 186 | owner: this.owner, 187 | repo: this.repo 188 | }) 189 | const workflows = workflowsResp.data.workflows 190 | debug('List Workflows', workflows) 191 | 192 | // Locate workflow either by name or id 193 | const workflowFind = workflows.find((workflow: any) => workflow.name === this.workflowRef || workflow.id.toString() === this.workflowRef) 194 | if(!workflowFind) throw new Error(`Unable to find workflow '${this.workflowRef}' in ${this.owner}/${this.repo} 😥`) 195 | core.debug(`Workflow id is: ${workflowFind.id}`) 196 | this.workflowId = workflowFind.id as number 197 | return this.workflowId 198 | } catch(error) { 199 | debug('List workflows error', error) 200 | throw error 201 | } 202 | } 203 | 204 | private isFilename(workflowRef: string) { 205 | return /.+\.ya?ml$/.test(workflowRef) 206 | } 207 | 208 | private debugFoundWorkflowRuns(runs: any){ 209 | debug(`Filtered Workflow Runs (after trigger date: ${new Date(this.triggerDate).toISOString()})`, runs.map((r: any) => ({ 210 | id: r.id, 211 | name: r.name, 212 | created_at: r.created_at, 213 | triggerDate: new Date(this.triggerDate).toISOString(), 214 | created_at_ts: new Date(r.created_at).valueOf(), 215 | triggerDateTs: this.triggerDate 216 | }))) 217 | } 218 | 219 | } 220 | 221 | -------------------------------------------------------------------------------- /src/workflow-logs-handler.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import * as github from '@actions/github' 3 | import { debug } from './debug' 4 | 5 | interface JobInfo { 6 | name: string, 7 | id: number 8 | } 9 | 10 | 11 | export async function handleWorkflowLogsPerJob(args: any, workflowRunId: number): Promise { 12 | const mode = args.workflowLogMode 13 | const token = args.token 14 | const owner = args.owner 15 | const repo = args.repo 16 | 17 | const handler = logHandlerFactory(mode) 18 | if (handler == null) { 19 | return 20 | } 21 | 22 | const octokit = github.getOctokit(token) 23 | const runId = workflowRunId 24 | const response = await octokit.rest.actions.listJobsForWorkflowRun({ 25 | owner: owner, 26 | repo: repo, 27 | run_id: runId 28 | }) 29 | 30 | await handler.handleJobList(response.data.jobs) 31 | 32 | for (const job of response.data.jobs) { 33 | try { 34 | const jobLog = await octokit.rest.actions.downloadJobLogsForWorkflowRun({ 35 | owner: owner, 36 | repo: repo, 37 | job_id: job.id, 38 | }) 39 | await handler.handleJobLogs(job, jobLog.data as string) 40 | } catch (error: any) { 41 | await handler.handleError(job, error) 42 | } 43 | } 44 | 45 | switch (mode) { 46 | case 'json-output': 47 | core.setOutput('workflow-logs', (handler as OutputLogsHandler).getJsonLogs()) 48 | break 49 | case 'output': 50 | core.setOutput('workflow-logs', (handler as OutputLogsHandler).getRawLogs()) 51 | break 52 | default: 53 | break 54 | } 55 | } 56 | 57 | interface WorkflowLogHandler { 58 | handleJobList(jobs: Array): Promise 59 | handleJobLogs(job: JobInfo, logs: string): Promise 60 | handleError(job: JobInfo, error: Error): Promise 61 | } 62 | 63 | class PrintLogsHandler implements WorkflowLogHandler { 64 | 65 | async handleJobList(jobs: Array): Promise { 66 | debug('Retrieving logs for jobs in workflow', jobs) 67 | } 68 | 69 | async handleJobLogs(job: JobInfo, logs: string): Promise { 70 | core.startGroup(`Logs of job '${job.name}'`) 71 | core.info(escapeImportedLogs(logs)) 72 | core.endGroup() 73 | } 74 | 75 | async handleError(job: JobInfo, error: Error): Promise { 76 | core.warning(escapeImportedLogs(error.message)) 77 | } 78 | } 79 | 80 | class OutputLogsHandler implements WorkflowLogHandler { 81 | private logs: Map = new Map() 82 | 83 | async handleJobList(jobs: Array): Promise { 84 | debug('Retrieving logs for jobs in workflow', jobs) 85 | } 86 | 87 | async handleJobLogs(job: JobInfo, logs: string): Promise { 88 | this.logs.set(job.name, logs) 89 | } 90 | 91 | async handleError(job: JobInfo, error: Error): Promise { 92 | core.warning(escapeImportedLogs(error.message)) 93 | } 94 | 95 | getJsonLogs(): string { 96 | const result: any = {} 97 | const logPattern = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{7}Z)\s+(.*)/ 98 | 99 | this.logs.forEach((logs: string, jobName: string) => { 100 | result[jobName] = [] 101 | for (const line of logs.split('\n')) { 102 | if (line === '') { 103 | continue 104 | } 105 | const splitted = line.split(logPattern) 106 | result[jobName].push({ 107 | datetime: splitted[1], 108 | message: splitted[2] 109 | }) 110 | } 111 | // result[jobName] = logs; 112 | }) 113 | return JSON.stringify(result) 114 | } 115 | 116 | getRawLogs(): string { 117 | let result = '' 118 | this.logs.forEach((logs: string, jobName: string) => { 119 | for (const line of logs.split('\n')) { 120 | result += `${jobName} | ${line}\n` 121 | } 122 | }) 123 | return result 124 | } 125 | } 126 | 127 | function logHandlerFactory(mode: string): WorkflowLogHandler | null { 128 | switch(mode) { 129 | case 'print': 130 | return new PrintLogsHandler() 131 | case 'output': 132 | case 'json-output': 133 | return new OutputLogsHandler() 134 | default: 135 | return null 136 | } 137 | } 138 | 139 | function escapeImportedLogs(str: string): string { 140 | return str.replace(/^/mg, '| ') 141 | .replace(/##\[([^\]]+)\]/gm, '##<$1>') 142 | } 143 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 4 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 5 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 6 | "strict": true, /* Enable all strict type-checking options. */ 7 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 8 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 9 | }, 10 | "exclude": ["node_modules", "**/*.test.ts"] 11 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@aashutoshrathi/word-wrap@^1.2.3": 6 | version "1.2.6" 7 | resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" 8 | integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== 9 | 10 | "@actions/core@1.10.1": 11 | version "1.10.1" 12 | resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.10.1.tgz#61108e7ac40acae95ee36da074fa5850ca4ced8a" 13 | integrity sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g== 14 | dependencies: 15 | "@actions/http-client" "^2.0.1" 16 | uuid "^8.3.2" 17 | 18 | "@actions/github@6.0.0": 19 | version "6.0.0" 20 | resolved "https://registry.yarnpkg.com/@actions/github/-/github-6.0.0.tgz#65883433f9d81521b782a64cc1fd45eef2191ea7" 21 | integrity sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g== 22 | dependencies: 23 | "@actions/http-client" "^2.2.0" 24 | "@octokit/core" "^5.0.1" 25 | "@octokit/plugin-paginate-rest" "^9.0.0" 26 | "@octokit/plugin-rest-endpoint-methods" "^10.0.0" 27 | 28 | "@actions/http-client@^2.0.1", "@actions/http-client@^2.2.0": 29 | version "2.2.1" 30 | resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-2.2.1.tgz#ed3fe7a5a6d317ac1d39886b0bb999ded229bb38" 31 | integrity sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw== 32 | dependencies: 33 | tunnel "^0.0.6" 34 | undici "^5.25.4" 35 | 36 | "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": 37 | version "4.4.0" 38 | resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" 39 | integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== 40 | dependencies: 41 | eslint-visitor-keys "^3.3.0" 42 | 43 | "@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": 44 | version "4.10.0" 45 | resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" 46 | integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== 47 | 48 | "@eslint/eslintrc@^2.1.4": 49 | version "2.1.4" 50 | resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" 51 | integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== 52 | dependencies: 53 | ajv "^6.12.4" 54 | debug "^4.3.2" 55 | espree "^9.6.0" 56 | globals "^13.19.0" 57 | ignore "^5.2.0" 58 | import-fresh "^3.2.1" 59 | js-yaml "^4.1.0" 60 | minimatch "^3.1.2" 61 | strip-json-comments "^3.1.1" 62 | 63 | "@eslint/js@8.57.0": 64 | version "8.57.0" 65 | resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" 66 | integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== 67 | 68 | "@fastify/busboy@^2.0.0": 69 | version "2.1.1" 70 | resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" 71 | integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== 72 | 73 | "@humanwhocodes/config-array@^0.11.14": 74 | version "0.11.14" 75 | resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" 76 | integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== 77 | dependencies: 78 | "@humanwhocodes/object-schema" "^2.0.2" 79 | debug "^4.3.1" 80 | minimatch "^3.0.5" 81 | 82 | "@humanwhocodes/module-importer@^1.0.1": 83 | version "1.0.1" 84 | resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" 85 | integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== 86 | 87 | "@humanwhocodes/object-schema@^2.0.2": 88 | version "2.0.3" 89 | resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" 90 | integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== 91 | 92 | "@nodelib/fs.scandir@2.1.5": 93 | version "2.1.5" 94 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 95 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 96 | dependencies: 97 | "@nodelib/fs.stat" "2.0.5" 98 | run-parallel "^1.1.9" 99 | 100 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 101 | version "2.0.5" 102 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 103 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 104 | 105 | "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": 106 | version "1.2.8" 107 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 108 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 109 | dependencies: 110 | "@nodelib/fs.scandir" "2.1.5" 111 | fastq "^1.6.0" 112 | 113 | "@octokit/auth-token@^4.0.0": 114 | version "4.0.0" 115 | resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-4.0.0.tgz#40d203ea827b9f17f42a29c6afb93b7745ef80c7" 116 | integrity sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA== 117 | 118 | "@octokit/core@^5.0.1": 119 | version "5.2.0" 120 | resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.2.0.tgz#ddbeaefc6b44a39834e1bb2e58a49a117672a7ea" 121 | integrity sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg== 122 | dependencies: 123 | "@octokit/auth-token" "^4.0.0" 124 | "@octokit/graphql" "^7.1.0" 125 | "@octokit/request" "^8.3.1" 126 | "@octokit/request-error" "^5.1.0" 127 | "@octokit/types" "^13.0.0" 128 | before-after-hook "^2.2.0" 129 | universal-user-agent "^6.0.0" 130 | 131 | "@octokit/endpoint@^9.0.1": 132 | version "9.0.5" 133 | resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" 134 | integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== 135 | dependencies: 136 | "@octokit/types" "^13.1.0" 137 | universal-user-agent "^6.0.0" 138 | 139 | "@octokit/graphql@^7.1.0": 140 | version "7.1.0" 141 | resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-7.1.0.tgz#9bc1c5de92f026648131f04101cab949eeffe4e0" 142 | integrity sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ== 143 | dependencies: 144 | "@octokit/request" "^8.3.0" 145 | "@octokit/types" "^13.0.0" 146 | universal-user-agent "^6.0.0" 147 | 148 | "@octokit/openapi-types@^20.0.0": 149 | version "20.0.0" 150 | resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-20.0.0.tgz#9ec2daa0090eeb865ee147636e0c00f73790c6e5" 151 | integrity sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA== 152 | 153 | "@octokit/openapi-types@^22.1.0": 154 | version "22.1.0" 155 | resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-22.1.0.tgz#6aa72f35fb29318064e4ab60972f40429857eb2e" 156 | integrity sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q== 157 | 158 | "@octokit/plugin-paginate-rest@^9.0.0": 159 | version "9.2.1" 160 | resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz#2e2a2f0f52c9a4b1da1a3aa17dabe3c459b9e401" 161 | integrity sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw== 162 | dependencies: 163 | "@octokit/types" "^12.6.0" 164 | 165 | "@octokit/plugin-rest-endpoint-methods@^10.0.0": 166 | version "10.4.1" 167 | resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz#41ba478a558b9f554793075b2e20cd2ef973be17" 168 | integrity sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg== 169 | dependencies: 170 | "@octokit/types" "^12.6.0" 171 | 172 | "@octokit/request-error@^5.1.0": 173 | version "5.1.0" 174 | resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" 175 | integrity sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q== 176 | dependencies: 177 | "@octokit/types" "^13.1.0" 178 | deprecation "^2.0.0" 179 | once "^1.4.0" 180 | 181 | "@octokit/request@^8.3.0", "@octokit/request@^8.3.1": 182 | version "8.4.0" 183 | resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.0.tgz#7f4b7b1daa3d1f48c0977ad8fffa2c18adef8974" 184 | integrity sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw== 185 | dependencies: 186 | "@octokit/endpoint" "^9.0.1" 187 | "@octokit/request-error" "^5.1.0" 188 | "@octokit/types" "^13.1.0" 189 | universal-user-agent "^6.0.0" 190 | 191 | "@octokit/types@^12.6.0": 192 | version "12.6.0" 193 | resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.6.0.tgz#8100fb9eeedfe083aae66473bd97b15b62aedcb2" 194 | integrity sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw== 195 | dependencies: 196 | "@octokit/openapi-types" "^20.0.0" 197 | 198 | "@octokit/types@^13.0.0", "@octokit/types@^13.1.0": 199 | version "13.4.1" 200 | resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.4.1.tgz#ad3574488cce6792e5d981a1bdf4b694e1ca349f" 201 | integrity sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg== 202 | dependencies: 203 | "@octokit/openapi-types" "^22.1.0" 204 | 205 | "@types/json-schema@^7.0.15": 206 | version "7.0.15" 207 | resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" 208 | integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== 209 | 210 | "@types/semver@^7.5.8": 211 | version "7.5.8" 212 | resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" 213 | integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== 214 | 215 | "@typescript-eslint/eslint-plugin@7.7.0": 216 | version "7.7.0" 217 | resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz#bf34a02f221811505b8bf2f31060c8560c1bb0a3" 218 | integrity sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ== 219 | dependencies: 220 | "@eslint-community/regexpp" "^4.10.0" 221 | "@typescript-eslint/scope-manager" "7.7.0" 222 | "@typescript-eslint/type-utils" "7.7.0" 223 | "@typescript-eslint/utils" "7.7.0" 224 | "@typescript-eslint/visitor-keys" "7.7.0" 225 | debug "^4.3.4" 226 | graphemer "^1.4.0" 227 | ignore "^5.3.1" 228 | natural-compare "^1.4.0" 229 | semver "^7.6.0" 230 | ts-api-utils "^1.3.0" 231 | 232 | "@typescript-eslint/parser@7.7.0": 233 | version "7.7.0" 234 | resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.7.0.tgz#6b1b3ce76c5de002c43af8ae933613b0f2b4bcc6" 235 | integrity sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg== 236 | dependencies: 237 | "@typescript-eslint/scope-manager" "7.7.0" 238 | "@typescript-eslint/types" "7.7.0" 239 | "@typescript-eslint/typescript-estree" "7.7.0" 240 | "@typescript-eslint/visitor-keys" "7.7.0" 241 | debug "^4.3.4" 242 | 243 | "@typescript-eslint/scope-manager@7.7.0": 244 | version "7.7.0" 245 | resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz#3f0db079b275bb8b0cb5be7613fb3130cfb5de77" 246 | integrity sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw== 247 | dependencies: 248 | "@typescript-eslint/types" "7.7.0" 249 | "@typescript-eslint/visitor-keys" "7.7.0" 250 | 251 | "@typescript-eslint/type-utils@7.7.0": 252 | version "7.7.0" 253 | resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz#36792ff4209a781b058de61631a48df17bdefbc5" 254 | integrity sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg== 255 | dependencies: 256 | "@typescript-eslint/typescript-estree" "7.7.0" 257 | "@typescript-eslint/utils" "7.7.0" 258 | debug "^4.3.4" 259 | ts-api-utils "^1.3.0" 260 | 261 | "@typescript-eslint/types@7.7.0": 262 | version "7.7.0" 263 | resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.7.0.tgz#23af4d24bf9ce15d8d301236e3e3014143604f27" 264 | integrity sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w== 265 | 266 | "@typescript-eslint/typescript-estree@7.7.0": 267 | version "7.7.0" 268 | resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz#b5dd6383b4c6a852d7b256a37af971e8982be97f" 269 | integrity sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ== 270 | dependencies: 271 | "@typescript-eslint/types" "7.7.0" 272 | "@typescript-eslint/visitor-keys" "7.7.0" 273 | debug "^4.3.4" 274 | globby "^11.1.0" 275 | is-glob "^4.0.3" 276 | minimatch "^9.0.4" 277 | semver "^7.6.0" 278 | ts-api-utils "^1.3.0" 279 | 280 | "@typescript-eslint/utils@7.7.0": 281 | version "7.7.0" 282 | resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.7.0.tgz#3d2b6606a60ac34f3c625facfb3b3ab7e126f58d" 283 | integrity sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig== 284 | dependencies: 285 | "@eslint-community/eslint-utils" "^4.4.0" 286 | "@types/json-schema" "^7.0.15" 287 | "@types/semver" "^7.5.8" 288 | "@typescript-eslint/scope-manager" "7.7.0" 289 | "@typescript-eslint/types" "7.7.0" 290 | "@typescript-eslint/typescript-estree" "7.7.0" 291 | semver "^7.6.0" 292 | 293 | "@typescript-eslint/visitor-keys@7.7.0": 294 | version "7.7.0" 295 | resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz#950148cf1ac11562a2d903fdf7acf76714a2dc9e" 296 | integrity sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA== 297 | dependencies: 298 | "@typescript-eslint/types" "7.7.0" 299 | eslint-visitor-keys "^3.4.3" 300 | 301 | "@ungap/structured-clone@^1.2.0": 302 | version "1.2.0" 303 | resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" 304 | integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== 305 | 306 | "@vercel/ncc@0.38.1": 307 | version "0.38.1" 308 | resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.38.1.tgz#13f08738111e1d9e8a22fd6141f3590e54d9a60e" 309 | integrity sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw== 310 | 311 | acorn-jsx@^5.3.2: 312 | version "5.3.2" 313 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" 314 | integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== 315 | 316 | acorn@^8.9.0: 317 | version "8.11.3" 318 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" 319 | integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== 320 | 321 | ajv@^6.12.4: 322 | version "6.12.6" 323 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 324 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 325 | dependencies: 326 | fast-deep-equal "^3.1.1" 327 | fast-json-stable-stringify "^2.0.0" 328 | json-schema-traverse "^0.4.1" 329 | uri-js "^4.2.2" 330 | 331 | ansi-regex@^5.0.1: 332 | version "5.0.1" 333 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 334 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 335 | 336 | ansi-styles@^4.1.0: 337 | version "4.3.0" 338 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 339 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 340 | dependencies: 341 | color-convert "^2.0.1" 342 | 343 | argparse@^2.0.1: 344 | version "2.0.1" 345 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 346 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 347 | 348 | array-union@^2.1.0: 349 | version "2.1.0" 350 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" 351 | integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== 352 | 353 | balanced-match@^1.0.0: 354 | version "1.0.2" 355 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 356 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 357 | 358 | before-after-hook@^2.2.0: 359 | version "2.2.3" 360 | resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" 361 | integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== 362 | 363 | brace-expansion@^1.1.7: 364 | version "1.1.11" 365 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 366 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 367 | dependencies: 368 | balanced-match "^1.0.0" 369 | concat-map "0.0.1" 370 | 371 | brace-expansion@^2.0.1: 372 | version "2.0.1" 373 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 374 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 375 | dependencies: 376 | balanced-match "^1.0.0" 377 | 378 | braces@^3.0.2: 379 | version "3.0.2" 380 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 381 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 382 | dependencies: 383 | fill-range "^7.0.1" 384 | 385 | callsites@^3.0.0: 386 | version "3.1.0" 387 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 388 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 389 | 390 | chalk@^4.0.0: 391 | version "4.1.2" 392 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 393 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 394 | dependencies: 395 | ansi-styles "^4.1.0" 396 | supports-color "^7.1.0" 397 | 398 | color-convert@^2.0.1: 399 | version "2.0.1" 400 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 401 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 402 | dependencies: 403 | color-name "~1.1.4" 404 | 405 | color-name@~1.1.4: 406 | version "1.1.4" 407 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 408 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 409 | 410 | concat-map@0.0.1: 411 | version "0.0.1" 412 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 413 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 414 | 415 | cross-spawn@^7.0.2: 416 | version "7.0.3" 417 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 418 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 419 | dependencies: 420 | path-key "^3.1.0" 421 | shebang-command "^2.0.0" 422 | which "^2.0.1" 423 | 424 | debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: 425 | version "4.3.4" 426 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 427 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 428 | dependencies: 429 | ms "2.1.2" 430 | 431 | deep-is@^0.1.3: 432 | version "0.1.4" 433 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" 434 | integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 435 | 436 | deprecation@^2.0.0: 437 | version "2.3.1" 438 | resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" 439 | integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== 440 | 441 | dir-glob@^3.0.1: 442 | version "3.0.1" 443 | resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" 444 | integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== 445 | dependencies: 446 | path-type "^4.0.0" 447 | 448 | doctrine@^3.0.0: 449 | version "3.0.0" 450 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 451 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 452 | dependencies: 453 | esutils "^2.0.2" 454 | 455 | escape-string-regexp@^4.0.0: 456 | version "4.0.0" 457 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 458 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 459 | 460 | eslint-scope@^7.2.2: 461 | version "7.2.2" 462 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" 463 | integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== 464 | dependencies: 465 | esrecurse "^4.3.0" 466 | estraverse "^5.2.0" 467 | 468 | eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: 469 | version "3.4.3" 470 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" 471 | integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== 472 | 473 | eslint@8.57.0: 474 | version "8.57.0" 475 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" 476 | integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== 477 | dependencies: 478 | "@eslint-community/eslint-utils" "^4.2.0" 479 | "@eslint-community/regexpp" "^4.6.1" 480 | "@eslint/eslintrc" "^2.1.4" 481 | "@eslint/js" "8.57.0" 482 | "@humanwhocodes/config-array" "^0.11.14" 483 | "@humanwhocodes/module-importer" "^1.0.1" 484 | "@nodelib/fs.walk" "^1.2.8" 485 | "@ungap/structured-clone" "^1.2.0" 486 | ajv "^6.12.4" 487 | chalk "^4.0.0" 488 | cross-spawn "^7.0.2" 489 | debug "^4.3.2" 490 | doctrine "^3.0.0" 491 | escape-string-regexp "^4.0.0" 492 | eslint-scope "^7.2.2" 493 | eslint-visitor-keys "^3.4.3" 494 | espree "^9.6.1" 495 | esquery "^1.4.2" 496 | esutils "^2.0.2" 497 | fast-deep-equal "^3.1.3" 498 | file-entry-cache "^6.0.1" 499 | find-up "^5.0.0" 500 | glob-parent "^6.0.2" 501 | globals "^13.19.0" 502 | graphemer "^1.4.0" 503 | ignore "^5.2.0" 504 | imurmurhash "^0.1.4" 505 | is-glob "^4.0.0" 506 | is-path-inside "^3.0.3" 507 | js-yaml "^4.1.0" 508 | json-stable-stringify-without-jsonify "^1.0.1" 509 | levn "^0.4.1" 510 | lodash.merge "^4.6.2" 511 | minimatch "^3.1.2" 512 | natural-compare "^1.4.0" 513 | optionator "^0.9.3" 514 | strip-ansi "^6.0.1" 515 | text-table "^0.2.0" 516 | 517 | espree@^9.6.0, espree@^9.6.1: 518 | version "9.6.1" 519 | resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" 520 | integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== 521 | dependencies: 522 | acorn "^8.9.0" 523 | acorn-jsx "^5.3.2" 524 | eslint-visitor-keys "^3.4.1" 525 | 526 | esquery@^1.4.2: 527 | version "1.5.0" 528 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" 529 | integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== 530 | dependencies: 531 | estraverse "^5.1.0" 532 | 533 | esrecurse@^4.3.0: 534 | version "4.3.0" 535 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" 536 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 537 | dependencies: 538 | estraverse "^5.2.0" 539 | 540 | estraverse@^5.1.0, estraverse@^5.2.0: 541 | version "5.3.0" 542 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" 543 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 544 | 545 | esutils@^2.0.2: 546 | version "2.0.3" 547 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 548 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 549 | 550 | fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: 551 | version "3.1.3" 552 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 553 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 554 | 555 | fast-glob@^3.2.9: 556 | version "3.3.2" 557 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" 558 | integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== 559 | dependencies: 560 | "@nodelib/fs.stat" "^2.0.2" 561 | "@nodelib/fs.walk" "^1.2.3" 562 | glob-parent "^5.1.2" 563 | merge2 "^1.3.0" 564 | micromatch "^4.0.4" 565 | 566 | fast-json-stable-stringify@^2.0.0: 567 | version "2.1.0" 568 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 569 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 570 | 571 | fast-levenshtein@^2.0.6: 572 | version "2.0.6" 573 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 574 | integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 575 | 576 | fastq@^1.6.0: 577 | version "1.17.1" 578 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" 579 | integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== 580 | dependencies: 581 | reusify "^1.0.4" 582 | 583 | file-entry-cache@^6.0.1: 584 | version "6.0.1" 585 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 586 | integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 587 | dependencies: 588 | flat-cache "^3.0.4" 589 | 590 | fill-range@^7.0.1: 591 | version "7.0.1" 592 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 593 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 594 | dependencies: 595 | to-regex-range "^5.0.1" 596 | 597 | find-up@^5.0.0: 598 | version "5.0.0" 599 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 600 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 601 | dependencies: 602 | locate-path "^6.0.0" 603 | path-exists "^4.0.0" 604 | 605 | flat-cache@^3.0.4: 606 | version "3.2.0" 607 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" 608 | integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== 609 | dependencies: 610 | flatted "^3.2.9" 611 | keyv "^4.5.3" 612 | rimraf "^3.0.2" 613 | 614 | flatted@^3.2.9: 615 | version "3.3.1" 616 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" 617 | integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== 618 | 619 | fs.realpath@^1.0.0: 620 | version "1.0.0" 621 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 622 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 623 | 624 | glob-parent@^5.1.2: 625 | version "5.1.2" 626 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 627 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 628 | dependencies: 629 | is-glob "^4.0.1" 630 | 631 | glob-parent@^6.0.2: 632 | version "6.0.2" 633 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" 634 | integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 635 | dependencies: 636 | is-glob "^4.0.3" 637 | 638 | glob@^7.1.3: 639 | version "7.2.3" 640 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 641 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 642 | dependencies: 643 | fs.realpath "^1.0.0" 644 | inflight "^1.0.4" 645 | inherits "2" 646 | minimatch "^3.1.1" 647 | once "^1.3.0" 648 | path-is-absolute "^1.0.0" 649 | 650 | globals@^13.19.0: 651 | version "13.24.0" 652 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" 653 | integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== 654 | dependencies: 655 | type-fest "^0.20.2" 656 | 657 | globby@^11.1.0: 658 | version "11.1.0" 659 | resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" 660 | integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== 661 | dependencies: 662 | array-union "^2.1.0" 663 | dir-glob "^3.0.1" 664 | fast-glob "^3.2.9" 665 | ignore "^5.2.0" 666 | merge2 "^1.4.1" 667 | slash "^3.0.0" 668 | 669 | graphemer@^1.4.0: 670 | version "1.4.0" 671 | resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" 672 | integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== 673 | 674 | has-flag@^4.0.0: 675 | version "4.0.0" 676 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 677 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 678 | 679 | ignore@^5.2.0, ignore@^5.3.1: 680 | version "5.3.1" 681 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" 682 | integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== 683 | 684 | import-fresh@^3.2.1: 685 | version "3.3.0" 686 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 687 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 688 | dependencies: 689 | parent-module "^1.0.0" 690 | resolve-from "^4.0.0" 691 | 692 | imurmurhash@^0.1.4: 693 | version "0.1.4" 694 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 695 | integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 696 | 697 | inflight@^1.0.4: 698 | version "1.0.6" 699 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 700 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 701 | dependencies: 702 | once "^1.3.0" 703 | wrappy "1" 704 | 705 | inherits@2: 706 | version "2.0.4" 707 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 708 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 709 | 710 | is-extglob@^2.1.1: 711 | version "2.1.1" 712 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 713 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 714 | 715 | is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: 716 | version "4.0.3" 717 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 718 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 719 | dependencies: 720 | is-extglob "^2.1.1" 721 | 722 | is-number@^7.0.0: 723 | version "7.0.0" 724 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 725 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 726 | 727 | is-path-inside@^3.0.3: 728 | version "3.0.3" 729 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 730 | integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 731 | 732 | isexe@^2.0.0: 733 | version "2.0.0" 734 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 735 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 736 | 737 | js-yaml@^4.1.0: 738 | version "4.1.0" 739 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 740 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 741 | dependencies: 742 | argparse "^2.0.1" 743 | 744 | json-buffer@3.0.1: 745 | version "3.0.1" 746 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" 747 | integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== 748 | 749 | json-schema-traverse@^0.4.1: 750 | version "0.4.1" 751 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 752 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 753 | 754 | json-stable-stringify-without-jsonify@^1.0.1: 755 | version "1.0.1" 756 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" 757 | integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== 758 | 759 | keyv@^4.5.3: 760 | version "4.5.4" 761 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" 762 | integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== 763 | dependencies: 764 | json-buffer "3.0.1" 765 | 766 | levn@^0.4.1: 767 | version "0.4.1" 768 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" 769 | integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== 770 | dependencies: 771 | prelude-ls "^1.2.1" 772 | type-check "~0.4.0" 773 | 774 | locate-path@^6.0.0: 775 | version "6.0.0" 776 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 777 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 778 | dependencies: 779 | p-locate "^5.0.0" 780 | 781 | lodash.merge@^4.6.2: 782 | version "4.6.2" 783 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" 784 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 785 | 786 | lru-cache@^6.0.0: 787 | version "6.0.0" 788 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 789 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 790 | dependencies: 791 | yallist "^4.0.0" 792 | 793 | merge2@^1.3.0, merge2@^1.4.1: 794 | version "1.4.1" 795 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 796 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 797 | 798 | micromatch@^4.0.4: 799 | version "4.0.5" 800 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" 801 | integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== 802 | dependencies: 803 | braces "^3.0.2" 804 | picomatch "^2.3.1" 805 | 806 | minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: 807 | version "3.1.2" 808 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 809 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 810 | dependencies: 811 | brace-expansion "^1.1.7" 812 | 813 | minimatch@^9.0.4: 814 | version "9.0.4" 815 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" 816 | integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== 817 | dependencies: 818 | brace-expansion "^2.0.1" 819 | 820 | ms@2.1.2: 821 | version "2.1.2" 822 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 823 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 824 | 825 | natural-compare@^1.4.0: 826 | version "1.4.0" 827 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 828 | integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== 829 | 830 | once@^1.3.0, once@^1.4.0: 831 | version "1.4.0" 832 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 833 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 834 | dependencies: 835 | wrappy "1" 836 | 837 | optionator@^0.9.3: 838 | version "0.9.3" 839 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" 840 | integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== 841 | dependencies: 842 | "@aashutoshrathi/word-wrap" "^1.2.3" 843 | deep-is "^0.1.3" 844 | fast-levenshtein "^2.0.6" 845 | levn "^0.4.1" 846 | prelude-ls "^1.2.1" 847 | type-check "^0.4.0" 848 | 849 | p-limit@^3.0.2: 850 | version "3.1.0" 851 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 852 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 853 | dependencies: 854 | yocto-queue "^0.1.0" 855 | 856 | p-locate@^5.0.0: 857 | version "5.0.0" 858 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 859 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 860 | dependencies: 861 | p-limit "^3.0.2" 862 | 863 | parent-module@^1.0.0: 864 | version "1.0.1" 865 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 866 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 867 | dependencies: 868 | callsites "^3.0.0" 869 | 870 | path-exists@^4.0.0: 871 | version "4.0.0" 872 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 873 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 874 | 875 | path-is-absolute@^1.0.0: 876 | version "1.0.1" 877 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 878 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 879 | 880 | path-key@^3.1.0: 881 | version "3.1.1" 882 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 883 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 884 | 885 | path-type@^4.0.0: 886 | version "4.0.0" 887 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 888 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 889 | 890 | picomatch@^2.3.1: 891 | version "2.3.1" 892 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 893 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 894 | 895 | prelude-ls@^1.2.1: 896 | version "1.2.1" 897 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" 898 | integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== 899 | 900 | punycode@^2.1.0: 901 | version "2.3.1" 902 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" 903 | integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== 904 | 905 | queue-microtask@^1.2.2: 906 | version "1.2.3" 907 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 908 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 909 | 910 | resolve-from@^4.0.0: 911 | version "4.0.0" 912 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 913 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 914 | 915 | reusify@^1.0.4: 916 | version "1.0.4" 917 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 918 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 919 | 920 | rimraf@^3.0.2: 921 | version "3.0.2" 922 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 923 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 924 | dependencies: 925 | glob "^7.1.3" 926 | 927 | run-parallel@^1.1.9: 928 | version "1.2.0" 929 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 930 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 931 | dependencies: 932 | queue-microtask "^1.2.2" 933 | 934 | semver@^7.6.0: 935 | version "7.6.0" 936 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" 937 | integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== 938 | dependencies: 939 | lru-cache "^6.0.0" 940 | 941 | shebang-command@^2.0.0: 942 | version "2.0.0" 943 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 944 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 945 | dependencies: 946 | shebang-regex "^3.0.0" 947 | 948 | shebang-regex@^3.0.0: 949 | version "3.0.0" 950 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 951 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 952 | 953 | slash@^3.0.0: 954 | version "3.0.0" 955 | resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" 956 | integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== 957 | 958 | strip-ansi@^6.0.1: 959 | version "6.0.1" 960 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 961 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 962 | dependencies: 963 | ansi-regex "^5.0.1" 964 | 965 | strip-json-comments@^3.1.1: 966 | version "3.1.1" 967 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 968 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 969 | 970 | supports-color@^7.1.0: 971 | version "7.2.0" 972 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 973 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 974 | dependencies: 975 | has-flag "^4.0.0" 976 | 977 | text-table@^0.2.0: 978 | version "0.2.0" 979 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 980 | integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== 981 | 982 | to-regex-range@^5.0.1: 983 | version "5.0.1" 984 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 985 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 986 | dependencies: 987 | is-number "^7.0.0" 988 | 989 | ts-api-utils@^1.3.0: 990 | version "1.3.0" 991 | resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" 992 | integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== 993 | 994 | tunnel@^0.0.6: 995 | version "0.0.6" 996 | resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" 997 | integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== 998 | 999 | type-check@^0.4.0, type-check@~0.4.0: 1000 | version "0.4.0" 1001 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" 1002 | integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== 1003 | dependencies: 1004 | prelude-ls "^1.2.1" 1005 | 1006 | type-fest@^0.20.2: 1007 | version "0.20.2" 1008 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 1009 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 1010 | 1011 | typescript@5.4.5: 1012 | version "5.4.5" 1013 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" 1014 | integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== 1015 | 1016 | undici@^5.25.4: 1017 | version "5.28.4" 1018 | resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" 1019 | integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== 1020 | dependencies: 1021 | "@fastify/busboy" "^2.0.0" 1022 | 1023 | universal-user-agent@^6.0.0: 1024 | version "6.0.1" 1025 | resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" 1026 | integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== 1027 | 1028 | uri-js@^4.2.2: 1029 | version "4.4.1" 1030 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 1031 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 1032 | dependencies: 1033 | punycode "^2.1.0" 1034 | 1035 | uuid@^8.3.2: 1036 | version "8.3.2" 1037 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" 1038 | integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== 1039 | 1040 | which@^2.0.1: 1041 | version "2.0.2" 1042 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1043 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1044 | dependencies: 1045 | isexe "^2.0.0" 1046 | 1047 | wrappy@1: 1048 | version "1.0.2" 1049 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1050 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 1051 | 1052 | yallist@^4.0.0: 1053 | version "4.0.0" 1054 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1055 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1056 | 1057 | yocto-queue@^0.1.0: 1058 | version "0.1.0" 1059 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 1060 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 1061 | --------------------------------------------------------------------------------