├── .github ├── ISSUE_TEMPLATE │ ├── 01_help.md │ ├── 02_bug.md │ ├── 03_feature_request.md │ └── 04_thanks.md ├── renovate.json └── workflows │ ├── release.yml │ ├── test.yml │ └── update-prettier.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── scripts └── build.mjs ├── src ├── compose-config-get.ts ├── index.ts ├── types.ts ├── util │ ├── extends-to-get-content-params.ts │ ├── get-config-file.ts │ └── get-config-files.ts └── version.ts ├── test ├── __snapshots__ │ └── get.test.ts.snap ├── get.test.ts ├── issues.test.ts ├── smoke.test.ts └── tsconfig.test.json ├── tsconfig.json └── vite.config.js /.github/ISSUE_TEMPLATE/01_help.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🆘 Help" 3 | about: "How does this even work 🤷‍♂️" 4 | labels: support 5 | --- 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02_bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🐛 Bug Report" 3 | about: "If something isn't working as expected 🤔" 4 | labels: bug 5 | --- 6 | 7 | 8 | 9 | **What happened?** 10 | 11 | 12 | 13 | **What did you expect to happen?** 14 | 15 | 16 | 17 | **What the problem might be** 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/03_feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🧚‍♂️ Feature Request" 3 | about: "Wouldn’t it be nice if 💭" 4 | labels: feature 5 | --- 6 | 7 | 8 | 9 | **What’s missing?** 10 | 11 | 12 | 13 | **Why?** 14 | 15 | 16 | 17 | **Alternatives you tried** 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/04_thanks.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "💝 Thank you" 3 | about: "@probot/octokit-plugin-config is awesome 🙌" 4 | labels: thanks 5 | --- 6 | 7 | 8 | 9 | **How do you use @probot/octokit-plugin-config?** 10 | 11 | 12 | 13 | **What do you love about it?** 14 | 15 | 16 | 17 | **How did you learn about it?** 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "github>probot/.github" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | "on": 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | release: 8 | name: release 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: lts/* 15 | cache: npm 16 | - run: npm ci 17 | - run: npm run build 18 | - run: npx semantic-release 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | NPM_TOKEN: ${{ secrets.PROBOTBOT_NPM_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | types: [opened, synchronize] 8 | 9 | jobs: 10 | test_matrix: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | node_version: 15 | - 18 16 | - 20 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Use Node.js ${{ matrix.node_version }} 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: ${{ matrix.node_version }} 23 | cache: npm 24 | - run: npm ci 25 | - run: npm test 26 | test: 27 | runs-on: ubuntu-latest 28 | needs: test_matrix 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: actions/setup-node@v4 32 | with: 33 | cache: npm 34 | node-version: 18 35 | - run: npm ci 36 | - run: npm run lint 37 | - run: npm run build 38 | -------------------------------------------------------------------------------- /.github/workflows/update-prettier.yml: -------------------------------------------------------------------------------- 1 | name: Update Prettier 2 | "on": 3 | push: 4 | branches: 5 | - dependabot/npm_and_yarn/prettier-* 6 | jobs: 7 | update_prettier: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - uses: actions/setup-node@v4 12 | with: 13 | cache: npm 14 | node-version: 18 15 | - run: npm ci 16 | - run: npm run lint:fix 17 | - uses: gr2m/create-or-update-pull-request-action@v1.x 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | title: Prettier updated 22 | body: An update to prettier required updates to your code. 23 | branch: ${{ github.ref }} 24 | commit-message: "style: prettier" 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | node_modules/ 3 | pkg/ 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at opensource+probot@github.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [https://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: https://contributor-covenant.org 74 | [version]: https://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). 4 | By participating in this project you agree to abide by its terms. 5 | 6 | ## Creating an Issue 7 | 8 | Before you create a new Issue: 9 | 10 | 1. Please make sure there is no [open issue](https://github.com/probot/octokit-plugin-config/issues?utf8=%E2%9C%93&q=is%3Aissue) yet. 11 | 2. If it is a bug report, include the steps to reproduce the issue and please create a reproducible test case on [runkit.com](https://runkit.com/). Example: https://runkit.com/gr2m/5aa034f1440b420012a6eebf 12 | 3. If it is a feature request, please share the motivation for the new feature, what alternatives you tried, and how you would implement it. 13 | 4. Please include links to the corresponding github documentation. 14 | 15 | ## Setup the repository locally 16 | 17 | First, fork the repository. 18 | 19 | Setup the repository locally. Replace `` with the name of the account you forked to. 20 | 21 | ```shell 22 | git clone https://github.com//octokit-plugin-config.git 23 | cd octokit-plugin-config 24 | npm install 25 | ``` 26 | 27 | Run the tests before making changes to make sure the local setup is working as expected 28 | 29 | ```shell 30 | npm test 31 | ``` 32 | 33 | ## Submitting the Pull Request 34 | 35 | - Create a new branch locally. 36 | - Make your changes in that branch and push them to your fork 37 | - Submit a pull request from your topic branch to the main branch on the `probot/octokit-plugin-config` repository. 38 | - Be sure to tag any issues your pull request is taking care of / contributing to. Adding "Closes #123" to a pull request description will automatically close the issue once the pull request is merged in. 39 | 40 | ## Testing a pull request from github repo locally: 41 | 42 | You can install `@probot/octokit-plugin-config` from each pull request. Replace `[PULL REQUEST NUMBER]`: 43 | 44 | ``` 45 | npm install https://github.pika.dev/probot/octokit-plugin-config/pr/[PULL REQUEST NUMBER] 46 | ``` 47 | 48 | Once you are done testing, you can revert back to the default module `@probot/octokit-plugin-config` from npm with `npm install @probot/octokit-plugin-config` 49 | 50 | ## Merging the Pull Request & releasing a new version 51 | 52 | Releases are automated using [semantic-release](https://github.com/semantic-release/semantic-release). 53 | The following commit message conventions determine which version is released: 54 | 55 | 1. `fix: ...` or `fix(scope name): ...` prefix in subject: bumps fix version, e.g. `1.2.3` → `1.2.4` 56 | 2. `feat: ...` or `feat(scope name): ...` prefix in subject: bumps feature version, e.g. `1.2.3` → `1.3.0` 57 | 3. `BREAKING CHANGE:` in body: bumps breaking version, e.g. `1.2.3` → `2.0.0` 58 | 59 | Only one version number is bumped at a time, the highest version change trumps the others. 60 | Besides publishing a new version to npm, semantic-release also creates a git tag and release 61 | on GitHub, generates changelogs from the commit messages and puts them into the release notes. 62 | 63 | Before the publish it runs the `npm run build` script which creates a `pkg/` folder with distributions for browsers, node and Typescript definitions. The contents of the `pkg/` folder are published to the npm registry. 64 | 65 | If the pull request looks good but does not follow the commit conventions, use the Squash & merge button. 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2020 Probot Contributors 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # octokit-plugin-config 2 | 3 | > Get/set persisted configuration using YAML/JSON files in repositories 4 | 5 | [![@latest](https://img.shields.io/npm/v/@probot/octokit-plugin-config.svg)](https://www.npmjs.com/package/@probot/octokit-plugin-config) 6 | [![Build Status](https://github.com/probot/octokit-plugin-config/workflows/Test/badge.svg)](https://github.com/probot/octokit-plugin-config/actions?query=workflow%3ATest+branch%3Amain) 7 | [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=probot/octokit-plugin-config)](https://dependabot.com/) 8 | 9 | By default, this plugin loads configuration from a given repository file. If the file doesn't exist, it loads configuration from the same path in the same owner's `.github` repository. 10 | 11 | Configuration can be extended across multiple files using [the `_extends` key](#extends). 12 | 13 | ## Usage 14 | 15 | 16 | 17 | 36 | 50 | 51 |
18 | 19 | Browsers 20 | 21 | 22 | 23 | Load `@probot/octokit-plugin-config` and [`@octokit/core`](https://github.com/octokit/core.js) (or core-compatible module) directly from [cdn.pika.dev](https://cdn.pika.dev) 24 | 25 | ```html 26 | 33 | ``` 34 | 35 |
37 | 38 | Node 39 | 40 | 41 | 42 | Install with `npm install @octokit/core @probot/octokit-plugin-config`. Optionally replace `@octokit/core` with a compatible module 43 | 44 | ```js 45 | const { Octokit } = require("@octokit/core"); 46 | const { config, composeConfigGet } = require("@probot/octokit-plugin-config"); 47 | ``` 48 | 49 |
52 | 53 | ```js 54 | // given that `.github/my-app.yml` in `octocat/hello-world` has the following content 55 | // 56 | // comment: 'Thank you for creating the issue!' 57 | // 58 | const { config } = await octokit.config.get({ 59 | owner: "octocat", 60 | repo: "hello-world", 61 | path: ".github/my-app.yml", 62 | }); 63 | // config is now { comment: "Thank you for creating the issue!" } 64 | 65 | // all options and returns 66 | const { config, files } = await octokit.config.get({ 67 | owner: "octocat", 68 | repo: "hello-world", 69 | path: ".github/my-app.yml", 70 | defaults: { 71 | comment: "Thank you for creating the issue!", 72 | }, 73 | branch: "develop", 74 | }); 75 | // files is an array of { owner, repo, path, config } objects 76 | ``` 77 | 78 | ## Options 79 | 80 | 81 | 82 | 83 | 86 | 89 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 101 | 102 | 103 | 104 | 105 | 108 | 109 | 110 | 111 | 112 | 115 | 116 | 117 | 118 | 119 | 122 | 123 | 124 | 125 | 126 | 129 | 130 | 131 |
84 | option 85 | 87 | type 88 | 90 | description 91 |
ownerString 99 | Required. Repository owner login. 100 |
repoString 106 | Required. Repository name. 107 |
pathString 113 | Required. Path of the configuration file. Supported file extensions are .yml, .yaml, and .json. 114 |
defaultsString 120 | Default options that are returned if the configuration file does not exist, or merged with the contents if it does exist. Defaults are merged shallowly using Object.assign. For custom merge strategies, you can set defaults to a function, see Merging configuration below for more information. Defaults to {}. 121 |
branchString 127 | Defaults to the repository's default branch. The branch is only used for the provided repository, not for the .github repository or other configurations linked using the _extends key. 128 |
132 | 133 | 134 | 135 | ### The `_extends` key 136 | 137 | `octokit.config.get()` supports sharing configs between repositories. If configuration for your app is not available in the target repository, it will be loaded from the `.github` directory of the same owner's `.github` repository. 138 | 139 | You can choose own shared location. Use the `_extends` option in the configuration file to extend settings from another repository. 140 | 141 | For example, given `.github/test.yml`: 142 | 143 | ```yml 144 | _extends: github-settings 145 | # Override values from the extended config or define new values 146 | name: myrepo 147 | ``` 148 | 149 | This configuration will be merged with the `.github/test.yml` file from the `github-settings` repository, which might look like this: 150 | 151 | ```yml 152 | shared1: will be merged 153 | shared2: will also be merged 154 | ``` 155 | 156 | Just put common configuration keys in a repository within your organization. Then reference this repository from config files with the same name. 157 | 158 | You can also reference configurations from other owners: 159 | 160 | ```yml 161 | _extends: other/probot-settings 162 | other: DDD 163 | ``` 164 | 165 | Additionally, you can specify a specific path for the configuration by appending a colon after the project. 166 | 167 | ```yml 168 | _extends: probot-settings:.github/other_test.yml 169 | other: FFF 170 | ``` 171 | 172 | 173 | 174 | ### Merging configuration 175 | 176 | Given `.github/test.yml`: 177 | 178 | ```yml 179 | settings: 180 | one: value from configuration 181 | ``` 182 | 183 | And 184 | 185 | ```js 186 | const { config } = await octokit.config.get({ 187 | owner, 188 | repo, 189 | path: ".github/test.yml", 190 | defaults: { 191 | settings: { 192 | one: "default value", 193 | two: "default value", 194 | }, 195 | }, 196 | }); 197 | ``` 198 | 199 | The resulting `config` object is 200 | 201 | ```js 202 | { 203 | settings: { 204 | one: "value from configuration"; 205 | } 206 | } 207 | ``` 208 | 209 | And not as you might expect 210 | 211 | ```js 212 | { 213 | settings: { 214 | one: "value from configuration"; 215 | two: "default value"; 216 | } 217 | } 218 | ``` 219 | 220 | The reason for that behavior is that merging objects deeply is not supported in JavaScript by default, and there are different strategies and many pitfals. There are many libraries that support deep merging in different ways, but instead making that decision for and significantly increasing the bundle size of this plugin, we let you pass a custom merge strategy instead. 221 | 222 | In order to achive the deeply merged configuration, the `defaults` option can be set to a function. The function receives one `configs` argument, which is an array of configurations loaded from files in reverse order, so that the latter items should take precedence over the former items. The `configs` array can have more than one object if [the `_extends` key](#extends) is used. 223 | 224 | ```js 225 | const defaults = { 226 | settings: { 227 | one: "default value", 228 | two: "default value", 229 | }, 230 | }; 231 | const { config } = await octokit.config.get({ 232 | owner, 233 | repo, 234 | path: ".github/test.yml", 235 | defaults(configs) { 236 | const allConfigs = [defaults, ...configs]; 237 | const fileSettingsConfigs = allConfigs.map( 238 | (config: Configuration) => config.settings 239 | ); 240 | return Object.assign({}, ...allConfigs, { 241 | settings: Object.assign({}, ...fileSettingsConfigs), 242 | }); 243 | }, 244 | }); 245 | ``` 246 | 247 | Or simpler, using a library such as [deepmerge](https://github.com/TehShrike/deepmerge) 248 | 249 | ```js 250 | const { config } = await octokit.config.get({ 251 | owner, 252 | repo, 253 | path: ".github/test.yml", 254 | defaults: (configs) => deepmerge.all([defaults, ...configs]), 255 | }); 256 | ``` 257 | 258 | ## Testing 259 | 260 | Writing tests for your app's usage of `octokit.config.get` can be tricky. It's tempting to just mock the method directly, e.g. using [a Jest mock function](https://jestjs.io/docs/en/mock-functions) 261 | 262 | ```js 263 | octokit.config.get = jest.fn().mockResolvedValue({ 264 | comment: "Thank you for creating the issue!", 265 | }); 266 | ``` 267 | 268 | The problem with this approach is that in future releases of `@probot/octokit-plugin-config`, the method name or parameters might change. Before that happens, we will log a deprecation message, to make the upgrade to the next breaking version easier. If all your tests mock the `.config.get()` method, then you won't see this deprecation message. Even worse, your tests will continue to pass, but fail in production, because the mock will revert any future changes to `.config.get()`. 269 | 270 | We recommend you have at least one test that does not mock the method, but instead mocks the http responses. You can achiev that with [nock](https://github.com/nock/nock/) or [fetch-mock](https://github.com/wheresrhys/fetch-mock) 271 | 272 | ### Testing with `nock` 273 | 274 | With configuration 275 | 276 | ```js 277 | async function myTest() { 278 | nock("https://api.github.com") 279 | .get("/repos/octocat/hello-world/contents/.github%2Fmy-app.yml") 280 | .reply(200, "comment: Thank you for creating the issue"); 281 | 282 | const octokit = new Octokit(); 283 | 284 | const { config } = await octokit.config.get({ 285 | owner: "octocat", 286 | repo: "hello-world", 287 | path: ".github/my-app.yml", 288 | }); 289 | 290 | assert.deepStrictEqual(config, { 291 | comment: "Thank you for creating the issue!", 292 | }); 293 | } 294 | ``` 295 | 296 | Without configuration 297 | 298 | ```js 299 | async function myTest() { 300 | nock("https://api.github.com") 301 | .get("/repos/octocat/hello-world/contents/.github%2Fmy-app.yml") 302 | .reply(404) 303 | .get("/repos/octocat/.github/contents/.github%2Fmy-app.yml") 304 | .reply(404); 305 | 306 | const octokit = new Octokit(); 307 | 308 | const { config } = await octokit.config.get({ 309 | owner: "octocat", 310 | repo: "hello-world", 311 | path: ".github/my-app.yml", 312 | }); 313 | 314 | assert.deepStrictEqual(config, {}); 315 | } 316 | ``` 317 | 318 | ### Testing with `fetch-mock` 319 | 320 | With configuration 321 | 322 | ```js 323 | async function myTest() { 324 | const fetch = fetchMock 325 | .sandbox() 326 | .getOnce( 327 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 328 | "comment: 'Thank you for creating the issue!'", 329 | ); 330 | const octokit = new TestOctokit({ 331 | request: { fetch }, 332 | }); 333 | 334 | const { config } = await octokit.config.get({ 335 | owner: "octocat", 336 | repo: "hello-world", 337 | path: ".github/my-app.yml", 338 | }); 339 | 340 | assert.deepStrictEqual(config, { 341 | comment: "Thank you for creating the issue!", 342 | }); 343 | } 344 | ``` 345 | 346 | Without configuration 347 | 348 | ```js 349 | async function myTest() { 350 | const fetch = fetchMock 351 | .sandbox() 352 | .getOnce( 353 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 354 | 404, 355 | ) 356 | .getOnce( 357 | "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 358 | 404, 359 | ); 360 | const octokit = new TestOctokit({ 361 | request: { fetch }, 362 | }); 363 | 364 | const { config } = await octokit.config.get({ 365 | owner: "octocat", 366 | repo: "hello-world", 367 | path: ".github/my-app.yml", 368 | }); 369 | 370 | assert.deepStrictEqual(config, {}); 371 | } 372 | ``` 373 | 374 | ## Contributing 375 | 376 | See [CONTRIBUTING.md](CONTRIBUTING.md) 377 | 378 | ## Credits 379 | 380 | The idea for this plugin and some of its code was extracted from [Probot](https://probot.github.io/). It originated as [probot-config](https://github.com/probot/probot-config), created by [Jan Michael Auer](https://github.com/jan-auer) and was later merged into [`probot`](https://github.com/probot/probot). 381 | 382 | ## License 383 | 384 | [ISC](LICENSE) 385 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@probot/octokit-plugin-config", 3 | "version": "0.0.0-development", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@probot/octokit-plugin-config", 9 | "version": "0.0.0-development", 10 | "license": "MIT", 11 | "dependencies": { 12 | "js-yaml": "^4.1.0" 13 | }, 14 | "devDependencies": { 15 | "@octokit/core": "^6.0.1", 16 | "@octokit/tsconfig": "^3.0.0", 17 | "@types/js-yaml": "^4.0.5", 18 | "@types/node": "^20.0.0", 19 | "@vitest/coverage-v8": "^3.0.0", 20 | "esbuild": "^0.25.0", 21 | "fetch-mock": "^10.0.0", 22 | "prettier": "^3.0.0", 23 | "semantic-release-plugin-update-version-in-files": "^2.0.0", 24 | "strip-indent": "^4.0.0", 25 | "typescript": "^5.0.0", 26 | "vitest": "^3.0.0" 27 | }, 28 | "engines": { 29 | "node": ">=18" 30 | }, 31 | "peerDependencies": { 32 | "@octokit/core": ">=5" 33 | } 34 | }, 35 | "node_modules/@ampproject/remapping": { 36 | "version": "2.3.0", 37 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", 38 | "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", 39 | "dev": true, 40 | "license": "Apache-2.0", 41 | "dependencies": { 42 | "@jridgewell/gen-mapping": "^0.3.5", 43 | "@jridgewell/trace-mapping": "^0.3.24" 44 | }, 45 | "engines": { 46 | "node": ">=6.0.0" 47 | } 48 | }, 49 | "node_modules/@babel/helper-string-parser": { 50 | "version": "7.27.1", 51 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", 52 | "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", 53 | "dev": true, 54 | "license": "MIT", 55 | "engines": { 56 | "node": ">=6.9.0" 57 | } 58 | }, 59 | "node_modules/@babel/helper-validator-identifier": { 60 | "version": "7.27.1", 61 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", 62 | "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", 63 | "dev": true, 64 | "license": "MIT", 65 | "engines": { 66 | "node": ">=6.9.0" 67 | } 68 | }, 69 | "node_modules/@babel/parser": { 70 | "version": "7.27.2", 71 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", 72 | "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", 73 | "dev": true, 74 | "license": "MIT", 75 | "dependencies": { 76 | "@babel/types": "^7.27.1" 77 | }, 78 | "bin": { 79 | "parser": "bin/babel-parser.js" 80 | }, 81 | "engines": { 82 | "node": ">=6.0.0" 83 | } 84 | }, 85 | "node_modules/@babel/types": { 86 | "version": "7.27.1", 87 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", 88 | "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", 89 | "dev": true, 90 | "license": "MIT", 91 | "dependencies": { 92 | "@babel/helper-string-parser": "^7.27.1", 93 | "@babel/helper-validator-identifier": "^7.27.1" 94 | }, 95 | "engines": { 96 | "node": ">=6.9.0" 97 | } 98 | }, 99 | "node_modules/@bcoe/v8-coverage": { 100 | "version": "1.0.2", 101 | "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", 102 | "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", 103 | "dev": true, 104 | "license": "MIT", 105 | "engines": { 106 | "node": ">=18" 107 | } 108 | }, 109 | "node_modules/@esbuild/aix-ppc64": { 110 | "version": "0.25.4", 111 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", 112 | "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", 113 | "cpu": [ 114 | "ppc64" 115 | ], 116 | "dev": true, 117 | "license": "MIT", 118 | "optional": true, 119 | "os": [ 120 | "aix" 121 | ], 122 | "engines": { 123 | "node": ">=18" 124 | } 125 | }, 126 | "node_modules/@esbuild/android-arm": { 127 | "version": "0.25.4", 128 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", 129 | "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", 130 | "cpu": [ 131 | "arm" 132 | ], 133 | "dev": true, 134 | "license": "MIT", 135 | "optional": true, 136 | "os": [ 137 | "android" 138 | ], 139 | "engines": { 140 | "node": ">=18" 141 | } 142 | }, 143 | "node_modules/@esbuild/android-arm64": { 144 | "version": "0.25.4", 145 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", 146 | "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", 147 | "cpu": [ 148 | "arm64" 149 | ], 150 | "dev": true, 151 | "license": "MIT", 152 | "optional": true, 153 | "os": [ 154 | "android" 155 | ], 156 | "engines": { 157 | "node": ">=18" 158 | } 159 | }, 160 | "node_modules/@esbuild/android-x64": { 161 | "version": "0.25.4", 162 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", 163 | "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", 164 | "cpu": [ 165 | "x64" 166 | ], 167 | "dev": true, 168 | "license": "MIT", 169 | "optional": true, 170 | "os": [ 171 | "android" 172 | ], 173 | "engines": { 174 | "node": ">=18" 175 | } 176 | }, 177 | "node_modules/@esbuild/darwin-arm64": { 178 | "version": "0.25.4", 179 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", 180 | "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", 181 | "cpu": [ 182 | "arm64" 183 | ], 184 | "dev": true, 185 | "license": "MIT", 186 | "optional": true, 187 | "os": [ 188 | "darwin" 189 | ], 190 | "engines": { 191 | "node": ">=18" 192 | } 193 | }, 194 | "node_modules/@esbuild/darwin-x64": { 195 | "version": "0.25.4", 196 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", 197 | "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", 198 | "cpu": [ 199 | "x64" 200 | ], 201 | "dev": true, 202 | "license": "MIT", 203 | "optional": true, 204 | "os": [ 205 | "darwin" 206 | ], 207 | "engines": { 208 | "node": ">=18" 209 | } 210 | }, 211 | "node_modules/@esbuild/freebsd-arm64": { 212 | "version": "0.25.4", 213 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", 214 | "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", 215 | "cpu": [ 216 | "arm64" 217 | ], 218 | "dev": true, 219 | "license": "MIT", 220 | "optional": true, 221 | "os": [ 222 | "freebsd" 223 | ], 224 | "engines": { 225 | "node": ">=18" 226 | } 227 | }, 228 | "node_modules/@esbuild/freebsd-x64": { 229 | "version": "0.25.4", 230 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", 231 | "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", 232 | "cpu": [ 233 | "x64" 234 | ], 235 | "dev": true, 236 | "license": "MIT", 237 | "optional": true, 238 | "os": [ 239 | "freebsd" 240 | ], 241 | "engines": { 242 | "node": ">=18" 243 | } 244 | }, 245 | "node_modules/@esbuild/linux-arm": { 246 | "version": "0.25.4", 247 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", 248 | "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", 249 | "cpu": [ 250 | "arm" 251 | ], 252 | "dev": true, 253 | "license": "MIT", 254 | "optional": true, 255 | "os": [ 256 | "linux" 257 | ], 258 | "engines": { 259 | "node": ">=18" 260 | } 261 | }, 262 | "node_modules/@esbuild/linux-arm64": { 263 | "version": "0.25.4", 264 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", 265 | "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", 266 | "cpu": [ 267 | "arm64" 268 | ], 269 | "dev": true, 270 | "license": "MIT", 271 | "optional": true, 272 | "os": [ 273 | "linux" 274 | ], 275 | "engines": { 276 | "node": ">=18" 277 | } 278 | }, 279 | "node_modules/@esbuild/linux-ia32": { 280 | "version": "0.25.4", 281 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", 282 | "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", 283 | "cpu": [ 284 | "ia32" 285 | ], 286 | "dev": true, 287 | "license": "MIT", 288 | "optional": true, 289 | "os": [ 290 | "linux" 291 | ], 292 | "engines": { 293 | "node": ">=18" 294 | } 295 | }, 296 | "node_modules/@esbuild/linux-loong64": { 297 | "version": "0.25.4", 298 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", 299 | "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", 300 | "cpu": [ 301 | "loong64" 302 | ], 303 | "dev": true, 304 | "license": "MIT", 305 | "optional": true, 306 | "os": [ 307 | "linux" 308 | ], 309 | "engines": { 310 | "node": ">=18" 311 | } 312 | }, 313 | "node_modules/@esbuild/linux-mips64el": { 314 | "version": "0.25.4", 315 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", 316 | "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", 317 | "cpu": [ 318 | "mips64el" 319 | ], 320 | "dev": true, 321 | "license": "MIT", 322 | "optional": true, 323 | "os": [ 324 | "linux" 325 | ], 326 | "engines": { 327 | "node": ">=18" 328 | } 329 | }, 330 | "node_modules/@esbuild/linux-ppc64": { 331 | "version": "0.25.4", 332 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", 333 | "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", 334 | "cpu": [ 335 | "ppc64" 336 | ], 337 | "dev": true, 338 | "license": "MIT", 339 | "optional": true, 340 | "os": [ 341 | "linux" 342 | ], 343 | "engines": { 344 | "node": ">=18" 345 | } 346 | }, 347 | "node_modules/@esbuild/linux-riscv64": { 348 | "version": "0.25.4", 349 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", 350 | "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", 351 | "cpu": [ 352 | "riscv64" 353 | ], 354 | "dev": true, 355 | "license": "MIT", 356 | "optional": true, 357 | "os": [ 358 | "linux" 359 | ], 360 | "engines": { 361 | "node": ">=18" 362 | } 363 | }, 364 | "node_modules/@esbuild/linux-s390x": { 365 | "version": "0.25.4", 366 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", 367 | "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", 368 | "cpu": [ 369 | "s390x" 370 | ], 371 | "dev": true, 372 | "license": "MIT", 373 | "optional": true, 374 | "os": [ 375 | "linux" 376 | ], 377 | "engines": { 378 | "node": ">=18" 379 | } 380 | }, 381 | "node_modules/@esbuild/linux-x64": { 382 | "version": "0.25.4", 383 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", 384 | "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", 385 | "cpu": [ 386 | "x64" 387 | ], 388 | "dev": true, 389 | "license": "MIT", 390 | "optional": true, 391 | "os": [ 392 | "linux" 393 | ], 394 | "engines": { 395 | "node": ">=18" 396 | } 397 | }, 398 | "node_modules/@esbuild/netbsd-arm64": { 399 | "version": "0.25.4", 400 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", 401 | "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", 402 | "cpu": [ 403 | "arm64" 404 | ], 405 | "dev": true, 406 | "license": "MIT", 407 | "optional": true, 408 | "os": [ 409 | "netbsd" 410 | ], 411 | "engines": { 412 | "node": ">=18" 413 | } 414 | }, 415 | "node_modules/@esbuild/netbsd-x64": { 416 | "version": "0.25.4", 417 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", 418 | "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", 419 | "cpu": [ 420 | "x64" 421 | ], 422 | "dev": true, 423 | "license": "MIT", 424 | "optional": true, 425 | "os": [ 426 | "netbsd" 427 | ], 428 | "engines": { 429 | "node": ">=18" 430 | } 431 | }, 432 | "node_modules/@esbuild/openbsd-arm64": { 433 | "version": "0.25.4", 434 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", 435 | "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", 436 | "cpu": [ 437 | "arm64" 438 | ], 439 | "dev": true, 440 | "license": "MIT", 441 | "optional": true, 442 | "os": [ 443 | "openbsd" 444 | ], 445 | "engines": { 446 | "node": ">=18" 447 | } 448 | }, 449 | "node_modules/@esbuild/openbsd-x64": { 450 | "version": "0.25.4", 451 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", 452 | "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", 453 | "cpu": [ 454 | "x64" 455 | ], 456 | "dev": true, 457 | "license": "MIT", 458 | "optional": true, 459 | "os": [ 460 | "openbsd" 461 | ], 462 | "engines": { 463 | "node": ">=18" 464 | } 465 | }, 466 | "node_modules/@esbuild/sunos-x64": { 467 | "version": "0.25.4", 468 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", 469 | "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", 470 | "cpu": [ 471 | "x64" 472 | ], 473 | "dev": true, 474 | "license": "MIT", 475 | "optional": true, 476 | "os": [ 477 | "sunos" 478 | ], 479 | "engines": { 480 | "node": ">=18" 481 | } 482 | }, 483 | "node_modules/@esbuild/win32-arm64": { 484 | "version": "0.25.4", 485 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", 486 | "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", 487 | "cpu": [ 488 | "arm64" 489 | ], 490 | "dev": true, 491 | "license": "MIT", 492 | "optional": true, 493 | "os": [ 494 | "win32" 495 | ], 496 | "engines": { 497 | "node": ">=18" 498 | } 499 | }, 500 | "node_modules/@esbuild/win32-ia32": { 501 | "version": "0.25.4", 502 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", 503 | "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", 504 | "cpu": [ 505 | "ia32" 506 | ], 507 | "dev": true, 508 | "license": "MIT", 509 | "optional": true, 510 | "os": [ 511 | "win32" 512 | ], 513 | "engines": { 514 | "node": ">=18" 515 | } 516 | }, 517 | "node_modules/@esbuild/win32-x64": { 518 | "version": "0.25.4", 519 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", 520 | "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", 521 | "cpu": [ 522 | "x64" 523 | ], 524 | "dev": true, 525 | "license": "MIT", 526 | "optional": true, 527 | "os": [ 528 | "win32" 529 | ], 530 | "engines": { 531 | "node": ">=18" 532 | } 533 | }, 534 | "node_modules/@isaacs/cliui": { 535 | "version": "8.0.2", 536 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", 537 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", 538 | "dev": true, 539 | "license": "ISC", 540 | "dependencies": { 541 | "string-width": "^5.1.2", 542 | "string-width-cjs": "npm:string-width@^4.2.0", 543 | "strip-ansi": "^7.0.1", 544 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", 545 | "wrap-ansi": "^8.1.0", 546 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" 547 | }, 548 | "engines": { 549 | "node": ">=12" 550 | } 551 | }, 552 | "node_modules/@istanbuljs/schema": { 553 | "version": "0.1.3", 554 | "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", 555 | "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", 556 | "dev": true, 557 | "license": "MIT", 558 | "engines": { 559 | "node": ">=8" 560 | } 561 | }, 562 | "node_modules/@jridgewell/gen-mapping": { 563 | "version": "0.3.8", 564 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", 565 | "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", 566 | "dev": true, 567 | "license": "MIT", 568 | "dependencies": { 569 | "@jridgewell/set-array": "^1.2.1", 570 | "@jridgewell/sourcemap-codec": "^1.4.10", 571 | "@jridgewell/trace-mapping": "^0.3.24" 572 | }, 573 | "engines": { 574 | "node": ">=6.0.0" 575 | } 576 | }, 577 | "node_modules/@jridgewell/resolve-uri": { 578 | "version": "3.1.2", 579 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 580 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 581 | "dev": true, 582 | "license": "MIT", 583 | "engines": { 584 | "node": ">=6.0.0" 585 | } 586 | }, 587 | "node_modules/@jridgewell/set-array": { 588 | "version": "1.2.1", 589 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 590 | "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 591 | "dev": true, 592 | "license": "MIT", 593 | "engines": { 594 | "node": ">=6.0.0" 595 | } 596 | }, 597 | "node_modules/@jridgewell/sourcemap-codec": { 598 | "version": "1.5.0", 599 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 600 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 601 | "dev": true, 602 | "license": "MIT" 603 | }, 604 | "node_modules/@jridgewell/trace-mapping": { 605 | "version": "0.3.25", 606 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 607 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 608 | "dev": true, 609 | "license": "MIT", 610 | "dependencies": { 611 | "@jridgewell/resolve-uri": "^3.1.0", 612 | "@jridgewell/sourcemap-codec": "^1.4.14" 613 | } 614 | }, 615 | "node_modules/@octokit/auth-token": { 616 | "version": "5.1.2", 617 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz", 618 | "integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==", 619 | "dev": true, 620 | "license": "MIT", 621 | "engines": { 622 | "node": ">= 18" 623 | } 624 | }, 625 | "node_modules/@octokit/core": { 626 | "version": "6.1.5", 627 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.5.tgz", 628 | "integrity": "sha512-vvmsN0r7rguA+FySiCsbaTTobSftpIDIpPW81trAmsv9TGxg3YCujAxRYp/Uy8xmDgYCzzgulG62H7KYUFmeIg==", 629 | "dev": true, 630 | "license": "MIT", 631 | "dependencies": { 632 | "@octokit/auth-token": "^5.0.0", 633 | "@octokit/graphql": "^8.2.2", 634 | "@octokit/request": "^9.2.3", 635 | "@octokit/request-error": "^6.1.8", 636 | "@octokit/types": "^14.0.0", 637 | "before-after-hook": "^3.0.2", 638 | "universal-user-agent": "^7.0.0" 639 | }, 640 | "engines": { 641 | "node": ">= 18" 642 | } 643 | }, 644 | "node_modules/@octokit/endpoint": { 645 | "version": "10.1.4", 646 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz", 647 | "integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==", 648 | "dev": true, 649 | "license": "MIT", 650 | "dependencies": { 651 | "@octokit/types": "^14.0.0", 652 | "universal-user-agent": "^7.0.2" 653 | }, 654 | "engines": { 655 | "node": ">= 18" 656 | } 657 | }, 658 | "node_modules/@octokit/graphql": { 659 | "version": "8.2.2", 660 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.2.tgz", 661 | "integrity": "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==", 662 | "dev": true, 663 | "license": "MIT", 664 | "dependencies": { 665 | "@octokit/request": "^9.2.3", 666 | "@octokit/types": "^14.0.0", 667 | "universal-user-agent": "^7.0.0" 668 | }, 669 | "engines": { 670 | "node": ">= 18" 671 | } 672 | }, 673 | "node_modules/@octokit/openapi-types": { 674 | "version": "25.0.0", 675 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.0.0.tgz", 676 | "integrity": "sha512-FZvktFu7HfOIJf2BScLKIEYjDsw6RKc7rBJCdvCTfKsVnx2GEB/Nbzjr29DUdb7vQhlzS/j8qDzdditP0OC6aw==", 677 | "dev": true, 678 | "license": "MIT" 679 | }, 680 | "node_modules/@octokit/request": { 681 | "version": "9.2.3", 682 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.3.tgz", 683 | "integrity": "sha512-Ma+pZU8PXLOEYzsWf0cn/gY+ME57Wq8f49WTXA8FMHp2Ps9djKw//xYJ1je8Hm0pR2lU9FUGeJRWOtxq6olt4w==", 684 | "dev": true, 685 | "license": "MIT", 686 | "dependencies": { 687 | "@octokit/endpoint": "^10.1.4", 688 | "@octokit/request-error": "^6.1.8", 689 | "@octokit/types": "^14.0.0", 690 | "fast-content-type-parse": "^2.0.0", 691 | "universal-user-agent": "^7.0.2" 692 | }, 693 | "engines": { 694 | "node": ">= 18" 695 | } 696 | }, 697 | "node_modules/@octokit/request-error": { 698 | "version": "6.1.8", 699 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.8.tgz", 700 | "integrity": "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==", 701 | "dev": true, 702 | "license": "MIT", 703 | "dependencies": { 704 | "@octokit/types": "^14.0.0" 705 | }, 706 | "engines": { 707 | "node": ">= 18" 708 | } 709 | }, 710 | "node_modules/@octokit/tsconfig": { 711 | "version": "3.1.0", 712 | "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-3.1.0.tgz", 713 | "integrity": "sha512-3jGTGqDnnh/MZlg/sf21J/0cghsmaSnG+ZPK+o++sQwUwgrLVtfbUi/BANHgf22SRnxhdYtOoRX90I9/cP+9BA==", 714 | "dev": true, 715 | "license": "MIT" 716 | }, 717 | "node_modules/@octokit/types": { 718 | "version": "14.0.0", 719 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.0.0.tgz", 720 | "integrity": "sha512-VVmZP0lEhbo2O1pdq63gZFiGCKkm8PPp8AUOijlwPO6hojEVjspA0MWKP7E4hbvGxzFKNqKr6p0IYtOH/Wf/zA==", 721 | "dev": true, 722 | "license": "MIT", 723 | "dependencies": { 724 | "@octokit/openapi-types": "^25.0.0" 725 | } 726 | }, 727 | "node_modules/@pkgjs/parseargs": { 728 | "version": "0.11.0", 729 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 730 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 731 | "dev": true, 732 | "license": "MIT", 733 | "optional": true, 734 | "engines": { 735 | "node": ">=14" 736 | } 737 | }, 738 | "node_modules/@rollup/rollup-android-arm-eabi": { 739 | "version": "4.41.0", 740 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz", 741 | "integrity": "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==", 742 | "cpu": [ 743 | "arm" 744 | ], 745 | "dev": true, 746 | "license": "MIT", 747 | "optional": true, 748 | "os": [ 749 | "android" 750 | ] 751 | }, 752 | "node_modules/@rollup/rollup-android-arm64": { 753 | "version": "4.41.0", 754 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz", 755 | "integrity": "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==", 756 | "cpu": [ 757 | "arm64" 758 | ], 759 | "dev": true, 760 | "license": "MIT", 761 | "optional": true, 762 | "os": [ 763 | "android" 764 | ] 765 | }, 766 | "node_modules/@rollup/rollup-darwin-arm64": { 767 | "version": "4.41.0", 768 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz", 769 | "integrity": "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==", 770 | "cpu": [ 771 | "arm64" 772 | ], 773 | "dev": true, 774 | "license": "MIT", 775 | "optional": true, 776 | "os": [ 777 | "darwin" 778 | ] 779 | }, 780 | "node_modules/@rollup/rollup-darwin-x64": { 781 | "version": "4.41.0", 782 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz", 783 | "integrity": "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==", 784 | "cpu": [ 785 | "x64" 786 | ], 787 | "dev": true, 788 | "license": "MIT", 789 | "optional": true, 790 | "os": [ 791 | "darwin" 792 | ] 793 | }, 794 | "node_modules/@rollup/rollup-freebsd-arm64": { 795 | "version": "4.41.0", 796 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz", 797 | "integrity": "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==", 798 | "cpu": [ 799 | "arm64" 800 | ], 801 | "dev": true, 802 | "license": "MIT", 803 | "optional": true, 804 | "os": [ 805 | "freebsd" 806 | ] 807 | }, 808 | "node_modules/@rollup/rollup-freebsd-x64": { 809 | "version": "4.41.0", 810 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz", 811 | "integrity": "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==", 812 | "cpu": [ 813 | "x64" 814 | ], 815 | "dev": true, 816 | "license": "MIT", 817 | "optional": true, 818 | "os": [ 819 | "freebsd" 820 | ] 821 | }, 822 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 823 | "version": "4.41.0", 824 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz", 825 | "integrity": "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==", 826 | "cpu": [ 827 | "arm" 828 | ], 829 | "dev": true, 830 | "license": "MIT", 831 | "optional": true, 832 | "os": [ 833 | "linux" 834 | ] 835 | }, 836 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 837 | "version": "4.41.0", 838 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz", 839 | "integrity": "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==", 840 | "cpu": [ 841 | "arm" 842 | ], 843 | "dev": true, 844 | "license": "MIT", 845 | "optional": true, 846 | "os": [ 847 | "linux" 848 | ] 849 | }, 850 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 851 | "version": "4.41.0", 852 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz", 853 | "integrity": "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==", 854 | "cpu": [ 855 | "arm64" 856 | ], 857 | "dev": true, 858 | "license": "MIT", 859 | "optional": true, 860 | "os": [ 861 | "linux" 862 | ] 863 | }, 864 | "node_modules/@rollup/rollup-linux-arm64-musl": { 865 | "version": "4.41.0", 866 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz", 867 | "integrity": "sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==", 868 | "cpu": [ 869 | "arm64" 870 | ], 871 | "dev": true, 872 | "license": "MIT", 873 | "optional": true, 874 | "os": [ 875 | "linux" 876 | ] 877 | }, 878 | "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 879 | "version": "4.41.0", 880 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz", 881 | "integrity": "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==", 882 | "cpu": [ 883 | "loong64" 884 | ], 885 | "dev": true, 886 | "license": "MIT", 887 | "optional": true, 888 | "os": [ 889 | "linux" 890 | ] 891 | }, 892 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 893 | "version": "4.41.0", 894 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz", 895 | "integrity": "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==", 896 | "cpu": [ 897 | "ppc64" 898 | ], 899 | "dev": true, 900 | "license": "MIT", 901 | "optional": true, 902 | "os": [ 903 | "linux" 904 | ] 905 | }, 906 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 907 | "version": "4.41.0", 908 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz", 909 | "integrity": "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==", 910 | "cpu": [ 911 | "riscv64" 912 | ], 913 | "dev": true, 914 | "license": "MIT", 915 | "optional": true, 916 | "os": [ 917 | "linux" 918 | ] 919 | }, 920 | "node_modules/@rollup/rollup-linux-riscv64-musl": { 921 | "version": "4.41.0", 922 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz", 923 | "integrity": "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==", 924 | "cpu": [ 925 | "riscv64" 926 | ], 927 | "dev": true, 928 | "license": "MIT", 929 | "optional": true, 930 | "os": [ 931 | "linux" 932 | ] 933 | }, 934 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 935 | "version": "4.41.0", 936 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz", 937 | "integrity": "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==", 938 | "cpu": [ 939 | "s390x" 940 | ], 941 | "dev": true, 942 | "license": "MIT", 943 | "optional": true, 944 | "os": [ 945 | "linux" 946 | ] 947 | }, 948 | "node_modules/@rollup/rollup-linux-x64-gnu": { 949 | "version": "4.41.0", 950 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz", 951 | "integrity": "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==", 952 | "cpu": [ 953 | "x64" 954 | ], 955 | "dev": true, 956 | "license": "MIT", 957 | "optional": true, 958 | "os": [ 959 | "linux" 960 | ] 961 | }, 962 | "node_modules/@rollup/rollup-linux-x64-musl": { 963 | "version": "4.41.0", 964 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz", 965 | "integrity": "sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==", 966 | "cpu": [ 967 | "x64" 968 | ], 969 | "dev": true, 970 | "license": "MIT", 971 | "optional": true, 972 | "os": [ 973 | "linux" 974 | ] 975 | }, 976 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 977 | "version": "4.41.0", 978 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz", 979 | "integrity": "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==", 980 | "cpu": [ 981 | "arm64" 982 | ], 983 | "dev": true, 984 | "license": "MIT", 985 | "optional": true, 986 | "os": [ 987 | "win32" 988 | ] 989 | }, 990 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 991 | "version": "4.41.0", 992 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz", 993 | "integrity": "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==", 994 | "cpu": [ 995 | "ia32" 996 | ], 997 | "dev": true, 998 | "license": "MIT", 999 | "optional": true, 1000 | "os": [ 1001 | "win32" 1002 | ] 1003 | }, 1004 | "node_modules/@rollup/rollup-win32-x64-msvc": { 1005 | "version": "4.41.0", 1006 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz", 1007 | "integrity": "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==", 1008 | "cpu": [ 1009 | "x64" 1010 | ], 1011 | "dev": true, 1012 | "license": "MIT", 1013 | "optional": true, 1014 | "os": [ 1015 | "win32" 1016 | ] 1017 | }, 1018 | "node_modules/@types/estree": { 1019 | "version": "1.0.7", 1020 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", 1021 | "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", 1022 | "dev": true, 1023 | "license": "MIT" 1024 | }, 1025 | "node_modules/@types/js-yaml": { 1026 | "version": "4.0.9", 1027 | "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", 1028 | "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", 1029 | "dev": true, 1030 | "license": "MIT" 1031 | }, 1032 | "node_modules/@types/node": { 1033 | "version": "20.17.48", 1034 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.48.tgz", 1035 | "integrity": "sha512-KpSfKOHPsiSC4IkZeu2LsusFwExAIVGkhG1KkbaBMLwau0uMhj0fCrvyg9ddM2sAvd+gtiBJLir4LAw1MNMIaw==", 1036 | "dev": true, 1037 | "license": "MIT", 1038 | "dependencies": { 1039 | "undici-types": "~6.19.2" 1040 | } 1041 | }, 1042 | "node_modules/@vitest/coverage-v8": { 1043 | "version": "3.1.3", 1044 | "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.1.3.tgz", 1045 | "integrity": "sha512-cj76U5gXCl3g88KSnf80kof6+6w+K4BjOflCl7t6yRJPDuCrHtVu0SgNYOUARJOL5TI8RScDbm5x4s1/P9bvpw==", 1046 | "dev": true, 1047 | "license": "MIT", 1048 | "dependencies": { 1049 | "@ampproject/remapping": "^2.3.0", 1050 | "@bcoe/v8-coverage": "^1.0.2", 1051 | "debug": "^4.4.0", 1052 | "istanbul-lib-coverage": "^3.2.2", 1053 | "istanbul-lib-report": "^3.0.1", 1054 | "istanbul-lib-source-maps": "^5.0.6", 1055 | "istanbul-reports": "^3.1.7", 1056 | "magic-string": "^0.30.17", 1057 | "magicast": "^0.3.5", 1058 | "std-env": "^3.9.0", 1059 | "test-exclude": "^7.0.1", 1060 | "tinyrainbow": "^2.0.0" 1061 | }, 1062 | "funding": { 1063 | "url": "https://opencollective.com/vitest" 1064 | }, 1065 | "peerDependencies": { 1066 | "@vitest/browser": "3.1.3", 1067 | "vitest": "3.1.3" 1068 | }, 1069 | "peerDependenciesMeta": { 1070 | "@vitest/browser": { 1071 | "optional": true 1072 | } 1073 | } 1074 | }, 1075 | "node_modules/@vitest/expect": { 1076 | "version": "3.1.3", 1077 | "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.1.3.tgz", 1078 | "integrity": "sha512-7FTQQuuLKmN1Ig/h+h/GO+44Q1IlglPlR2es4ab7Yvfx+Uk5xsv+Ykk+MEt/M2Yn/xGmzaLKxGw2lgy2bwuYqg==", 1079 | "dev": true, 1080 | "license": "MIT", 1081 | "dependencies": { 1082 | "@vitest/spy": "3.1.3", 1083 | "@vitest/utils": "3.1.3", 1084 | "chai": "^5.2.0", 1085 | "tinyrainbow": "^2.0.0" 1086 | }, 1087 | "funding": { 1088 | "url": "https://opencollective.com/vitest" 1089 | } 1090 | }, 1091 | "node_modules/@vitest/mocker": { 1092 | "version": "3.1.3", 1093 | "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.1.3.tgz", 1094 | "integrity": "sha512-PJbLjonJK82uCWHjzgBJZuR7zmAOrSvKk1QBxrennDIgtH4uK0TB1PvYmc0XBCigxxtiAVPfWtAdy4lpz8SQGQ==", 1095 | "dev": true, 1096 | "license": "MIT", 1097 | "dependencies": { 1098 | "@vitest/spy": "3.1.3", 1099 | "estree-walker": "^3.0.3", 1100 | "magic-string": "^0.30.17" 1101 | }, 1102 | "funding": { 1103 | "url": "https://opencollective.com/vitest" 1104 | }, 1105 | "peerDependencies": { 1106 | "msw": "^2.4.9", 1107 | "vite": "^5.0.0 || ^6.0.0" 1108 | }, 1109 | "peerDependenciesMeta": { 1110 | "msw": { 1111 | "optional": true 1112 | }, 1113 | "vite": { 1114 | "optional": true 1115 | } 1116 | } 1117 | }, 1118 | "node_modules/@vitest/pretty-format": { 1119 | "version": "3.1.3", 1120 | "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.3.tgz", 1121 | "integrity": "sha512-i6FDiBeJUGLDKADw2Gb01UtUNb12yyXAqC/mmRWuYl+m/U9GS7s8us5ONmGkGpUUo7/iAYzI2ePVfOZTYvUifA==", 1122 | "dev": true, 1123 | "license": "MIT", 1124 | "dependencies": { 1125 | "tinyrainbow": "^2.0.0" 1126 | }, 1127 | "funding": { 1128 | "url": "https://opencollective.com/vitest" 1129 | } 1130 | }, 1131 | "node_modules/@vitest/runner": { 1132 | "version": "3.1.3", 1133 | "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.1.3.tgz", 1134 | "integrity": "sha512-Tae+ogtlNfFei5DggOsSUvkIaSuVywujMj6HzR97AHK6XK8i3BuVyIifWAm/sE3a15lF5RH9yQIrbXYuo0IFyA==", 1135 | "dev": true, 1136 | "license": "MIT", 1137 | "dependencies": { 1138 | "@vitest/utils": "3.1.3", 1139 | "pathe": "^2.0.3" 1140 | }, 1141 | "funding": { 1142 | "url": "https://opencollective.com/vitest" 1143 | } 1144 | }, 1145 | "node_modules/@vitest/snapshot": { 1146 | "version": "3.1.3", 1147 | "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.1.3.tgz", 1148 | "integrity": "sha512-XVa5OPNTYUsyqG9skuUkFzAeFnEzDp8hQu7kZ0N25B1+6KjGm4hWLtURyBbsIAOekfWQ7Wuz/N/XXzgYO3deWQ==", 1149 | "dev": true, 1150 | "license": "MIT", 1151 | "dependencies": { 1152 | "@vitest/pretty-format": "3.1.3", 1153 | "magic-string": "^0.30.17", 1154 | "pathe": "^2.0.3" 1155 | }, 1156 | "funding": { 1157 | "url": "https://opencollective.com/vitest" 1158 | } 1159 | }, 1160 | "node_modules/@vitest/spy": { 1161 | "version": "3.1.3", 1162 | "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.1.3.tgz", 1163 | "integrity": "sha512-x6w+ctOEmEXdWaa6TO4ilb7l9DxPR5bwEb6hILKuxfU1NqWT2mpJD9NJN7t3OTfxmVlOMrvtoFJGdgyzZ605lQ==", 1164 | "dev": true, 1165 | "license": "MIT", 1166 | "dependencies": { 1167 | "tinyspy": "^3.0.2" 1168 | }, 1169 | "funding": { 1170 | "url": "https://opencollective.com/vitest" 1171 | } 1172 | }, 1173 | "node_modules/@vitest/utils": { 1174 | "version": "3.1.3", 1175 | "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.1.3.tgz", 1176 | "integrity": "sha512-2Ltrpht4OmHO9+c/nmHtF09HWiyWdworqnHIwjfvDyWjuwKbdkcS9AnhsDn+8E2RM4x++foD1/tNuLPVvWG1Rg==", 1177 | "dev": true, 1178 | "license": "MIT", 1179 | "dependencies": { 1180 | "@vitest/pretty-format": "3.1.3", 1181 | "loupe": "^3.1.3", 1182 | "tinyrainbow": "^2.0.0" 1183 | }, 1184 | "funding": { 1185 | "url": "https://opencollective.com/vitest" 1186 | } 1187 | }, 1188 | "node_modules/ansi-regex": { 1189 | "version": "6.1.0", 1190 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", 1191 | "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", 1192 | "dev": true, 1193 | "license": "MIT", 1194 | "engines": { 1195 | "node": ">=12" 1196 | }, 1197 | "funding": { 1198 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 1199 | } 1200 | }, 1201 | "node_modules/ansi-styles": { 1202 | "version": "6.2.1", 1203 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 1204 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 1205 | "dev": true, 1206 | "license": "MIT", 1207 | "engines": { 1208 | "node": ">=12" 1209 | }, 1210 | "funding": { 1211 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1212 | } 1213 | }, 1214 | "node_modules/argparse": { 1215 | "version": "2.0.1", 1216 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1217 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1218 | "license": "Python-2.0" 1219 | }, 1220 | "node_modules/assertion-error": { 1221 | "version": "2.0.1", 1222 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", 1223 | "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", 1224 | "dev": true, 1225 | "license": "MIT", 1226 | "engines": { 1227 | "node": ">=12" 1228 | } 1229 | }, 1230 | "node_modules/balanced-match": { 1231 | "version": "1.0.2", 1232 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1233 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1234 | "dev": true, 1235 | "license": "MIT" 1236 | }, 1237 | "node_modules/before-after-hook": { 1238 | "version": "3.0.2", 1239 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", 1240 | "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", 1241 | "dev": true, 1242 | "license": "Apache-2.0" 1243 | }, 1244 | "node_modules/brace-expansion": { 1245 | "version": "2.0.1", 1246 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1247 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1248 | "dev": true, 1249 | "license": "MIT", 1250 | "dependencies": { 1251 | "balanced-match": "^1.0.0" 1252 | } 1253 | }, 1254 | "node_modules/cac": { 1255 | "version": "6.7.14", 1256 | "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", 1257 | "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", 1258 | "dev": true, 1259 | "license": "MIT", 1260 | "engines": { 1261 | "node": ">=8" 1262 | } 1263 | }, 1264 | "node_modules/chai": { 1265 | "version": "5.2.0", 1266 | "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", 1267 | "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", 1268 | "dev": true, 1269 | "license": "MIT", 1270 | "dependencies": { 1271 | "assertion-error": "^2.0.1", 1272 | "check-error": "^2.1.1", 1273 | "deep-eql": "^5.0.1", 1274 | "loupe": "^3.1.0", 1275 | "pathval": "^2.0.0" 1276 | }, 1277 | "engines": { 1278 | "node": ">=12" 1279 | } 1280 | }, 1281 | "node_modules/check-error": { 1282 | "version": "2.1.1", 1283 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", 1284 | "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", 1285 | "dev": true, 1286 | "license": "MIT", 1287 | "engines": { 1288 | "node": ">= 16" 1289 | } 1290 | }, 1291 | "node_modules/color-convert": { 1292 | "version": "2.0.1", 1293 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1294 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1295 | "dev": true, 1296 | "license": "MIT", 1297 | "dependencies": { 1298 | "color-name": "~1.1.4" 1299 | }, 1300 | "engines": { 1301 | "node": ">=7.0.0" 1302 | } 1303 | }, 1304 | "node_modules/color-name": { 1305 | "version": "1.1.4", 1306 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1307 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1308 | "dev": true, 1309 | "license": "MIT" 1310 | }, 1311 | "node_modules/cross-spawn": { 1312 | "version": "7.0.6", 1313 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 1314 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 1315 | "dev": true, 1316 | "license": "MIT", 1317 | "dependencies": { 1318 | "path-key": "^3.1.0", 1319 | "shebang-command": "^2.0.0", 1320 | "which": "^2.0.1" 1321 | }, 1322 | "engines": { 1323 | "node": ">= 8" 1324 | } 1325 | }, 1326 | "node_modules/debug": { 1327 | "version": "4.4.1", 1328 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", 1329 | "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", 1330 | "dev": true, 1331 | "license": "MIT", 1332 | "dependencies": { 1333 | "ms": "^2.1.3" 1334 | }, 1335 | "engines": { 1336 | "node": ">=6.0" 1337 | }, 1338 | "peerDependenciesMeta": { 1339 | "supports-color": { 1340 | "optional": true 1341 | } 1342 | } 1343 | }, 1344 | "node_modules/deep-eql": { 1345 | "version": "5.0.2", 1346 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", 1347 | "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", 1348 | "dev": true, 1349 | "license": "MIT", 1350 | "engines": { 1351 | "node": ">=6" 1352 | } 1353 | }, 1354 | "node_modules/dequal": { 1355 | "version": "2.0.3", 1356 | "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", 1357 | "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", 1358 | "dev": true, 1359 | "license": "MIT", 1360 | "engines": { 1361 | "node": ">=6" 1362 | } 1363 | }, 1364 | "node_modules/eastasianwidth": { 1365 | "version": "0.2.0", 1366 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 1367 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 1368 | "dev": true, 1369 | "license": "MIT" 1370 | }, 1371 | "node_modules/emoji-regex": { 1372 | "version": "9.2.2", 1373 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 1374 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 1375 | "dev": true, 1376 | "license": "MIT" 1377 | }, 1378 | "node_modules/es-module-lexer": { 1379 | "version": "1.7.0", 1380 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", 1381 | "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", 1382 | "dev": true, 1383 | "license": "MIT" 1384 | }, 1385 | "node_modules/esbuild": { 1386 | "version": "0.25.4", 1387 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", 1388 | "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", 1389 | "dev": true, 1390 | "hasInstallScript": true, 1391 | "license": "MIT", 1392 | "bin": { 1393 | "esbuild": "bin/esbuild" 1394 | }, 1395 | "engines": { 1396 | "node": ">=18" 1397 | }, 1398 | "optionalDependencies": { 1399 | "@esbuild/aix-ppc64": "0.25.4", 1400 | "@esbuild/android-arm": "0.25.4", 1401 | "@esbuild/android-arm64": "0.25.4", 1402 | "@esbuild/android-x64": "0.25.4", 1403 | "@esbuild/darwin-arm64": "0.25.4", 1404 | "@esbuild/darwin-x64": "0.25.4", 1405 | "@esbuild/freebsd-arm64": "0.25.4", 1406 | "@esbuild/freebsd-x64": "0.25.4", 1407 | "@esbuild/linux-arm": "0.25.4", 1408 | "@esbuild/linux-arm64": "0.25.4", 1409 | "@esbuild/linux-ia32": "0.25.4", 1410 | "@esbuild/linux-loong64": "0.25.4", 1411 | "@esbuild/linux-mips64el": "0.25.4", 1412 | "@esbuild/linux-ppc64": "0.25.4", 1413 | "@esbuild/linux-riscv64": "0.25.4", 1414 | "@esbuild/linux-s390x": "0.25.4", 1415 | "@esbuild/linux-x64": "0.25.4", 1416 | "@esbuild/netbsd-arm64": "0.25.4", 1417 | "@esbuild/netbsd-x64": "0.25.4", 1418 | "@esbuild/openbsd-arm64": "0.25.4", 1419 | "@esbuild/openbsd-x64": "0.25.4", 1420 | "@esbuild/sunos-x64": "0.25.4", 1421 | "@esbuild/win32-arm64": "0.25.4", 1422 | "@esbuild/win32-ia32": "0.25.4", 1423 | "@esbuild/win32-x64": "0.25.4" 1424 | } 1425 | }, 1426 | "node_modules/estree-walker": { 1427 | "version": "3.0.3", 1428 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 1429 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 1430 | "dev": true, 1431 | "license": "MIT", 1432 | "dependencies": { 1433 | "@types/estree": "^1.0.0" 1434 | } 1435 | }, 1436 | "node_modules/expect-type": { 1437 | "version": "1.2.1", 1438 | "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", 1439 | "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", 1440 | "dev": true, 1441 | "license": "Apache-2.0", 1442 | "engines": { 1443 | "node": ">=12.0.0" 1444 | } 1445 | }, 1446 | "node_modules/fast-content-type-parse": { 1447 | "version": "2.0.1", 1448 | "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz", 1449 | "integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==", 1450 | "dev": true, 1451 | "funding": [ 1452 | { 1453 | "type": "github", 1454 | "url": "https://github.com/sponsors/fastify" 1455 | }, 1456 | { 1457 | "type": "opencollective", 1458 | "url": "https://opencollective.com/fastify" 1459 | } 1460 | ], 1461 | "license": "MIT" 1462 | }, 1463 | "node_modules/fdir": { 1464 | "version": "6.4.4", 1465 | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", 1466 | "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", 1467 | "dev": true, 1468 | "license": "MIT", 1469 | "peerDependencies": { 1470 | "picomatch": "^3 || ^4" 1471 | }, 1472 | "peerDependenciesMeta": { 1473 | "picomatch": { 1474 | "optional": true 1475 | } 1476 | } 1477 | }, 1478 | "node_modules/fetch-mock": { 1479 | "version": "10.1.1", 1480 | "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-10.1.1.tgz", 1481 | "integrity": "sha512-R6MwxuGwlUe0K6GzdLY1Wa9voX/GbUBDZjNHBsvlBhrpXurCYpQN4EW0iFCmtWddDTuS0ubR93OtFSgy9E/L2A==", 1482 | "dev": true, 1483 | "license": "MIT", 1484 | "dependencies": { 1485 | "debug": "^4.1.1", 1486 | "dequal": "^2.0.3", 1487 | "globrex": "^0.1.2", 1488 | "is-subset": "^0.1.1", 1489 | "regexparam": "^3.0.0" 1490 | }, 1491 | "engines": { 1492 | "node": ">=8.0.0" 1493 | }, 1494 | "peerDependenciesMeta": { 1495 | "node-fetch": { 1496 | "optional": true 1497 | } 1498 | } 1499 | }, 1500 | "node_modules/foreground-child": { 1501 | "version": "3.3.1", 1502 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", 1503 | "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", 1504 | "dev": true, 1505 | "license": "ISC", 1506 | "dependencies": { 1507 | "cross-spawn": "^7.0.6", 1508 | "signal-exit": "^4.0.1" 1509 | }, 1510 | "engines": { 1511 | "node": ">=14" 1512 | }, 1513 | "funding": { 1514 | "url": "https://github.com/sponsors/isaacs" 1515 | } 1516 | }, 1517 | "node_modules/fsevents": { 1518 | "version": "2.3.3", 1519 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1520 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1521 | "dev": true, 1522 | "hasInstallScript": true, 1523 | "license": "MIT", 1524 | "optional": true, 1525 | "os": [ 1526 | "darwin" 1527 | ], 1528 | "engines": { 1529 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1530 | } 1531 | }, 1532 | "node_modules/glob": { 1533 | "version": "10.4.5", 1534 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", 1535 | "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", 1536 | "dev": true, 1537 | "license": "ISC", 1538 | "dependencies": { 1539 | "foreground-child": "^3.1.0", 1540 | "jackspeak": "^3.1.2", 1541 | "minimatch": "^9.0.4", 1542 | "minipass": "^7.1.2", 1543 | "package-json-from-dist": "^1.0.0", 1544 | "path-scurry": "^1.11.1" 1545 | }, 1546 | "bin": { 1547 | "glob": "dist/esm/bin.mjs" 1548 | }, 1549 | "funding": { 1550 | "url": "https://github.com/sponsors/isaacs" 1551 | } 1552 | }, 1553 | "node_modules/globrex": { 1554 | "version": "0.1.2", 1555 | "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", 1556 | "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", 1557 | "dev": true, 1558 | "license": "MIT" 1559 | }, 1560 | "node_modules/has-flag": { 1561 | "version": "4.0.0", 1562 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1563 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1564 | "dev": true, 1565 | "license": "MIT", 1566 | "engines": { 1567 | "node": ">=8" 1568 | } 1569 | }, 1570 | "node_modules/html-escaper": { 1571 | "version": "2.0.2", 1572 | "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", 1573 | "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", 1574 | "dev": true, 1575 | "license": "MIT" 1576 | }, 1577 | "node_modules/is-fullwidth-code-point": { 1578 | "version": "3.0.0", 1579 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1580 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1581 | "dev": true, 1582 | "license": "MIT", 1583 | "engines": { 1584 | "node": ">=8" 1585 | } 1586 | }, 1587 | "node_modules/is-subset": { 1588 | "version": "0.1.1", 1589 | "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", 1590 | "integrity": "sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw==", 1591 | "dev": true, 1592 | "license": "MIT" 1593 | }, 1594 | "node_modules/isexe": { 1595 | "version": "2.0.0", 1596 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1597 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1598 | "dev": true, 1599 | "license": "ISC" 1600 | }, 1601 | "node_modules/istanbul-lib-coverage": { 1602 | "version": "3.2.2", 1603 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", 1604 | "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", 1605 | "dev": true, 1606 | "license": "BSD-3-Clause", 1607 | "engines": { 1608 | "node": ">=8" 1609 | } 1610 | }, 1611 | "node_modules/istanbul-lib-report": { 1612 | "version": "3.0.1", 1613 | "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", 1614 | "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", 1615 | "dev": true, 1616 | "license": "BSD-3-Clause", 1617 | "dependencies": { 1618 | "istanbul-lib-coverage": "^3.0.0", 1619 | "make-dir": "^4.0.0", 1620 | "supports-color": "^7.1.0" 1621 | }, 1622 | "engines": { 1623 | "node": ">=10" 1624 | } 1625 | }, 1626 | "node_modules/istanbul-lib-source-maps": { 1627 | "version": "5.0.6", 1628 | "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", 1629 | "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", 1630 | "dev": true, 1631 | "license": "BSD-3-Clause", 1632 | "dependencies": { 1633 | "@jridgewell/trace-mapping": "^0.3.23", 1634 | "debug": "^4.1.1", 1635 | "istanbul-lib-coverage": "^3.0.0" 1636 | }, 1637 | "engines": { 1638 | "node": ">=10" 1639 | } 1640 | }, 1641 | "node_modules/istanbul-reports": { 1642 | "version": "3.1.7", 1643 | "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", 1644 | "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", 1645 | "dev": true, 1646 | "license": "BSD-3-Clause", 1647 | "dependencies": { 1648 | "html-escaper": "^2.0.0", 1649 | "istanbul-lib-report": "^3.0.0" 1650 | }, 1651 | "engines": { 1652 | "node": ">=8" 1653 | } 1654 | }, 1655 | "node_modules/jackspeak": { 1656 | "version": "3.4.3", 1657 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", 1658 | "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", 1659 | "dev": true, 1660 | "license": "BlueOak-1.0.0", 1661 | "dependencies": { 1662 | "@isaacs/cliui": "^8.0.2" 1663 | }, 1664 | "funding": { 1665 | "url": "https://github.com/sponsors/isaacs" 1666 | }, 1667 | "optionalDependencies": { 1668 | "@pkgjs/parseargs": "^0.11.0" 1669 | } 1670 | }, 1671 | "node_modules/js-yaml": { 1672 | "version": "4.1.0", 1673 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1674 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1675 | "license": "MIT", 1676 | "dependencies": { 1677 | "argparse": "^2.0.1" 1678 | }, 1679 | "bin": { 1680 | "js-yaml": "bin/js-yaml.js" 1681 | } 1682 | }, 1683 | "node_modules/loupe": { 1684 | "version": "3.1.3", 1685 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", 1686 | "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", 1687 | "dev": true, 1688 | "license": "MIT" 1689 | }, 1690 | "node_modules/lru-cache": { 1691 | "version": "10.4.3", 1692 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 1693 | "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 1694 | "dev": true, 1695 | "license": "ISC" 1696 | }, 1697 | "node_modules/magic-string": { 1698 | "version": "0.30.17", 1699 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", 1700 | "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", 1701 | "dev": true, 1702 | "license": "MIT", 1703 | "dependencies": { 1704 | "@jridgewell/sourcemap-codec": "^1.5.0" 1705 | } 1706 | }, 1707 | "node_modules/magicast": { 1708 | "version": "0.3.5", 1709 | "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", 1710 | "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", 1711 | "dev": true, 1712 | "license": "MIT", 1713 | "dependencies": { 1714 | "@babel/parser": "^7.25.4", 1715 | "@babel/types": "^7.25.4", 1716 | "source-map-js": "^1.2.0" 1717 | } 1718 | }, 1719 | "node_modules/make-dir": { 1720 | "version": "4.0.0", 1721 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", 1722 | "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", 1723 | "dev": true, 1724 | "license": "MIT", 1725 | "dependencies": { 1726 | "semver": "^7.5.3" 1727 | }, 1728 | "engines": { 1729 | "node": ">=10" 1730 | }, 1731 | "funding": { 1732 | "url": "https://github.com/sponsors/sindresorhus" 1733 | } 1734 | }, 1735 | "node_modules/min-indent": { 1736 | "version": "1.0.1", 1737 | "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", 1738 | "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", 1739 | "dev": true, 1740 | "license": "MIT", 1741 | "engines": { 1742 | "node": ">=4" 1743 | } 1744 | }, 1745 | "node_modules/minimatch": { 1746 | "version": "9.0.5", 1747 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 1748 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 1749 | "dev": true, 1750 | "license": "ISC", 1751 | "dependencies": { 1752 | "brace-expansion": "^2.0.1" 1753 | }, 1754 | "engines": { 1755 | "node": ">=16 || 14 >=14.17" 1756 | }, 1757 | "funding": { 1758 | "url": "https://github.com/sponsors/isaacs" 1759 | } 1760 | }, 1761 | "node_modules/minipass": { 1762 | "version": "7.1.2", 1763 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", 1764 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", 1765 | "dev": true, 1766 | "license": "ISC", 1767 | "engines": { 1768 | "node": ">=16 || 14 >=14.17" 1769 | } 1770 | }, 1771 | "node_modules/ms": { 1772 | "version": "2.1.3", 1773 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1774 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1775 | "dev": true, 1776 | "license": "MIT" 1777 | }, 1778 | "node_modules/nanoid": { 1779 | "version": "3.3.11", 1780 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", 1781 | "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 1782 | "dev": true, 1783 | "funding": [ 1784 | { 1785 | "type": "github", 1786 | "url": "https://github.com/sponsors/ai" 1787 | } 1788 | ], 1789 | "license": "MIT", 1790 | "bin": { 1791 | "nanoid": "bin/nanoid.cjs" 1792 | }, 1793 | "engines": { 1794 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1795 | } 1796 | }, 1797 | "node_modules/package-json-from-dist": { 1798 | "version": "1.0.1", 1799 | "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", 1800 | "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", 1801 | "dev": true, 1802 | "license": "BlueOak-1.0.0" 1803 | }, 1804 | "node_modules/path-key": { 1805 | "version": "3.1.1", 1806 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1807 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1808 | "dev": true, 1809 | "license": "MIT", 1810 | "engines": { 1811 | "node": ">=8" 1812 | } 1813 | }, 1814 | "node_modules/path-scurry": { 1815 | "version": "1.11.1", 1816 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 1817 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 1818 | "dev": true, 1819 | "license": "BlueOak-1.0.0", 1820 | "dependencies": { 1821 | "lru-cache": "^10.2.0", 1822 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 1823 | }, 1824 | "engines": { 1825 | "node": ">=16 || 14 >=14.18" 1826 | }, 1827 | "funding": { 1828 | "url": "https://github.com/sponsors/isaacs" 1829 | } 1830 | }, 1831 | "node_modules/pathe": { 1832 | "version": "2.0.3", 1833 | "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", 1834 | "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", 1835 | "dev": true, 1836 | "license": "MIT" 1837 | }, 1838 | "node_modules/pathval": { 1839 | "version": "2.0.0", 1840 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", 1841 | "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", 1842 | "dev": true, 1843 | "license": "MIT", 1844 | "engines": { 1845 | "node": ">= 14.16" 1846 | } 1847 | }, 1848 | "node_modules/picocolors": { 1849 | "version": "1.1.1", 1850 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1851 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1852 | "dev": true, 1853 | "license": "ISC" 1854 | }, 1855 | "node_modules/picomatch": { 1856 | "version": "4.0.2", 1857 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 1858 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 1859 | "dev": true, 1860 | "license": "MIT", 1861 | "engines": { 1862 | "node": ">=12" 1863 | }, 1864 | "funding": { 1865 | "url": "https://github.com/sponsors/jonschlinkert" 1866 | } 1867 | }, 1868 | "node_modules/postcss": { 1869 | "version": "8.5.3", 1870 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", 1871 | "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", 1872 | "dev": true, 1873 | "funding": [ 1874 | { 1875 | "type": "opencollective", 1876 | "url": "https://opencollective.com/postcss/" 1877 | }, 1878 | { 1879 | "type": "tidelift", 1880 | "url": "https://tidelift.com/funding/github/npm/postcss" 1881 | }, 1882 | { 1883 | "type": "github", 1884 | "url": "https://github.com/sponsors/ai" 1885 | } 1886 | ], 1887 | "license": "MIT", 1888 | "dependencies": { 1889 | "nanoid": "^3.3.8", 1890 | "picocolors": "^1.1.1", 1891 | "source-map-js": "^1.2.1" 1892 | }, 1893 | "engines": { 1894 | "node": "^10 || ^12 || >=14" 1895 | } 1896 | }, 1897 | "node_modules/prettier": { 1898 | "version": "3.5.3", 1899 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", 1900 | "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", 1901 | "dev": true, 1902 | "license": "MIT", 1903 | "bin": { 1904 | "prettier": "bin/prettier.cjs" 1905 | }, 1906 | "engines": { 1907 | "node": ">=14" 1908 | }, 1909 | "funding": { 1910 | "url": "https://github.com/prettier/prettier?sponsor=1" 1911 | } 1912 | }, 1913 | "node_modules/regexparam": { 1914 | "version": "3.0.0", 1915 | "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz", 1916 | "integrity": "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==", 1917 | "dev": true, 1918 | "license": "MIT", 1919 | "engines": { 1920 | "node": ">=8" 1921 | } 1922 | }, 1923 | "node_modules/rollup": { 1924 | "version": "4.41.0", 1925 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz", 1926 | "integrity": "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==", 1927 | "dev": true, 1928 | "license": "MIT", 1929 | "dependencies": { 1930 | "@types/estree": "1.0.7" 1931 | }, 1932 | "bin": { 1933 | "rollup": "dist/bin/rollup" 1934 | }, 1935 | "engines": { 1936 | "node": ">=18.0.0", 1937 | "npm": ">=8.0.0" 1938 | }, 1939 | "optionalDependencies": { 1940 | "@rollup/rollup-android-arm-eabi": "4.41.0", 1941 | "@rollup/rollup-android-arm64": "4.41.0", 1942 | "@rollup/rollup-darwin-arm64": "4.41.0", 1943 | "@rollup/rollup-darwin-x64": "4.41.0", 1944 | "@rollup/rollup-freebsd-arm64": "4.41.0", 1945 | "@rollup/rollup-freebsd-x64": "4.41.0", 1946 | "@rollup/rollup-linux-arm-gnueabihf": "4.41.0", 1947 | "@rollup/rollup-linux-arm-musleabihf": "4.41.0", 1948 | "@rollup/rollup-linux-arm64-gnu": "4.41.0", 1949 | "@rollup/rollup-linux-arm64-musl": "4.41.0", 1950 | "@rollup/rollup-linux-loongarch64-gnu": "4.41.0", 1951 | "@rollup/rollup-linux-powerpc64le-gnu": "4.41.0", 1952 | "@rollup/rollup-linux-riscv64-gnu": "4.41.0", 1953 | "@rollup/rollup-linux-riscv64-musl": "4.41.0", 1954 | "@rollup/rollup-linux-s390x-gnu": "4.41.0", 1955 | "@rollup/rollup-linux-x64-gnu": "4.41.0", 1956 | "@rollup/rollup-linux-x64-musl": "4.41.0", 1957 | "@rollup/rollup-win32-arm64-msvc": "4.41.0", 1958 | "@rollup/rollup-win32-ia32-msvc": "4.41.0", 1959 | "@rollup/rollup-win32-x64-msvc": "4.41.0", 1960 | "fsevents": "~2.3.2" 1961 | } 1962 | }, 1963 | "node_modules/semantic-release-plugin-update-version-in-files": { 1964 | "version": "2.0.0", 1965 | "resolved": "https://registry.npmjs.org/semantic-release-plugin-update-version-in-files/-/semantic-release-plugin-update-version-in-files-2.0.0.tgz", 1966 | "integrity": "sha512-ovpBKjkygkbiTH0CG+vJb62O+eGFoI7PM5KCVuuy2I5Xaj5t9JzmwMtAAls3Ie+R06IQu556P4gIKjJ9FIDJZQ==", 1967 | "dev": true, 1968 | "license": "ISC", 1969 | "dependencies": { 1970 | "debug": "^4.1.1", 1971 | "glob": "^10.0.0" 1972 | }, 1973 | "engines": { 1974 | "node": ">=18" 1975 | } 1976 | }, 1977 | "node_modules/semver": { 1978 | "version": "7.7.2", 1979 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", 1980 | "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", 1981 | "dev": true, 1982 | "license": "ISC", 1983 | "bin": { 1984 | "semver": "bin/semver.js" 1985 | }, 1986 | "engines": { 1987 | "node": ">=10" 1988 | } 1989 | }, 1990 | "node_modules/shebang-command": { 1991 | "version": "2.0.0", 1992 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1993 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1994 | "dev": true, 1995 | "license": "MIT", 1996 | "dependencies": { 1997 | "shebang-regex": "^3.0.0" 1998 | }, 1999 | "engines": { 2000 | "node": ">=8" 2001 | } 2002 | }, 2003 | "node_modules/shebang-regex": { 2004 | "version": "3.0.0", 2005 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 2006 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 2007 | "dev": true, 2008 | "license": "MIT", 2009 | "engines": { 2010 | "node": ">=8" 2011 | } 2012 | }, 2013 | "node_modules/siginfo": { 2014 | "version": "2.0.0", 2015 | "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", 2016 | "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", 2017 | "dev": true, 2018 | "license": "ISC" 2019 | }, 2020 | "node_modules/signal-exit": { 2021 | "version": "4.1.0", 2022 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 2023 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 2024 | "dev": true, 2025 | "license": "ISC", 2026 | "engines": { 2027 | "node": ">=14" 2028 | }, 2029 | "funding": { 2030 | "url": "https://github.com/sponsors/isaacs" 2031 | } 2032 | }, 2033 | "node_modules/source-map-js": { 2034 | "version": "1.2.1", 2035 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 2036 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 2037 | "dev": true, 2038 | "license": "BSD-3-Clause", 2039 | "engines": { 2040 | "node": ">=0.10.0" 2041 | } 2042 | }, 2043 | "node_modules/stackback": { 2044 | "version": "0.0.2", 2045 | "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", 2046 | "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", 2047 | "dev": true, 2048 | "license": "MIT" 2049 | }, 2050 | "node_modules/std-env": { 2051 | "version": "3.9.0", 2052 | "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", 2053 | "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", 2054 | "dev": true, 2055 | "license": "MIT" 2056 | }, 2057 | "node_modules/string-width": { 2058 | "version": "5.1.2", 2059 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 2060 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 2061 | "dev": true, 2062 | "license": "MIT", 2063 | "dependencies": { 2064 | "eastasianwidth": "^0.2.0", 2065 | "emoji-regex": "^9.2.2", 2066 | "strip-ansi": "^7.0.1" 2067 | }, 2068 | "engines": { 2069 | "node": ">=12" 2070 | }, 2071 | "funding": { 2072 | "url": "https://github.com/sponsors/sindresorhus" 2073 | } 2074 | }, 2075 | "node_modules/string-width-cjs": { 2076 | "name": "string-width", 2077 | "version": "4.2.3", 2078 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 2079 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 2080 | "dev": true, 2081 | "license": "MIT", 2082 | "dependencies": { 2083 | "emoji-regex": "^8.0.0", 2084 | "is-fullwidth-code-point": "^3.0.0", 2085 | "strip-ansi": "^6.0.1" 2086 | }, 2087 | "engines": { 2088 | "node": ">=8" 2089 | } 2090 | }, 2091 | "node_modules/string-width-cjs/node_modules/ansi-regex": { 2092 | "version": "5.0.1", 2093 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 2094 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 2095 | "dev": true, 2096 | "license": "MIT", 2097 | "engines": { 2098 | "node": ">=8" 2099 | } 2100 | }, 2101 | "node_modules/string-width-cjs/node_modules/emoji-regex": { 2102 | "version": "8.0.0", 2103 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 2104 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 2105 | "dev": true, 2106 | "license": "MIT" 2107 | }, 2108 | "node_modules/string-width-cjs/node_modules/strip-ansi": { 2109 | "version": "6.0.1", 2110 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2111 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2112 | "dev": true, 2113 | "license": "MIT", 2114 | "dependencies": { 2115 | "ansi-regex": "^5.0.1" 2116 | }, 2117 | "engines": { 2118 | "node": ">=8" 2119 | } 2120 | }, 2121 | "node_modules/strip-ansi": { 2122 | "version": "7.1.0", 2123 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 2124 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 2125 | "dev": true, 2126 | "license": "MIT", 2127 | "dependencies": { 2128 | "ansi-regex": "^6.0.1" 2129 | }, 2130 | "engines": { 2131 | "node": ">=12" 2132 | }, 2133 | "funding": { 2134 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 2135 | } 2136 | }, 2137 | "node_modules/strip-ansi-cjs": { 2138 | "name": "strip-ansi", 2139 | "version": "6.0.1", 2140 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2141 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2142 | "dev": true, 2143 | "license": "MIT", 2144 | "dependencies": { 2145 | "ansi-regex": "^5.0.1" 2146 | }, 2147 | "engines": { 2148 | "node": ">=8" 2149 | } 2150 | }, 2151 | "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { 2152 | "version": "5.0.1", 2153 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 2154 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 2155 | "dev": true, 2156 | "license": "MIT", 2157 | "engines": { 2158 | "node": ">=8" 2159 | } 2160 | }, 2161 | "node_modules/strip-indent": { 2162 | "version": "4.0.0", 2163 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", 2164 | "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", 2165 | "dev": true, 2166 | "license": "MIT", 2167 | "dependencies": { 2168 | "min-indent": "^1.0.1" 2169 | }, 2170 | "engines": { 2171 | "node": ">=12" 2172 | }, 2173 | "funding": { 2174 | "url": "https://github.com/sponsors/sindresorhus" 2175 | } 2176 | }, 2177 | "node_modules/supports-color": { 2178 | "version": "7.2.0", 2179 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2180 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2181 | "dev": true, 2182 | "license": "MIT", 2183 | "dependencies": { 2184 | "has-flag": "^4.0.0" 2185 | }, 2186 | "engines": { 2187 | "node": ">=8" 2188 | } 2189 | }, 2190 | "node_modules/test-exclude": { 2191 | "version": "7.0.1", 2192 | "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", 2193 | "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", 2194 | "dev": true, 2195 | "license": "ISC", 2196 | "dependencies": { 2197 | "@istanbuljs/schema": "^0.1.2", 2198 | "glob": "^10.4.1", 2199 | "minimatch": "^9.0.4" 2200 | }, 2201 | "engines": { 2202 | "node": ">=18" 2203 | } 2204 | }, 2205 | "node_modules/tinybench": { 2206 | "version": "2.9.0", 2207 | "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", 2208 | "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", 2209 | "dev": true, 2210 | "license": "MIT" 2211 | }, 2212 | "node_modules/tinyexec": { 2213 | "version": "0.3.2", 2214 | "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", 2215 | "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", 2216 | "dev": true, 2217 | "license": "MIT" 2218 | }, 2219 | "node_modules/tinyglobby": { 2220 | "version": "0.2.13", 2221 | "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", 2222 | "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", 2223 | "dev": true, 2224 | "license": "MIT", 2225 | "dependencies": { 2226 | "fdir": "^6.4.4", 2227 | "picomatch": "^4.0.2" 2228 | }, 2229 | "engines": { 2230 | "node": ">=12.0.0" 2231 | }, 2232 | "funding": { 2233 | "url": "https://github.com/sponsors/SuperchupuDev" 2234 | } 2235 | }, 2236 | "node_modules/tinypool": { 2237 | "version": "1.0.2", 2238 | "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", 2239 | "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", 2240 | "dev": true, 2241 | "license": "MIT", 2242 | "engines": { 2243 | "node": "^18.0.0 || >=20.0.0" 2244 | } 2245 | }, 2246 | "node_modules/tinyrainbow": { 2247 | "version": "2.0.0", 2248 | "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", 2249 | "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", 2250 | "dev": true, 2251 | "license": "MIT", 2252 | "engines": { 2253 | "node": ">=14.0.0" 2254 | } 2255 | }, 2256 | "node_modules/tinyspy": { 2257 | "version": "3.0.2", 2258 | "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", 2259 | "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", 2260 | "dev": true, 2261 | "license": "MIT", 2262 | "engines": { 2263 | "node": ">=14.0.0" 2264 | } 2265 | }, 2266 | "node_modules/typescript": { 2267 | "version": "5.8.3", 2268 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", 2269 | "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", 2270 | "dev": true, 2271 | "license": "Apache-2.0", 2272 | "bin": { 2273 | "tsc": "bin/tsc", 2274 | "tsserver": "bin/tsserver" 2275 | }, 2276 | "engines": { 2277 | "node": ">=14.17" 2278 | } 2279 | }, 2280 | "node_modules/undici-types": { 2281 | "version": "6.19.8", 2282 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", 2283 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", 2284 | "dev": true, 2285 | "license": "MIT" 2286 | }, 2287 | "node_modules/universal-user-agent": { 2288 | "version": "7.0.3", 2289 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", 2290 | "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", 2291 | "dev": true, 2292 | "license": "ISC" 2293 | }, 2294 | "node_modules/vite": { 2295 | "version": "6.3.5", 2296 | "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", 2297 | "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", 2298 | "dev": true, 2299 | "license": "MIT", 2300 | "dependencies": { 2301 | "esbuild": "^0.25.0", 2302 | "fdir": "^6.4.4", 2303 | "picomatch": "^4.0.2", 2304 | "postcss": "^8.5.3", 2305 | "rollup": "^4.34.9", 2306 | "tinyglobby": "^0.2.13" 2307 | }, 2308 | "bin": { 2309 | "vite": "bin/vite.js" 2310 | }, 2311 | "engines": { 2312 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 2313 | }, 2314 | "funding": { 2315 | "url": "https://github.com/vitejs/vite?sponsor=1" 2316 | }, 2317 | "optionalDependencies": { 2318 | "fsevents": "~2.3.3" 2319 | }, 2320 | "peerDependencies": { 2321 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 2322 | "jiti": ">=1.21.0", 2323 | "less": "*", 2324 | "lightningcss": "^1.21.0", 2325 | "sass": "*", 2326 | "sass-embedded": "*", 2327 | "stylus": "*", 2328 | "sugarss": "*", 2329 | "terser": "^5.16.0", 2330 | "tsx": "^4.8.1", 2331 | "yaml": "^2.4.2" 2332 | }, 2333 | "peerDependenciesMeta": { 2334 | "@types/node": { 2335 | "optional": true 2336 | }, 2337 | "jiti": { 2338 | "optional": true 2339 | }, 2340 | "less": { 2341 | "optional": true 2342 | }, 2343 | "lightningcss": { 2344 | "optional": true 2345 | }, 2346 | "sass": { 2347 | "optional": true 2348 | }, 2349 | "sass-embedded": { 2350 | "optional": true 2351 | }, 2352 | "stylus": { 2353 | "optional": true 2354 | }, 2355 | "sugarss": { 2356 | "optional": true 2357 | }, 2358 | "terser": { 2359 | "optional": true 2360 | }, 2361 | "tsx": { 2362 | "optional": true 2363 | }, 2364 | "yaml": { 2365 | "optional": true 2366 | } 2367 | } 2368 | }, 2369 | "node_modules/vite-node": { 2370 | "version": "3.1.3", 2371 | "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.1.3.tgz", 2372 | "integrity": "sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA==", 2373 | "dev": true, 2374 | "license": "MIT", 2375 | "dependencies": { 2376 | "cac": "^6.7.14", 2377 | "debug": "^4.4.0", 2378 | "es-module-lexer": "^1.7.0", 2379 | "pathe": "^2.0.3", 2380 | "vite": "^5.0.0 || ^6.0.0" 2381 | }, 2382 | "bin": { 2383 | "vite-node": "vite-node.mjs" 2384 | }, 2385 | "engines": { 2386 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 2387 | }, 2388 | "funding": { 2389 | "url": "https://opencollective.com/vitest" 2390 | } 2391 | }, 2392 | "node_modules/vitest": { 2393 | "version": "3.1.3", 2394 | "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.1.3.tgz", 2395 | "integrity": "sha512-188iM4hAHQ0km23TN/adso1q5hhwKqUpv+Sd6p5sOuh6FhQnRNW3IsiIpvxqahtBabsJ2SLZgmGSpcYK4wQYJw==", 2396 | "dev": true, 2397 | "license": "MIT", 2398 | "dependencies": { 2399 | "@vitest/expect": "3.1.3", 2400 | "@vitest/mocker": "3.1.3", 2401 | "@vitest/pretty-format": "^3.1.3", 2402 | "@vitest/runner": "3.1.3", 2403 | "@vitest/snapshot": "3.1.3", 2404 | "@vitest/spy": "3.1.3", 2405 | "@vitest/utils": "3.1.3", 2406 | "chai": "^5.2.0", 2407 | "debug": "^4.4.0", 2408 | "expect-type": "^1.2.1", 2409 | "magic-string": "^0.30.17", 2410 | "pathe": "^2.0.3", 2411 | "std-env": "^3.9.0", 2412 | "tinybench": "^2.9.0", 2413 | "tinyexec": "^0.3.2", 2414 | "tinyglobby": "^0.2.13", 2415 | "tinypool": "^1.0.2", 2416 | "tinyrainbow": "^2.0.0", 2417 | "vite": "^5.0.0 || ^6.0.0", 2418 | "vite-node": "3.1.3", 2419 | "why-is-node-running": "^2.3.0" 2420 | }, 2421 | "bin": { 2422 | "vitest": "vitest.mjs" 2423 | }, 2424 | "engines": { 2425 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 2426 | }, 2427 | "funding": { 2428 | "url": "https://opencollective.com/vitest" 2429 | }, 2430 | "peerDependencies": { 2431 | "@edge-runtime/vm": "*", 2432 | "@types/debug": "^4.1.12", 2433 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 2434 | "@vitest/browser": "3.1.3", 2435 | "@vitest/ui": "3.1.3", 2436 | "happy-dom": "*", 2437 | "jsdom": "*" 2438 | }, 2439 | "peerDependenciesMeta": { 2440 | "@edge-runtime/vm": { 2441 | "optional": true 2442 | }, 2443 | "@types/debug": { 2444 | "optional": true 2445 | }, 2446 | "@types/node": { 2447 | "optional": true 2448 | }, 2449 | "@vitest/browser": { 2450 | "optional": true 2451 | }, 2452 | "@vitest/ui": { 2453 | "optional": true 2454 | }, 2455 | "happy-dom": { 2456 | "optional": true 2457 | }, 2458 | "jsdom": { 2459 | "optional": true 2460 | } 2461 | } 2462 | }, 2463 | "node_modules/which": { 2464 | "version": "2.0.2", 2465 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 2466 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 2467 | "dev": true, 2468 | "license": "ISC", 2469 | "dependencies": { 2470 | "isexe": "^2.0.0" 2471 | }, 2472 | "bin": { 2473 | "node-which": "bin/node-which" 2474 | }, 2475 | "engines": { 2476 | "node": ">= 8" 2477 | } 2478 | }, 2479 | "node_modules/why-is-node-running": { 2480 | "version": "2.3.0", 2481 | "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", 2482 | "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", 2483 | "dev": true, 2484 | "license": "MIT", 2485 | "dependencies": { 2486 | "siginfo": "^2.0.0", 2487 | "stackback": "0.0.2" 2488 | }, 2489 | "bin": { 2490 | "why-is-node-running": "cli.js" 2491 | }, 2492 | "engines": { 2493 | "node": ">=8" 2494 | } 2495 | }, 2496 | "node_modules/wrap-ansi": { 2497 | "version": "8.1.0", 2498 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 2499 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 2500 | "dev": true, 2501 | "license": "MIT", 2502 | "dependencies": { 2503 | "ansi-styles": "^6.1.0", 2504 | "string-width": "^5.0.1", 2505 | "strip-ansi": "^7.0.1" 2506 | }, 2507 | "engines": { 2508 | "node": ">=12" 2509 | }, 2510 | "funding": { 2511 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 2512 | } 2513 | }, 2514 | "node_modules/wrap-ansi-cjs": { 2515 | "name": "wrap-ansi", 2516 | "version": "7.0.0", 2517 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 2518 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 2519 | "dev": true, 2520 | "license": "MIT", 2521 | "dependencies": { 2522 | "ansi-styles": "^4.0.0", 2523 | "string-width": "^4.1.0", 2524 | "strip-ansi": "^6.0.0" 2525 | }, 2526 | "engines": { 2527 | "node": ">=10" 2528 | }, 2529 | "funding": { 2530 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 2531 | } 2532 | }, 2533 | "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { 2534 | "version": "5.0.1", 2535 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 2536 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 2537 | "dev": true, 2538 | "license": "MIT", 2539 | "engines": { 2540 | "node": ">=8" 2541 | } 2542 | }, 2543 | "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { 2544 | "version": "4.3.0", 2545 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 2546 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 2547 | "dev": true, 2548 | "license": "MIT", 2549 | "dependencies": { 2550 | "color-convert": "^2.0.1" 2551 | }, 2552 | "engines": { 2553 | "node": ">=8" 2554 | }, 2555 | "funding": { 2556 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 2557 | } 2558 | }, 2559 | "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { 2560 | "version": "8.0.0", 2561 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 2562 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 2563 | "dev": true, 2564 | "license": "MIT" 2565 | }, 2566 | "node_modules/wrap-ansi-cjs/node_modules/string-width": { 2567 | "version": "4.2.3", 2568 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 2569 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 2570 | "dev": true, 2571 | "license": "MIT", 2572 | "dependencies": { 2573 | "emoji-regex": "^8.0.0", 2574 | "is-fullwidth-code-point": "^3.0.0", 2575 | "strip-ansi": "^6.0.1" 2576 | }, 2577 | "engines": { 2578 | "node": ">=8" 2579 | } 2580 | }, 2581 | "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { 2582 | "version": "6.0.1", 2583 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2584 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2585 | "dev": true, 2586 | "license": "MIT", 2587 | "dependencies": { 2588 | "ansi-regex": "^5.0.1" 2589 | }, 2590 | "engines": { 2591 | "node": ">=8" 2592 | } 2593 | } 2594 | } 2595 | } 2596 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@probot/octokit-plugin-config", 3 | "version": "0.0.0-development", 4 | "description": "Get/set persisted configuration using YAML/JSON files in repositories", 5 | "type": "module", 6 | "scripts": { 7 | "build": "node scripts/build.mjs && tsc -p tsconfig.json", 8 | "lint": "prettier --check '{src,test}/**/*.ts' README.md package.json", 9 | "lint:fix": "prettier --write '{src,test}/**/*.ts' README.md package.json", 10 | "pretest": "npm run -s lint", 11 | "test": "vitest run --coverage" 12 | }, 13 | "repository": "github:probot/octokit-plugin-config", 14 | "keywords": [ 15 | "github", 16 | "api", 17 | "sdk", 18 | "toolkit" 19 | ], 20 | "author": "Gregor Martynus (https://dev.to/gr2m)", 21 | "license": "MIT", 22 | "devDependencies": { 23 | "@octokit/core": "^6.0.1", 24 | "@octokit/tsconfig": "^3.0.0", 25 | "@types/js-yaml": "^4.0.5", 26 | "@types/node": "^20.0.0", 27 | "@vitest/coverage-v8": "^3.0.0", 28 | "esbuild": "^0.25.0", 29 | "fetch-mock": "^10.0.0", 30 | "prettier": "^3.0.0", 31 | "semantic-release-plugin-update-version-in-files": "^2.0.0", 32 | "strip-indent": "^4.0.0", 33 | "typescript": "^5.0.0", 34 | "vitest": "^3.0.0" 35 | }, 36 | "peerDependencies": { 37 | "@octokit/core": ">=5" 38 | }, 39 | "release": { 40 | "branches": [ 41 | "+([0-9]).x", 42 | "main", 43 | "next", 44 | { 45 | "name": "beta", 46 | "prerelease": true 47 | } 48 | ], 49 | "plugins": [ 50 | "@semantic-release/commit-analyzer", 51 | "@semantic-release/release-notes-generator", 52 | "@semantic-release/github", 53 | [ 54 | "@semantic-release/npm", 55 | { 56 | "pkgRoot": "./pkg" 57 | } 58 | ], 59 | [ 60 | "semantic-release-plugin-update-version-in-files", 61 | { 62 | "files": [ 63 | "pkg/dist-web/*", 64 | "pkg/dist-node/*", 65 | "pkg/*/version.*" 66 | ] 67 | } 68 | ] 69 | ] 70 | }, 71 | "publishConfig": { 72 | "access": "public" 73 | }, 74 | "dependencies": { 75 | "js-yaml": "^4.1.0" 76 | }, 77 | "engines": { 78 | "node": ">=18" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /scripts/build.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import esbuild from "esbuild"; 3 | import { copyFile, readFile, writeFile, rm } from "fs/promises"; 4 | 5 | /** 6 | * @type {esbuild.BuildOptions} 7 | */ 8 | const sharedOptions = { 9 | sourcemap: "external", 10 | sourcesContent: true, 11 | minify: false, 12 | allowOverwrite: true, 13 | packages: "external", 14 | platform: "neutral", 15 | format: "esm", 16 | }; 17 | 18 | async function main() { 19 | // Start with a clean slate 20 | await rm("pkg", { recursive: true, force: true }); 21 | // Build the source code for a neutral platform as ESM 22 | await esbuild.build({ 23 | entryPoints: ["./src/*.ts", "./src/**/*.ts"], 24 | outdir: "pkg/dist-src", 25 | bundle: false, 26 | ...sharedOptions, 27 | }); 28 | 29 | // Remove the types file from the dist-src folder 30 | await rm("./pkg/dist-src/types.js"); 31 | 32 | const entryPoints = ["./pkg/dist-src/index.js"]; 33 | 34 | // Copy the README, LICENSE to the pkg folder 35 | await copyFile("LICENSE", "pkg/LICENSE"); 36 | await copyFile("README.md", "pkg/README.md"); 37 | 38 | // Handle the package.json 39 | let pkg = JSON.parse((await readFile("package.json", "utf8")).toString()); 40 | // Remove unnecessary fields from the package.json 41 | delete pkg.scripts; 42 | delete pkg.prettier; 43 | delete pkg.release; 44 | delete pkg.jest; 45 | await writeFile( 46 | "pkg/package.json", 47 | JSON.stringify( 48 | { 49 | ...pkg, 50 | files: ["dist-*/**", "bin/**"], 51 | // Tooling currently are having issues with the "exports" field, ex: TypeScript, eslint 52 | // We add a `main` and `types` field to the package.json for the time being 53 | main: "dist-src/index.js", 54 | types: "dist-types/index.d.ts", 55 | exports: { 56 | ".": { 57 | types: "./dist-types/index.d.ts", 58 | import: "./dist-src/index.js", 59 | }, 60 | }, 61 | sideEffects: false, 62 | }, 63 | null, 64 | 2 65 | ) 66 | ); 67 | } 68 | main(); -------------------------------------------------------------------------------- /src/compose-config-get.ts: -------------------------------------------------------------------------------- 1 | import type { Octokit } from "@octokit/core"; 2 | import type { Configuration, GetOptions, GetResult } from "./types.js"; 3 | import { getConfigFiles } from "./util/get-config-files.js"; 4 | 5 | /** 6 | * Loads configuration from one or multiple files and resolves with 7 | * the combined configuration as well as the list of files the configuration 8 | * was loaded from 9 | * 10 | * @param octokit Octokit instance 11 | * @param options 12 | */ 13 | export async function composeConfigGet( 14 | octokit: Octokit, 15 | { owner, repo, defaults, path, branch }: GetOptions, 16 | ): Promise> { 17 | const files = await getConfigFiles(octokit, { 18 | owner, 19 | repo, 20 | path, 21 | branch, 22 | }); 23 | 24 | const configs = files 25 | .map((file) => file.config) 26 | .reverse() 27 | .filter(Boolean) as Configuration[]; 28 | 29 | return { 30 | files, 31 | config: 32 | typeof defaults === "function" 33 | ? defaults(configs) 34 | : Object.assign({}, defaults, ...configs), 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type { Octokit } from "@octokit/core"; 2 | import type * as Types from "./types.js"; 3 | export type * from "./types.js"; 4 | import { VERSION } from "./version.js"; 5 | import { composeConfigGet } from "./compose-config-get.js"; 6 | 7 | /** 8 | * @param octokit Octokit instance 9 | */ 10 | export function config(octokit: Octokit): Types.API { 11 | return { 12 | config: { 13 | async get(options) { 14 | return composeConfigGet(octokit, options); 15 | }, 16 | }, 17 | }; 18 | } 19 | 20 | config.VERSION = VERSION; 21 | 22 | export { composeConfigGet } from "./compose-config-get.js"; 23 | 24 | export namespace createPullRequest { 25 | export type GetOptions = 26 | Types.GetOptions; 27 | export type GetResult = 28 | Types.GetResult; 29 | export type ConfigFile = Types.ConfigFile; 30 | } 31 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type Configuration = Record; 2 | 3 | export type API = { 4 | config: { 5 | get( 6 | options: GetOptions, 7 | ): Promise>; 8 | }; 9 | }; 10 | 11 | export type GetOptions = { 12 | /** 13 | * Repository owner login 14 | */ 15 | owner: string; 16 | /** 17 | * Repository name 18 | */ 19 | repo: string; 20 | /** 21 | * Path to configuration file 22 | */ 23 | path: string; 24 | /** 25 | * Default settings that the loaded configuration will be merged into. 26 | * 27 | * An object will be merged shallowly. Pass a function for deep merges and custom merge strategies, 28 | * @see https://github.com/probot/octokit-plugin-config/#merging-configuration 29 | */ 30 | defaults?: T | defaultsFunction; 31 | branch?: string; 32 | }; 33 | 34 | export type GetResult = { 35 | /** 36 | * combined combination from all loaded files and passed `defaults` option 37 | */ 38 | config: T; 39 | /** 40 | * List of files that configuration was loaded from. 41 | */ 42 | files: ConfigFile[]; 43 | }; 44 | 45 | export type ConfigFile = { 46 | /** 47 | * Repository owner login 48 | */ 49 | owner: string; 50 | /** 51 | * Repository name 52 | */ 53 | repo: string; 54 | /** 55 | * Path to configuration file 56 | */ 57 | path: string; 58 | /** 59 | * API URL for configuration file 60 | */ 61 | url: string; 62 | /** 63 | * Configuration data object. Set to null if the file does not exist. 64 | */ 65 | config: Configuration | null; 66 | }; 67 | 68 | export type defaultsFunction = (files: Configuration[]) => T; 69 | -------------------------------------------------------------------------------- /src/util/extends-to-get-content-params.ts: -------------------------------------------------------------------------------- 1 | type Options = { 2 | owner: string; 3 | path: string; 4 | url: string; 5 | extendsValue: string; 6 | }; 7 | 8 | const EXTENDS_REGEX = new RegExp( 9 | "^" + 10 | "(?:([a-z\\d](?:[a-z\\d]|-(?=[a-z\\d])){0,38})/)?" + // org 11 | "([-_.\\w\\d]+)" + // project 12 | "(?::([-_./\\w\\d]+\\.ya?ml))?" + // filename 13 | "$", 14 | "i", 15 | ); 16 | 17 | /** 18 | * Computes parameters to retrieve the configuration file specified in _extends 19 | * 20 | * Base can either be the name of a repository in the same organization or 21 | * a full slug "organization/repo". 22 | * 23 | * @param options 24 | * @return The params needed to retrieve a configuration file 25 | */ 26 | export function extendsToGetContentParams({ 27 | owner, 28 | path, 29 | url, 30 | extendsValue, 31 | }: Options) { 32 | if (typeof extendsValue !== "string") { 33 | throw new Error( 34 | `[@probot/octokit-plugin-config] Invalid value ${JSON.stringify( 35 | extendsValue, 36 | )} for _extends in ${url}`, 37 | ); 38 | } 39 | 40 | const match = extendsValue.match(EXTENDS_REGEX); 41 | 42 | if (match === null) { 43 | throw new Error( 44 | `[@probot/octokit-plugin-config] Invalid value "${extendsValue}" for _extends in ${url}`, 45 | ); 46 | } 47 | 48 | return { 49 | owner: match[1] || owner, 50 | repo: match[2], 51 | path: match[3] || path, 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /src/util/get-config-file.ts: -------------------------------------------------------------------------------- 1 | import type { Octokit } from "@octokit/core"; 2 | import yaml from "js-yaml"; 3 | 4 | import type { Configuration, ConfigFile } from "../types.js"; 5 | 6 | type Options = { 7 | owner: string; 8 | repo: string; 9 | path: string; 10 | ref?: string; 11 | }; 12 | 13 | const SUPPORTED_FILE_EXTENSIONS = ["json", "yml", "yaml"]; 14 | 15 | /** 16 | * Load configuration from a given repository and path. 17 | * 18 | * @param octokit Octokit instance 19 | * @param options 20 | */ 21 | export async function getConfigFile( 22 | octokit: Octokit, 23 | { owner, repo, path, ref }: Options, 24 | ): Promise { 25 | const fileExtension = (path.split(".").pop() as string).toLowerCase(); 26 | 27 | if (!SUPPORTED_FILE_EXTENSIONS.includes(fileExtension)) { 28 | throw new Error( 29 | `[@probot/octokit-plugin-config] .${fileExtension} extension is not support for configuration (path: "${path}")`, 30 | ); 31 | } 32 | 33 | // https://docs.github.com/en/rest/reference/repos#get-repository-content 34 | const endpoint = { 35 | method: "GET", 36 | url: "/repos/{owner}/{repo}/contents/{path}", 37 | owner, 38 | repo, 39 | path, 40 | mediaType: { 41 | format: "raw", 42 | }, 43 | // this can be just `ref` once https://github.com/octokit/endpoint.js/issues/206 is resolved 44 | ...(ref ? { ref } : {}), 45 | }; 46 | const { url } = octokit.request.endpoint(endpoint); 47 | const emptyConfigResult = { 48 | owner, 49 | repo, 50 | path, 51 | url, 52 | config: null, 53 | }; 54 | 55 | try { 56 | const { data, headers } = await octokit.request(endpoint); 57 | 58 | // If path is a submodule, or a folder, then a JSON string is returned with 59 | // the "Content-Type" header set to "application/json; charset=utf-8". 60 | // 61 | // - https://docs.github.com/en/rest/reference/repos#if-the-content-is-a-submodule 62 | // - https://docs.github.com/en/rest/reference/repos#if-the-content-is-a-directory 63 | // 64 | // symlinks just return the content of the linked file when requesting the raw formt, 65 | // so we are fine 66 | if (headers["content-type"] === "application/json; charset=utf-8") { 67 | throw new Error( 68 | `[@probot/octokit-plugin-config] ${url} exists, but is either a directory or a submodule. Ignoring.`, 69 | ); 70 | } 71 | 72 | if (fileExtension === "json") { 73 | if (typeof data === "string") { 74 | throw new Error( 75 | `[@probot/octokit-plugin-config] Configuration could not be parsed from ${url} (invalid JSON)`, 76 | ); 77 | } 78 | 79 | return { 80 | ...emptyConfigResult, 81 | config: data, 82 | }; 83 | } 84 | 85 | const config = (yaml.load(data) || {}) as unknown as Configuration; 86 | 87 | if (typeof config === "string") { 88 | throw new Error( 89 | `[@probot/octokit-plugin-config] Configuration could not be parsed from ${url} (YAML is not an object)`, 90 | ); 91 | } 92 | 93 | return { 94 | ...emptyConfigResult, 95 | config, 96 | }; 97 | } catch (error: any) { 98 | if (error.status === 404) { 99 | return emptyConfigResult; 100 | } 101 | 102 | if (error.name === "YAMLException") { 103 | const reason = /unknown tag/.test(error.message) 104 | ? "unsafe YAML" 105 | : "invalid YAML"; 106 | 107 | throw new Error( 108 | `[@probot/octokit-plugin-config] Configuration could not be parsed from ${url} (${reason})`, 109 | ); 110 | } 111 | 112 | throw error; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/util/get-config-files.ts: -------------------------------------------------------------------------------- 1 | import type { Octokit } from "@octokit/core"; 2 | import type { ConfigFile } from "../types.js"; 3 | import { getConfigFile } from "./get-config-file.js"; 4 | import { extendsToGetContentParams } from "./extends-to-get-content-params.js"; 5 | 6 | type Options = { 7 | owner: string; 8 | repo: string; 9 | path: string; 10 | branch?: string; 11 | }; 12 | 13 | /** 14 | * Load configuration from selected repository file. If the file does not exist 15 | * it loads configuration from the owners `.github` repository. 16 | * 17 | * If the repository file configuration includes an `_extends` key, that file 18 | * is loaded. Same with the target file until no `_extends` key is present. 19 | * 20 | * @param octokit Octokit instance 21 | * @param options 22 | */ 23 | export async function getConfigFiles( 24 | octokit: Octokit, 25 | { owner, repo, path, branch }: Options, 26 | ): Promise { 27 | const requestedRepoFile = await getConfigFile(octokit, { 28 | owner, 29 | repo, 30 | path, 31 | ref: branch, 32 | }); 33 | 34 | const files = [requestedRepoFile]; 35 | 36 | // if no configuration file present in selected repository, 37 | // try to load it from the `.github` repository 38 | if (!requestedRepoFile.config) { 39 | if (repo === ".github") { 40 | return files; 41 | } 42 | 43 | const defaultRepoConfig = await getConfigFile(octokit, { 44 | owner, 45 | repo: ".github", 46 | path, 47 | }); 48 | 49 | files.push(defaultRepoConfig); 50 | } 51 | 52 | const file = files[files.length - 1]; 53 | 54 | // if the configuration has no `_extends` key, we are done here. 55 | if (!file.config || !file.config._extends) { 56 | return files; 57 | } 58 | 59 | // parse the value of `_extends` into request parameters to 60 | // retrieve the new configuration file 61 | let extendConfigOptions = extendsToGetContentParams({ 62 | owner, 63 | path, 64 | url: file.url, 65 | extendsValue: file.config._extends as string, 66 | }); 67 | 68 | // remove the `_extends` key from the configuration that is returned 69 | delete file.config._extends; 70 | 71 | // now load the configuration linked from the `_extends` key. If that 72 | // configuration also includes an `_extends` key, then load that configuration 73 | // as well, until the target configuration has no `_extends` key 74 | do { 75 | const extendRepoConfig = await getConfigFile(octokit, extendConfigOptions); 76 | files.push(extendRepoConfig); 77 | if (!extendRepoConfig.config || !extendRepoConfig.config._extends) { 78 | return files; 79 | } 80 | 81 | extendConfigOptions = extendsToGetContentParams({ 82 | owner, 83 | path, 84 | url: extendRepoConfig.url, 85 | extendsValue: extendRepoConfig.config._extends as string, 86 | }); 87 | delete extendRepoConfig.config._extends; 88 | 89 | // Avoid loops 90 | const alreadyLoaded = files.find( 91 | (file) => 92 | file.owner === extendConfigOptions.owner && 93 | file.repo === extendConfigOptions.repo && 94 | file.path === extendConfigOptions.path, 95 | ); 96 | 97 | if (alreadyLoaded) { 98 | throw new Error( 99 | `[@probot/octokit-plugin-config] Recursion detected. Ignoring "_extends: ${extendRepoConfig.config._extends}" from ${extendRepoConfig.url} because ${alreadyLoaded.url} was already loaded.`, 100 | ); 101 | } 102 | } while (true); 103 | } 104 | -------------------------------------------------------------------------------- /src/version.ts: -------------------------------------------------------------------------------- 1 | export const VERSION = "0.0.0-development"; 2 | -------------------------------------------------------------------------------- /test/__snapshots__/get.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`octokit.config.get > .json extension > result 1`] = ` 4 | { 5 | "config": { 6 | "comment": "Thank you for creating the issue!", 7 | }, 8 | "files": [ 9 | { 10 | "config": { 11 | "comment": "Thank you for creating the issue!", 12 | }, 13 | "owner": "octocat", 14 | "path": ".github/my-app.json", 15 | "repo": "hello-world", 16 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.json", 17 | }, 18 | ], 19 | } 20 | `; 21 | 22 | exports[`octokit.config.get > .yaml extension > result 1`] = ` 23 | { 24 | "config": { 25 | "comment": "Thank you for creating the issue!", 26 | }, 27 | "files": [ 28 | { 29 | "config": { 30 | "comment": "Thank you for creating the issue!", 31 | }, 32 | "owner": "octocat", 33 | "path": ".github/my-app.yaml", 34 | "repo": "hello-world", 35 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml", 36 | }, 37 | ], 38 | } 39 | `; 40 | 41 | exports[`octokit.config.get > _extends file is missing > result 1`] = ` 42 | { 43 | "config": { 44 | "setting1": "value from repo config file", 45 | }, 46 | "files": [ 47 | { 48 | "config": { 49 | "setting1": "value from repo config file", 50 | }, 51 | "owner": "octocat", 52 | "path": ".github/my-app.yml", 53 | "repo": "hello-world", 54 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 55 | }, 56 | { 57 | "config": null, 58 | "owner": "octocat", 59 | "path": ".github/my-app.yml", 60 | "repo": "base", 61 | "url": "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 62 | }, 63 | ], 64 | } 65 | `; 66 | 67 | exports[`octokit.config.get > _extends: base > result 1`] = ` 68 | { 69 | "config": { 70 | "setting1": "value from repo config file", 71 | "setting2": "value from base config file", 72 | }, 73 | "files": [ 74 | { 75 | "config": { 76 | "setting1": "value from repo config file", 77 | }, 78 | "owner": "octocat", 79 | "path": ".github/my-app.yml", 80 | "repo": "hello-world", 81 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 82 | }, 83 | { 84 | "config": { 85 | "setting1": "value from base config file", 86 | "setting2": "value from base config file", 87 | }, 88 | "owner": "octocat", 89 | "path": ".github/my-app.yml", 90 | "repo": "base", 91 | "url": "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 92 | }, 93 | ], 94 | } 95 | `; 96 | 97 | exports[`octokit.config.get > _extends: base -> _extends: base2 > result 1`] = ` 98 | { 99 | "config": { 100 | "setting1": "value from repo config file", 101 | "setting2": "value from base1 config file", 102 | "setting3": "value from base2 config file", 103 | }, 104 | "files": [ 105 | { 106 | "config": { 107 | "setting1": "value from repo config file", 108 | }, 109 | "owner": "octocat", 110 | "path": ".github/my-app.yml", 111 | "repo": "hello-world", 112 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 113 | }, 114 | { 115 | "config": { 116 | "setting1": "value from base1 config file", 117 | "setting2": "value from base1 config file", 118 | }, 119 | "owner": "octocat", 120 | "path": ".github/my-app.yml", 121 | "repo": "base", 122 | "url": "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 123 | }, 124 | { 125 | "config": { 126 | "setting1": "value from base2 config file", 127 | "setting2": "value from base2 config file", 128 | "setting3": "value from base2 config file", 129 | }, 130 | "owner": "octocat", 131 | "path": ".github/my-app.yml", 132 | "repo": "base2", 133 | "url": "https://api.github.com/repos/octocat/base2/contents/.github%2Fmy-app.yml", 134 | }, 135 | ], 136 | } 137 | `; 138 | 139 | exports[`octokit.config.get > _extends: base with defaults and custom merge > result 1`] = ` 140 | { 141 | "config": { 142 | "otherSetting1": "value from repo config file", 143 | "otherSetting2": "value from base config file", 144 | "otherSetting3": "default value", 145 | "settings": { 146 | "one": "value from repo config file", 147 | "three": "default value", 148 | "two": "value from base config file", 149 | }, 150 | }, 151 | "files": [ 152 | { 153 | "config": { 154 | "otherSetting1": "value from repo config file", 155 | "settings": { 156 | "one": "value from repo config file", 157 | }, 158 | }, 159 | "owner": "octocat", 160 | "path": ".github/my-app.yml", 161 | "repo": "hello-world", 162 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 163 | }, 164 | { 165 | "config": { 166 | "otherSetting1": "value from base config file", 167 | "otherSetting2": "value from base config file", 168 | "settings": { 169 | "one": "value from base config file", 170 | "two": "value from base config file", 171 | }, 172 | }, 173 | "owner": "octocat", 174 | "path": ".github/my-app.yml", 175 | "repo": "base", 176 | "url": "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 177 | }, 178 | ], 179 | } 180 | `; 181 | 182 | exports[`octokit.config.get > _extends: base:test.yml > result 1`] = ` 183 | { 184 | "config": { 185 | "setting1": "value from repo config file", 186 | "setting2": "value from base config file", 187 | }, 188 | "files": [ 189 | { 190 | "config": { 191 | "setting1": "value from repo config file", 192 | }, 193 | "owner": "octocat", 194 | "path": ".github/my-app.yml", 195 | "repo": "hello-world", 196 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 197 | }, 198 | { 199 | "config": { 200 | "setting1": "value from base config file", 201 | "setting2": "value from base config file", 202 | }, 203 | "owner": "octocat", 204 | "path": "test.yml", 205 | "repo": "base", 206 | "url": "https://api.github.com/repos/octocat/base/contents/test.yml", 207 | }, 208 | ], 209 | } 210 | `; 211 | 212 | exports[`octokit.config.get > _extends: other-owner/base > result 1`] = ` 213 | { 214 | "config": { 215 | "setting1": "value from repo config file", 216 | "setting2": "value from base config file", 217 | }, 218 | "files": [ 219 | { 220 | "config": { 221 | "setting1": "value from repo config file", 222 | }, 223 | "owner": "octocat", 224 | "path": ".github/my-app.yml", 225 | "repo": "hello-world", 226 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 227 | }, 228 | { 229 | "config": { 230 | "setting1": "value from base config file", 231 | "setting2": "value from base config file", 232 | }, 233 | "owner": "other-owner", 234 | "path": ".github/my-app.yml", 235 | "repo": "base", 236 | "url": "https://api.github.com/repos/other-owner/base/contents/.github%2Fmy-app.yml", 237 | }, 238 | ], 239 | } 240 | `; 241 | 242 | exports[`octokit.config.get > _extends: other-owner/base:test.yml > result 1`] = ` 243 | { 244 | "config": { 245 | "setting1": "value from repo config file", 246 | "setting2": "value from base config file", 247 | }, 248 | "files": [ 249 | { 250 | "config": { 251 | "setting1": "value from repo config file", 252 | }, 253 | "owner": "octocat", 254 | "path": ".github/my-app.yml", 255 | "repo": "hello-world", 256 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 257 | }, 258 | { 259 | "config": { 260 | "setting1": "value from base config file", 261 | "setting2": "value from base config file", 262 | }, 263 | "owner": "other-owner", 264 | "path": "test.yml", 265 | "repo": "base", 266 | "url": "https://api.github.com/repos/other-owner/base/contents/test.yml", 267 | }, 268 | ], 269 | } 270 | `; 271 | 272 | exports[`octokit.config.get > README simple usage example > result 1`] = ` 273 | { 274 | "config": { 275 | "comment": "Thank you for creating the issue!", 276 | }, 277 | "files": [ 278 | { 279 | "config": { 280 | "comment": "Thank you for creating the issue!", 281 | }, 282 | "owner": "octocat", 283 | "path": ".github/my-app.yml", 284 | "repo": "hello-world", 285 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 286 | }, 287 | ], 288 | } 289 | `; 290 | 291 | exports[`octokit.config.get > branch option > result 1`] = ` 292 | { 293 | "config": { 294 | "comment": "Thank you for creating the issue!", 295 | }, 296 | "files": [ 297 | { 298 | "config": { 299 | "comment": "Thank you for creating the issue!", 300 | }, 301 | "owner": "octocat", 302 | "path": ".github/my-app.yml", 303 | "repo": "hello-world", 304 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml?ref=my-branch", 305 | }, 306 | ], 307 | } 308 | `; 309 | 310 | exports[`octokit.config.get > config file is empty > result 1`] = ` 311 | { 312 | "config": {}, 313 | "files": [ 314 | { 315 | "config": {}, 316 | "owner": "octocat", 317 | "path": ".github/my-app.yml", 318 | "repo": "hello-world", 319 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 320 | }, 321 | ], 322 | } 323 | `; 324 | 325 | exports[`octokit.config.get > config file missing > result 1`] = ` 326 | { 327 | "config": { 328 | "comment": "Thank you for creating the issue!", 329 | }, 330 | "files": [ 331 | { 332 | "config": null, 333 | "owner": "octocat", 334 | "path": ".github/my-app.yml", 335 | "repo": "hello-world", 336 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 337 | }, 338 | { 339 | "config": null, 340 | "owner": "octocat", 341 | "path": ".github/my-app.yml", 342 | "repo": ".github", 343 | "url": "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 344 | }, 345 | ], 346 | } 347 | `; 348 | 349 | exports[`octokit.config.get > merges deeply using defaults function > result 1`] = ` 350 | { 351 | "config": { 352 | "otherSetting1": "value from config file", 353 | "otherSetting2": "default value", 354 | "settings": { 355 | "one": "value from config file", 356 | "two": "default value", 357 | }, 358 | }, 359 | "files": [ 360 | { 361 | "config": { 362 | "otherSetting1": "value from config file", 363 | "settings": { 364 | "one": "value from config file", 365 | }, 366 | }, 367 | "owner": "octocat", 368 | "path": ".github/my-app.yml", 369 | "repo": "hello-world", 370 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 371 | }, 372 | ], 373 | } 374 | `; 375 | 376 | exports[`octokit.config.get > merges defaults option > result 1`] = ` 377 | { 378 | "config": { 379 | "config": "value from .github/my-app.yml", 380 | "otherConfig": "default value", 381 | }, 382 | "files": [ 383 | { 384 | "config": { 385 | "config": "value from .github/my-app.yml", 386 | }, 387 | "owner": "octocat", 388 | "path": ".github/my-app.yml", 389 | "repo": "hello-world", 390 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 391 | }, 392 | ], 393 | } 394 | `; 395 | 396 | exports[`octokit.config.get > merges defaults option from .github repository > result 1`] = ` 397 | { 398 | "config": { 399 | "config": "value from octocat/.github:.github/my-app.yml", 400 | "otherConfig": "default value", 401 | }, 402 | "files": [ 403 | { 404 | "config": null, 405 | "owner": "octocat", 406 | "path": ".github/my-app.yml", 407 | "repo": "hello-world", 408 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 409 | }, 410 | { 411 | "config": { 412 | "config": "value from octocat/.github:.github/my-app.yml", 413 | }, 414 | "owner": "octocat", 415 | "path": ".github/my-app.yml", 416 | "repo": ".github", 417 | "url": "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 418 | }, 419 | ], 420 | } 421 | `; 422 | 423 | exports[`octokit.config.get > repo is .github > result 1`] = ` 424 | { 425 | "config": {}, 426 | "files": [ 427 | { 428 | "config": null, 429 | "owner": "octocat", 430 | "path": ".github/my-app.yml", 431 | "repo": ".github", 432 | "url": "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 433 | }, 434 | ], 435 | } 436 | `; 437 | 438 | exports[`octokit.config.get > resolves _extends in .github repository file > result 1`] = ` 439 | { 440 | "config": { 441 | "config": "value from octocat/.github:.github/my-second-app.yml", 442 | "otherConfig": "value from octocat/hello-world:.github/my-third-app.yml", 443 | }, 444 | "files": [ 445 | { 446 | "config": null, 447 | "owner": "octocat", 448 | "path": ".github/my-app.yml", 449 | "repo": "hello-world", 450 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 451 | }, 452 | { 453 | "config": {}, 454 | "owner": "octocat", 455 | "path": ".github/my-app.yml", 456 | "repo": ".github", 457 | "url": "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 458 | }, 459 | { 460 | "config": { 461 | "config": "value from octocat/.github:.github/my-second-app.yml", 462 | }, 463 | "owner": "octocat", 464 | "path": ".github/my-second-app.yml", 465 | "repo": ".github", 466 | "url": "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-second-app.yml", 467 | }, 468 | { 469 | "config": { 470 | "otherConfig": "value from octocat/hello-world:.github/my-third-app.yml", 471 | }, 472 | "owner": "octocat", 473 | "path": ".github/my-third-app.yml", 474 | "repo": "hello-world", 475 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-third-app.yml", 476 | }, 477 | ], 478 | } 479 | `; 480 | 481 | exports[`octokit.config.get > returns defaults option when no config files exist > result 1`] = ` 482 | { 483 | "config": { 484 | "comment": "Thank you for creating the issue!", 485 | }, 486 | "files": [ 487 | { 488 | "config": null, 489 | "owner": "octocat", 490 | "path": ".github/my-app.yml", 491 | "repo": "hello-world", 492 | "url": "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 493 | }, 494 | { 495 | "config": null, 496 | "owner": "octocat", 497 | "path": ".github/my-app.yml", 498 | "repo": ".github", 499 | "url": "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 500 | }, 501 | ], 502 | } 503 | `; 504 | -------------------------------------------------------------------------------- /test/get.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { Octokit } from "@octokit/core"; 3 | import fetchMock from "fetch-mock"; 4 | import stripIndent from "strip-indent"; 5 | 6 | import { config } from "../src/index.js"; 7 | import type { Configuration } from "../src/types.js"; 8 | 9 | const TestOctokit = Octokit.plugin(config); 10 | 11 | const NOT_FOUND_RESPONSE = { 12 | status: 404, 13 | body: { 14 | message: "Not Found", 15 | documentation_url: 16 | "https://docs.github.com/rest/reference/repos#get-repository-content", 17 | }, 18 | }; 19 | 20 | const deepMergeSettings = ( 21 | defaults: Configuration, 22 | configs: Configuration[], 23 | ) => { 24 | const allConfigs = [defaults, ...configs]; 25 | const fileSettingsConfigs = allConfigs.map( 26 | (config: Configuration) => config.settings, 27 | ); 28 | return Object.assign({}, ...allConfigs, { 29 | settings: Object.assign({}, ...fileSettingsConfigs), 30 | }); 31 | }; 32 | 33 | describe("octokit.config.get", () => { 34 | it("README simple usage example", async () => { 35 | const mock = fetchMock 36 | .sandbox() 37 | .getOnce( 38 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 39 | `comment: 'Thank you for creating the issue!'`, 40 | { 41 | headers: { 42 | accept: "application/vnd.github.v3.raw", 43 | }, 44 | }, 45 | ); 46 | const octokit = new TestOctokit({ 47 | request: { 48 | fetch: mock, 49 | }, 50 | }); 51 | 52 | const result = await octokit.config.get({ 53 | owner: "octocat", 54 | repo: "hello-world", 55 | path: ".github/my-app.yml", 56 | }); 57 | 58 | expect(result).toMatchSnapshot("result"); 59 | expect(mock.done()).toBe(true); 60 | }); 61 | 62 | it("config file missing", async () => { 63 | const mock = fetchMock 64 | .sandbox() 65 | .getOnce( 66 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 67 | NOT_FOUND_RESPONSE, 68 | ) 69 | .getOnce( 70 | "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 71 | NOT_FOUND_RESPONSE, 72 | ); 73 | 74 | const octokit = new TestOctokit({ 75 | request: { 76 | fetch: mock, 77 | }, 78 | }); 79 | 80 | const result = await octokit.config.get({ 81 | owner: "octocat", 82 | repo: "hello-world", 83 | path: ".github/my-app.yml", 84 | defaults: { 85 | comment: "Thank you for creating the issue!", 86 | }, 87 | }); 88 | 89 | expect(result).toMatchSnapshot("result"); 90 | expect(mock.done()).toBe(true); 91 | }); 92 | 93 | it("returns defaults option when no config files exist", async () => { 94 | const mock = fetchMock 95 | .sandbox() 96 | .getOnce( 97 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 98 | NOT_FOUND_RESPONSE, 99 | ) 100 | .getOnce( 101 | "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 102 | NOT_FOUND_RESPONSE, 103 | ); 104 | 105 | const octokit = new TestOctokit({ 106 | request: { 107 | fetch: mock, 108 | }, 109 | }); 110 | 111 | const result = await octokit.config.get({ 112 | owner: "octocat", 113 | repo: "hello-world", 114 | path: ".github/my-app.yml", 115 | defaults: { 116 | comment: "Thank you for creating the issue!", 117 | }, 118 | }); 119 | 120 | expect(result).toMatchSnapshot("result"); 121 | expect(mock.done()).toBe(true); 122 | }); 123 | 124 | it("merges defaults option", async () => { 125 | const mock = fetchMock 126 | .sandbox() 127 | .getOnce( 128 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 129 | `config: 'value from .github/my-app.yml'`, 130 | ); 131 | 132 | const octokit = new TestOctokit({ 133 | request: { 134 | fetch: mock, 135 | }, 136 | }); 137 | 138 | const result = await octokit.config.get({ 139 | owner: "octocat", 140 | repo: "hello-world", 141 | path: ".github/my-app.yml", 142 | defaults: { 143 | config: "default value", 144 | otherConfig: "default value", 145 | }, 146 | }); 147 | 148 | expect(result).toMatchSnapshot("result"); 149 | expect(mock.done()).toBe(true); 150 | }); 151 | 152 | it("merges defaults option from .github repository", async () => { 153 | const mock = fetchMock 154 | .sandbox() 155 | .getOnce( 156 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 157 | NOT_FOUND_RESPONSE, 158 | ) 159 | .getOnce( 160 | "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 161 | `config: 'value from octocat/.github:.github/my-app.yml'`, 162 | ); 163 | 164 | const octokit = new TestOctokit({ 165 | request: { 166 | fetch: mock, 167 | }, 168 | }); 169 | 170 | const result = await octokit.config.get({ 171 | owner: "octocat", 172 | repo: "hello-world", 173 | path: ".github/my-app.yml", 174 | defaults: { 175 | config: "default value", 176 | otherConfig: "default value", 177 | }, 178 | }); 179 | 180 | expect(result).toMatchSnapshot("result"); 181 | expect(mock.done()).toBe(true); 182 | }); 183 | 184 | it("resolves _extends in .github repository file", async () => { 185 | const mock = fetchMock 186 | .sandbox() 187 | .getOnce( 188 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 189 | NOT_FOUND_RESPONSE, 190 | ) 191 | .getOnce( 192 | "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 193 | `_extends: '.github:.github/my-second-app.yml'`, 194 | ) 195 | .getOnce( 196 | "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-second-app.yml", 197 | stripIndent(` 198 | config: value from octocat/.github:.github/my-second-app.yml 199 | _extends: hello-world:.github/my-third-app.yml`), 200 | ) 201 | .getOnce( 202 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-third-app.yml", 203 | `otherConfig: 'value from octocat/hello-world:.github/my-third-app.yml'`, 204 | ); 205 | 206 | const octokit = new TestOctokit({ 207 | request: { 208 | fetch: mock, 209 | }, 210 | }); 211 | 212 | const result = await octokit.config.get({ 213 | owner: "octocat", 214 | repo: "hello-world", 215 | path: ".github/my-app.yml", 216 | defaults: { 217 | config: "default value", 218 | otherConfig: "default value", 219 | }, 220 | }); 221 | 222 | expect(result).toMatchSnapshot("result"); 223 | expect(mock.done()).toBe(true); 224 | }); 225 | 226 | it("merges deeply using defaults function", async () => { 227 | const mock = fetchMock.sandbox().getOnce( 228 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 229 | stripIndent(` 230 | settings: 231 | one: value from config file 232 | otherSetting1: value from config file`), 233 | ); 234 | 235 | const octokit = new TestOctokit({ 236 | request: { 237 | fetch: mock, 238 | }, 239 | }); 240 | 241 | const defaults = { 242 | settings: { 243 | one: "default value", 244 | two: "default value", 245 | }, 246 | otherSetting1: "default value", 247 | otherSetting2: "default value", 248 | }; 249 | const result = await octokit.config.get({ 250 | owner: "octocat", 251 | repo: "hello-world", 252 | path: ".github/my-app.yml", 253 | defaults: (configs) => deepMergeSettings(defaults, configs), 254 | }); 255 | 256 | expect(result).toMatchSnapshot("result"); 257 | expect(mock.done()).toBe(true); 258 | }); 259 | 260 | it("branch option", async () => { 261 | const mock = fetchMock 262 | .sandbox() 263 | .getOnce( 264 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml?ref=my-branch", 265 | `comment: 'Thank you for creating the issue!'`, 266 | { 267 | headers: { 268 | accept: "application/vnd.github.v3.raw", 269 | }, 270 | }, 271 | ); 272 | const octokit = new TestOctokit({ 273 | request: { 274 | fetch: mock, 275 | }, 276 | }); 277 | 278 | const result = await octokit.config.get({ 279 | owner: "octocat", 280 | repo: "hello-world", 281 | path: ".github/my-app.yml", 282 | branch: "my-branch", 283 | }); 284 | 285 | expect(result).toMatchSnapshot("result"); 286 | expect(mock.done()).toBe(true); 287 | }); 288 | 289 | it("_extends: base", async () => { 290 | const mock = fetchMock 291 | .sandbox() 292 | .getOnce( 293 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 294 | stripIndent(` 295 | setting1: value from repo config file 296 | _extends: base`), 297 | ) 298 | .getOnce( 299 | "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 300 | stripIndent(` 301 | setting1: value from base config file 302 | setting2: value from base config file`), 303 | ); 304 | 305 | const octokit = new TestOctokit({ 306 | request: { 307 | fetch: mock, 308 | }, 309 | }); 310 | const result = await octokit.config.get({ 311 | owner: "octocat", 312 | repo: "hello-world", 313 | path: ".github/my-app.yml", 314 | }); 315 | 316 | expect(result).toMatchSnapshot("result"); 317 | expect(mock.done()).toBe(true); 318 | }); 319 | 320 | it("_extends: base -> _extends: base2", async () => { 321 | const mock = fetchMock 322 | .sandbox() 323 | .getOnce( 324 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 325 | stripIndent(` 326 | setting1: value from repo config file 327 | _extends: base`), 328 | ) 329 | .getOnce( 330 | "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 331 | stripIndent(` 332 | setting1: value from base1 config file 333 | setting2: value from base1 config file 334 | _extends: base2`), 335 | ) 336 | .getOnce( 337 | "https://api.github.com/repos/octocat/base2/contents/.github%2Fmy-app.yml", 338 | stripIndent(` 339 | setting1: value from base2 config file 340 | setting2: value from base2 config file 341 | setting3: value from base2 config file`), 342 | ); 343 | 344 | const octokit = new TestOctokit({ 345 | request: { 346 | fetch: mock, 347 | }, 348 | }); 349 | const result = await octokit.config.get({ 350 | owner: "octocat", 351 | repo: "hello-world", 352 | path: ".github/my-app.yml", 353 | }); 354 | 355 | expect(result).toMatchSnapshot("result"); 356 | expect(mock.done()).toBe(true); 357 | }); 358 | 359 | it("_extends: base with defaults and custom merge", async () => { 360 | const mock = fetchMock 361 | .sandbox() 362 | .getOnce( 363 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 364 | stripIndent(` 365 | settings: 366 | one: value from repo config file 367 | otherSetting1: value from repo config file 368 | _extends: base`), 369 | ) 370 | .getOnce( 371 | "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 372 | stripIndent(` 373 | settings: 374 | one: value from base config file 375 | two: value from base config file 376 | otherSetting1: value from base config file 377 | otherSetting2: value from base config file`), 378 | ); 379 | 380 | const octokit = new TestOctokit({ 381 | request: { 382 | fetch: mock, 383 | }, 384 | }); 385 | const defaults = { 386 | settings: { 387 | one: "default value", 388 | two: "default value", 389 | three: "default value", 390 | }, 391 | otherSetting1: "default value", 392 | otherSetting2: "default value", 393 | otherSetting3: "default value", 394 | }; 395 | const result = await octokit.config.get({ 396 | owner: "octocat", 397 | repo: "hello-world", 398 | path: ".github/my-app.yml", 399 | defaults: (configs) => deepMergeSettings(defaults, configs), 400 | }); 401 | 402 | expect(result).toMatchSnapshot("result"); 403 | expect(mock.done()).toBe(true); 404 | }); 405 | 406 | it("config file is a submodule", async () => { 407 | expect.assertions(2); 408 | 409 | const mock = fetchMock 410 | .sandbox() 411 | .getOnce( 412 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 413 | { 414 | body: {}, 415 | headers: { 416 | "content-type": "application/json; charset=utf-8", 417 | }, 418 | }, 419 | ); 420 | 421 | const octokit = new TestOctokit({ 422 | request: { 423 | fetch: mock, 424 | }, 425 | }); 426 | 427 | try { 428 | await octokit.config.get({ 429 | owner: "octocat", 430 | repo: "hello-world", 431 | path: ".github/my-app.yml", 432 | }); 433 | } catch (error: any) { 434 | expect(error.message).toMatchInlineSnapshot( 435 | `"[@probot/octokit-plugin-config] https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml exists, but is either a directory or a submodule. Ignoring."`, 436 | ); 437 | } 438 | 439 | expect(mock.done()).toBe(true); 440 | }); 441 | 442 | it("config file is empty", async () => { 443 | const mock = fetchMock 444 | .sandbox() 445 | .getOnce( 446 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 447 | "", 448 | ); 449 | 450 | const octokit = new TestOctokit({ 451 | request: { 452 | fetch: mock, 453 | }, 454 | }); 455 | 456 | const result = await octokit.config.get({ 457 | owner: "octocat", 458 | repo: "hello-world", 459 | path: ".github/my-app.yml", 460 | }); 461 | 462 | expect(result).toMatchSnapshot("result"); 463 | expect(mock.done()).toBe(true); 464 | }); 465 | 466 | it("repo is .github", async () => { 467 | const mock = fetchMock 468 | .sandbox() 469 | .getOnce( 470 | "https://api.github.com/repos/octocat/.github/contents/.github%2Fmy-app.yml", 471 | NOT_FOUND_RESPONSE, 472 | ); 473 | 474 | const octokit = new TestOctokit({ 475 | request: { 476 | fetch: mock, 477 | }, 478 | }); 479 | 480 | const result = await octokit.config.get({ 481 | owner: "octocat", 482 | repo: ".github", 483 | path: ".github/my-app.yml", 484 | }); 485 | 486 | expect(result).toMatchSnapshot("result"); 487 | expect(mock.done()).toBe(true); 488 | }); 489 | 490 | it("_extends file is missing", async () => { 491 | const mock = fetchMock 492 | .sandbox() 493 | .getOnce( 494 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 495 | stripIndent(` 496 | setting1: value from repo config file 497 | _extends: base`), 498 | ) 499 | .getOnce( 500 | "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 501 | NOT_FOUND_RESPONSE, 502 | ); 503 | 504 | const octokit = new TestOctokit({ 505 | request: { 506 | fetch: mock, 507 | }, 508 | }); 509 | const result = await octokit.config.get({ 510 | owner: "octocat", 511 | repo: "hello-world", 512 | path: ".github/my-app.yml", 513 | }); 514 | 515 | expect(result).toMatchSnapshot("result"); 516 | expect(mock.done()).toBe(true); 517 | }); 518 | 519 | it("request error", async () => { 520 | expect.assertions(2); 521 | 522 | const mock = fetchMock 523 | .sandbox() 524 | .getOnce( 525 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 526 | { 527 | status: 500, 528 | }, 529 | ); 530 | 531 | const octokit = new TestOctokit({ 532 | request: { 533 | fetch: mock, 534 | }, 535 | }); 536 | 537 | try { 538 | await octokit.config.get({ 539 | owner: "octocat", 540 | repo: "hello-world", 541 | path: ".github/my-app.yml", 542 | }); 543 | } catch (error: any) { 544 | expect(error.status).toEqual(500); 545 | } 546 | 547 | expect(mock.done()).toBe(true); 548 | }); 549 | 550 | it("recursion", async () => { 551 | expect.assertions(2); 552 | 553 | const mock = fetchMock 554 | .sandbox() 555 | .getOnce( 556 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 557 | stripIndent(` 558 | settings: 559 | one: value from repo config file 560 | otherSetting1: value from repo config file 561 | _extends: base`), 562 | ) 563 | .getOnce( 564 | "https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml", 565 | stripIndent(` 566 | settings: 567 | one: value from base config file 568 | two: value from base config file 569 | otherSetting1: value from base config file 570 | otherSetting2: value from base config file 571 | _extends: hello-world`), 572 | ); 573 | 574 | const octokit = new TestOctokit({ 575 | request: { 576 | fetch: mock, 577 | }, 578 | }); 579 | try { 580 | await octokit.config.get({ 581 | owner: "octocat", 582 | repo: "hello-world", 583 | path: ".github/my-app.yml", 584 | }); 585 | } catch (error: any) { 586 | expect(error.message).toMatchInlineSnapshot( 587 | `"[@probot/octokit-plugin-config] Recursion detected. Ignoring "_extends: undefined" from https://api.github.com/repos/octocat/base/contents/.github%2Fmy-app.yml because https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml was already loaded."`, 588 | ); 589 | } 590 | 591 | expect(mock.done()).toBe(true); 592 | }); 593 | 594 | it(".yaml extension", async () => { 595 | const mock = fetchMock 596 | .sandbox() 597 | .getOnce( 598 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml", 599 | `comment: 'Thank you for creating the issue!'`, 600 | { 601 | headers: { 602 | accept: "application/vnd.github.v3.raw", 603 | }, 604 | }, 605 | ); 606 | const octokit = new TestOctokit({ 607 | request: { 608 | fetch: mock, 609 | }, 610 | }); 611 | 612 | const result = await octokit.config.get({ 613 | owner: "octocat", 614 | repo: "hello-world", 615 | path: ".github/my-app.yaml", 616 | }); 617 | 618 | expect(result).toMatchSnapshot("result"); 619 | expect(mock.done()).toBe(true); 620 | }); 621 | 622 | it(".json extension", async () => { 623 | const mock = fetchMock.sandbox().getOnce( 624 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.json", 625 | { comment: "Thank you for creating the issue!" }, 626 | { 627 | headers: { 628 | accept: "application/vnd.github.v3.raw", 629 | }, 630 | }, 631 | ); 632 | const octokit = new TestOctokit({ 633 | request: { 634 | fetch: mock, 635 | }, 636 | }); 637 | 638 | const result = await octokit.config.get({ 639 | owner: "octocat", 640 | repo: "hello-world", 641 | path: ".github/my-app.json", 642 | }); 643 | 644 | expect(result).toMatchSnapshot("result"); 645 | expect(mock.done()).toBe(true); 646 | }); 647 | 648 | it(".unknown extension", async () => { 649 | expect.assertions(1); 650 | 651 | const octokit = new TestOctokit(); 652 | 653 | try { 654 | await octokit.config.get({ 655 | owner: "octocat", 656 | repo: "hello-world", 657 | path: ".github/my-app.unknown", 658 | }); 659 | } catch (error: any) { 660 | expect(error.message).toEqual( 661 | '[@probot/octokit-plugin-config] .unknown extension is not support for configuration (path: ".github/my-app.unknown")', 662 | ); 663 | } 664 | }); 665 | 666 | it("malformed json", async () => { 667 | expect.assertions(2); 668 | 669 | const mock = fetchMock 670 | .sandbox() 671 | .getOnce( 672 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.json", 673 | "malformed json", 674 | { 675 | headers: { 676 | accept: "application/vnd.github.v3.raw", 677 | }, 678 | }, 679 | ); 680 | const octokit = new TestOctokit({ 681 | request: { 682 | fetch: mock, 683 | }, 684 | }); 685 | 686 | try { 687 | await octokit.config.get({ 688 | owner: "octocat", 689 | repo: "hello-world", 690 | path: ".github/my-app.json", 691 | }); 692 | } catch (error: any) { 693 | expect(error.message).toMatchInlineSnapshot( 694 | `"[@probot/octokit-plugin-config] Configuration could not be parsed from https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.json (invalid JSON)"`, 695 | ); 696 | } 697 | 698 | expect(mock.done()).toBe(true); 699 | }); 700 | 701 | it("malformed yaml", async () => { 702 | expect.assertions(2); 703 | 704 | const mock = fetchMock 705 | .sandbox() 706 | .getOnce( 707 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml", 708 | "malformed yaml", 709 | { 710 | headers: { 711 | accept: "application/vnd.github.v3.raw", 712 | }, 713 | }, 714 | ); 715 | const octokit = new TestOctokit({ 716 | request: { 717 | fetch: mock, 718 | }, 719 | }); 720 | 721 | try { 722 | await octokit.config.get({ 723 | owner: "octocat", 724 | repo: "hello-world", 725 | path: ".github/my-app.yaml", 726 | }); 727 | } catch (error: any) { 728 | expect(error.message).toMatchInlineSnapshot( 729 | `"[@probot/octokit-plugin-config] Configuration could not be parsed from https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml (YAML is not an object)"`, 730 | ); 731 | } 732 | 733 | expect(mock.done()).toBe(true); 734 | }); 735 | 736 | it("malformed yaml: @", async () => { 737 | expect.assertions(2); 738 | 739 | const mock = fetchMock 740 | .sandbox() 741 | .getOnce( 742 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml", 743 | "@", 744 | { 745 | headers: { 746 | accept: "application/vnd.github.v3.raw", 747 | }, 748 | }, 749 | ); 750 | const octokit = new TestOctokit({ 751 | request: { 752 | fetch: mock, 753 | }, 754 | }); 755 | 756 | try { 757 | await octokit.config.get({ 758 | owner: "octocat", 759 | repo: "hello-world", 760 | path: ".github/my-app.yaml", 761 | }); 762 | } catch (error: any) { 763 | expect(error.message).toMatchInlineSnapshot( 764 | `"[@probot/octokit-plugin-config] Configuration could not be parsed from https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml (invalid YAML)"`, 765 | ); 766 | } 767 | 768 | expect(mock.done()).toBe(true); 769 | }); 770 | it("unsafe yaml", async () => { 771 | expect.assertions(2); 772 | 773 | const mock = fetchMock 774 | .sandbox() 775 | .getOnce( 776 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml", 777 | 'evil: ! "function () {}"', 778 | { 779 | headers: { 780 | accept: "application/vnd.github.v3.raw", 781 | }, 782 | }, 783 | ); 784 | const octokit = new TestOctokit({ 785 | request: { 786 | fetch: mock, 787 | }, 788 | }); 789 | 790 | try { 791 | await octokit.config.get({ 792 | owner: "octocat", 793 | repo: "hello-world", 794 | path: ".github/my-app.yaml", 795 | }); 796 | } catch (error: any) { 797 | expect(error.message).toMatchInlineSnapshot( 798 | `"[@probot/octokit-plugin-config] Configuration could not be parsed from https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yaml (unsafe YAML)"`, 799 | ); 800 | } 801 | 802 | expect(mock.done()).toBe(true); 803 | }); 804 | 805 | it("_extends: other-owner/base", async () => { 806 | const mock = fetchMock 807 | .sandbox() 808 | .getOnce( 809 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 810 | stripIndent(` 811 | setting1: value from repo config file 812 | _extends: other-owner/base 813 | `), 814 | ) 815 | .getOnce( 816 | "https://api.github.com/repos/other-owner/base/contents/.github%2Fmy-app.yml", 817 | stripIndent(` 818 | setting1: value from base config file 819 | setting2: value from base config file 820 | `), 821 | ); 822 | 823 | const octokit = new TestOctokit({ 824 | request: { 825 | fetch: mock, 826 | }, 827 | }); 828 | const result = await octokit.config.get({ 829 | owner: "octocat", 830 | repo: "hello-world", 831 | path: ".github/my-app.yml", 832 | }); 833 | 834 | expect(result).toMatchSnapshot("result"); 835 | expect(mock.done()).toBe(true); 836 | }); 837 | 838 | it("_extends: base:test.yml", async () => { 839 | const mock = fetchMock 840 | .sandbox() 841 | .getOnce( 842 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 843 | stripIndent(` 844 | setting1: value from repo config file 845 | _extends: base:test.yml 846 | `), 847 | ) 848 | .getOnce( 849 | "https://api.github.com/repos/octocat/base/contents/test.yml", 850 | stripIndent(` 851 | setting1: value from base config file 852 | setting2: value from base config file 853 | `), 854 | ); 855 | 856 | const octokit = new TestOctokit({ 857 | request: { 858 | fetch: mock, 859 | }, 860 | }); 861 | const result = await octokit.config.get({ 862 | owner: "octocat", 863 | repo: "hello-world", 864 | path: ".github/my-app.yml", 865 | }); 866 | 867 | expect(result).toMatchSnapshot("result"); 868 | expect(mock.done()).toBe(true); 869 | }); 870 | 871 | it("_extends: other-owner/base:test.yml", async () => { 872 | const mock = fetchMock 873 | .sandbox() 874 | .getOnce( 875 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 876 | stripIndent(` 877 | setting1: value from repo config file 878 | _extends: other-owner/base:test.yml 879 | `), 880 | ) 881 | .getOnce( 882 | "https://api.github.com/repos/other-owner/base/contents/test.yml", 883 | stripIndent(` 884 | setting1: value from base config file 885 | setting2: value from base config file 886 | `), 887 | ); 888 | 889 | const octokit = new TestOctokit({ 890 | request: { 891 | fetch: mock, 892 | }, 893 | }); 894 | const result = await octokit.config.get({ 895 | owner: "octocat", 896 | repo: "hello-world", 897 | path: ".github/my-app.yml", 898 | }); 899 | 900 | expect(result).toMatchSnapshot("result"); 901 | expect(mock.done()).toBe(true); 902 | }); 903 | 904 | it("_extends: invalid!", async () => { 905 | expect.assertions(2); 906 | 907 | const mock = fetchMock.sandbox().getOnce( 908 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 909 | stripIndent(` 910 | setting1: value from repo config file 911 | _extends: invalid! 912 | `), 913 | ); 914 | 915 | const octokit = new TestOctokit({ 916 | request: { 917 | fetch: mock, 918 | }, 919 | }); 920 | 921 | try { 922 | await octokit.config.get({ 923 | owner: "octocat", 924 | repo: "hello-world", 925 | path: ".github/my-app.yml", 926 | }); 927 | } catch (error: any) { 928 | expect(error.message).toMatchInlineSnapshot( 929 | `"[@probot/octokit-plugin-config] Invalid value "invalid!" for _extends in https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml"`, 930 | ); 931 | } 932 | 933 | expect(mock.done()).toBe(true); 934 | }); 935 | 936 | it("_extends: { nope }", async () => { 937 | expect.assertions(2); 938 | 939 | const mock = fetchMock.sandbox().getOnce( 940 | "https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml", 941 | stripIndent(` 942 | setting1: value from repo config file 943 | _extends: { nope } 944 | `), 945 | ); 946 | 947 | const octokit = new TestOctokit({ 948 | request: { 949 | fetch: mock, 950 | }, 951 | }); 952 | 953 | try { 954 | await octokit.config.get({ 955 | owner: "octocat", 956 | repo: "hello-world", 957 | path: ".github/my-app.yml", 958 | }); 959 | } catch (error: any) { 960 | expect(error.message).toMatchInlineSnapshot( 961 | `"[@probot/octokit-plugin-config] Invalid value {"nope":null} for _extends in https://api.github.com/repos/octocat/hello-world/contents/.github%2Fmy-app.yml"`, 962 | ); 963 | } 964 | 965 | expect(mock.done()).toBe(true); 966 | }); 967 | }); 968 | -------------------------------------------------------------------------------- /test/issues.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { Octokit } from "@octokit/core"; 3 | import fetchMock from "fetch-mock"; 4 | 5 | import { config } from "../src/index.js"; 6 | 7 | const TestOctokit = Octokit.plugin(config); 8 | 9 | describe("issues", () => { 10 | it("#91 sets incorrect accept header when media type previews are set", async () => { 11 | const mock = fetchMock.sandbox().getOnce((_url, { headers }) => { 12 | // @ts-ignore TypeScript says we can't do this but turns out we can so there you go 13 | expect(headers["accept"]).toEqual("application/vnd.github.v3.raw"); 14 | return true; 15 | }, "foo: bar"); 16 | const octokit = new TestOctokit({ 17 | previews: ["luke-cage"], 18 | request: { 19 | fetch: mock, 20 | }, 21 | }); 22 | 23 | await octokit.config.get({ 24 | owner: "ScottChapman", 25 | repo: "probot-config-plugin-bug", 26 | path: "config.yaml", 27 | }); 28 | 29 | expect(mock.done()).toBe(true); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/smoke.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { config, composeConfigGet } from "../src/index.js"; 3 | 4 | describe("Smoke test", () => { 5 | it("config is a function", () => { 6 | expect(config).toBeInstanceOf(Function); 7 | }); 8 | 9 | it("config.VERSION is set", () => { 10 | expect(config.VERSION).toEqual("0.0.0-development"); 11 | }); 12 | 13 | it("composeConfigGet is a function", () => { 14 | expect(composeConfigGet).toBeInstanceOf(Function); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "emitDeclarationOnly": false, 5 | "noEmit": true, 6 | }, 7 | "include": ["src/**/*"] 8 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@octokit/tsconfig", 3 | "compilerOptions": { 4 | "esModuleInterop": true, 5 | "declaration": true, 6 | "outDir": "pkg/dist-types", 7 | "emitDeclarationOnly": true, 8 | "sourceMap": true 9 | }, 10 | "include": [ 11 | "src/**/*" 12 | ] 13 | } -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | coverage: { 6 | include: ["src/**/*.ts"], 7 | reporter: ["html"], 8 | thresholds: { 9 | 100: true, 10 | }, 11 | }, 12 | }, 13 | }); 14 | --------------------------------------------------------------------------------