diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..4c18324 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "js", + //https://containers.dev/templates or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/typescript-node", + // https://containers.dev/features + "features": { + "ghcr.io/devcontainers/features/github-cli:1": { + "installDirectlyFromGitHubRelease": true, + "version": "latest" + }, + "ghcr.io/devcontainers/features/node:1": { + "nodeGypDependencies": true, + "version": "lts" + } + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "pnpm install", + + "customizations": { + "codespaces": { + "openFiles": ["readme.md"] + }, + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "yoavbls.pretty-ts-errors" + ], + "settings": { + "javascript.format.enable": false, + "typescript.format.enable": false, + "editor.formatOnPaste": true, + "editor.formatOnType": true, + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "javascript.preferences.importModuleSpecifierEnding": "js", + "typescript.preferences.importModuleSpecifierEnding": "auto", + "typescript.enablePromptUseWorkspaceTsdk": true + } + } + } +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..e016438 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @hugomrdias diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ced9997 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,108 @@ +# Code of Conduct + +**TL;DR Be kind, inclusive, and considerate.** + +In the interest of fostering an open, inclusive, and welcoming environment, all +members, contributors, and maintainers interacting within our online community +(including Discord, Discourse, etc.), on affiliated projects and repositories +(including issues, pull requests, and discussions on Github), and/or involved +with associated events pledge to accept and observe the following Code of +Conduct. + +As members, contributors, and maintainers, we pledge to make participation in +our projects and community a harassment-free experience, ensuring a safe +environment for all, regardless of background, gender, gender identity and +expression, age, sexual orientation, disability, physical appearance, body size, +race, ethnicity, religion (or lack thereof), or any other dimension of +diversity. + +Sexual language and imagery will not be accepted in any way. Be kind to others. +Do not insult or put down people within the community. Behave professionally. +Remember that harassment and sexist, racist, or exclusionary jokes are not +appropriate in any form. Participants violating these rules may be sanctioned or +expelled from the community and related projects. + +## Spelling it out + +Harassment includes offensive verbal comments or actions related to or involving + +- background +- gender +- gender identity and expression +- age +- sexual orientation +- disability +- physical appearance +- body size +- race +- ethnicity +- religion (or lack thereof) +- economic status +- geographic location +- technology choices +- sexual imagery +- deliberate intimidation +- violence and threats of violence +- stalking +- doxing +- inappropriate or unwelcome physical contact in public spaces +- unwelcomed sexual attention +- influencing unacceptable behavior +- any other dimension of diversity + +## Our Responsibilities + +Maintainers of the community and associated projects are not only subject to the +anti-harassment policy, but also responsible for executing the policy, +moderating related forums, and for taking appropriate and fair corrective action +in response to any instances of unacceptable behavior that breach the policy. + +Maintainers have the right to remove and reject comments, threads, commits, +code, documentation, pull requests, issues, and contributions not aligned with +this Code of Conduct. + +## Scope + +This Code of Conduct applies within all project and community spaces, as well as +in any public spaces where an individual representing the community is involved. +This covers + +- Interactions on the Github repository, including discussions, issues, pull + requests, commits, and wikis +- Interactions on any affiliated Discord, Slack, IRC, or related online + communities and forums like Discourse, etc. +- Any official project emails and social media posts +- Individuals representing the community at public events like meetups, talks, + and presentations + +## Enforcement + +All instances of abusive, harassing, or otherwise unacceptable behavior should +be reported by contacting the project and community maintainers at +[support@fission.codes][support-email]. All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. + +Maintainers of the community and associated projects are obligated to maintain +confidentiality with regard to the reporter of an incident. Further details of +specific enforcement policies may be posted separately. + +Anyone asked to stop abusive, harassing, or otherwise unacceptable behavior are +expected to comply immediately and accept the response decided on by the +maintainers of the community and associated projects. + +## Need help? + +If you are experiencing harassment, witness an incident or have concerns about +content please contact us at [support@fission.codes][support-email]. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant, v2.1][contributor-cov], +among other sources like [!!con’s Code of Conduct][!!con] and +[Mozilla’s Community Participation Guidelines][mozilla]. + +[!!con]: https://bangbangcon.com/conduct.html +[contributor-cov]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/ +[mozilla]: https://www.mozilla.org/en-US/about/governance/policies/participation/ +[support-email]: mailto:support@fission.codes diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..d91095a --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,134 @@ +# Contributing to Template + +Thank you for helping to improve the project! We are so happy that you are contributing! 💖 + +You can contribute to the project at any level. Whether you are new to web development or have been at it for ages doesn't matter. We can use your help! + +**No contribution is too small, and all contributions are valued.** + +This guide will help you to get started. It includes many details, but don't let that turn you away. Consider this a map to help you navigate the process, and please reach out to us with any questions and concerns in the our public [channel] . + +## Conduct + +Please review our [Code of Conduct] which describes the behavior we expect from all contributors. Please be kind, inclusive, and considerate when interacting with contributors and maintainers. + +## Contributing in issues + +You can contribute by [opening an issue][issue] to request a feature or report a bug. We also welcome comments on an issue, bug reproductions, and pull requests if you see how to address an issue. + +If you are still determining the details of a feature request, you can start with a [discussion][discussions] where we can informally discuss what you have on your mind. + +**Anyone can participate in any stage of contribution**. We urge you to +join in the discussion around bugs and comment on pull requests. + +### Asking for help + +If you have reviewed our [documentation][docs] and still have questions or are having problems, ask for help in the our public [channel] or [start a discussion][discussions]. + +### Submitting a bug report + +We provide a template to give you a starting point when submitting a bug report. Please fill this template in with all relevant information, but feel free to delete any sections that do not apply. + +The most important information is describing the problem and how it impacts you. We also invite you to propose a solution, which could be a description of expected behavior. + +We very much appreciate it if you could include a [short, self-contained, correct example][sscce] that demonstrates the issue. + +## Development + +If you have been assigned to fix an issue or develop a new feature, please follow these steps to get started: + +- Fork this repository. +- Install dependencies by running `pnpm install`. + - We use [pnpm](https://pnpm.io/) for package management. + - Make sure you have Node LTS installed in your system. +- Optionally run `npx simple-git-hooks` to install git hooks for linting and formatting. +- Implement your changes to files in the `src/` directory and corresponding test files in the `/test` directory. +- Git stage your required changes and commit (see below commit [guidelines](#how-should-i-write-my-commits)). +- Submit PR for review + +### Codespaces + +This repo has a dev container configuration to enable one click setup of a development environment using Codespaces. + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)][codespaces] + +## Pull requests + +Pull requests are how we make changes. + +Even tiny pull requests to fix typos or improve comments are welcome. Before submitting a significant PR, it is usually best to start by [opening an issue][issue] or [starting a discusssion][discussions]. Taking one of these steps increases the likelihood that your PR will be merged. + +All commits must be signed before a pull request will be accepted. See the GitHub [signing commits][signing] and [telling git about your signing key][telling-git] documentation. We recommend generating a new SSH key for signing if you are setting up signing for the first time. + +We squash and merge all PRs. Orderly, well-written commits will help us during review, but we don't require a pristine commit history. + +### Tests + +If your change alters existing code, please run the test suites: + +```sh +pnpm run lint +pnpm run test + +# node tests can use native watch mode +pnpm test:node -n watch + +# browser tests can enable watch +pnpm test:browser --watch +``` + +If you are adding a new feature, please add tests that prove the code works correctly and reference them when you submit the pull request. + +### Opening a pull request + +We provide a [pull request template][template] to give you a starting point when creating a pull request. Please fill this template in, but feel free to delete any sections that do not apply or that you are unsure about. + +### Discuss and update + +You will likely receive feedback or requests for changes to your pull request. Don't be discouraged! Pull request reviews help us all to collaborate and produce better code. Some reviewers may sign off immediately, and others may have more detailed comments and feedback. It's all part of the process of evaluating whether the changes are correct and necessary. + +**Once the PR is open, do not rebase the commits.** Add more commits to address feedback. We will squash and merge all contributions, and we may clean up the history recorded in the final commit. + +### Merging + +The primary goals for a pull request are to improve the codebase and for the contributor to succeed. Some pull requests may not be merged at the end of the day, but that does not indicate failure. If your pull request is not merged, please know that your efforts are appreciated and will have an impact on how we think about the codebase in the long run. + +## Release Process + +[Release Please](https://github.com/googleapis/release-please) automates CHANGELOG generation, the creation of GitHub releases, +and version bumps for our packages. Release Please does so by parsing your +git history, looking for [Conventional Commit messages](https://www.conventionalcommits.org/), +and creating release PRs. + +### What's a Release PR? + +Rather than continuously releasing what's landed to our default branch, release-please maintains Release PRs: + +These Release PRs are kept up-to-date as additional work is merged. When we're ready to tag a release, we simply merge the release PR. + +When the release PR is merged the release job is triggered to create a new tag, a new github release and run other package specific jobs. Only merge ONE release PR at a time and wait for CI to finish before merging another. + +Release PRs are created individually for each package in the mono repo. + +### How should I write my commits? + +Release Please assumes you are using [Conventional Commit messages](https://www.conventionalcommits.org/). + +The most important prefixes you should have in mind are: + +- `fix:` which represents bug fixes, and correlates to a [SemVer](https://semver.org/) + patch. +- `feat:` which represents a new feature, and correlates to a SemVer minor. +- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking change + (indicated by the `!`) and will result in a SemVer major. + +[channel]: https://discord.gg/zAQBDEq +[codespaces]: https://codespaces.new/fission-codes/stack +[discussions]: https://github.com/fission-codes/stack/discussions +[issue]: https://github.com/fission-codes/stack/issues +[docs]: https://fission-codes.github.io/stack/ +[sscce]: http://www.sscce.org/ +[signing]: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits +[telling-git]: https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key +[template]: PULL_REQUEST_TEMPLATE.md +[Code of Conduct]: CODE_OF_CONDUCT.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..e9d48fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '[bug]: ' +labels: bug, help wanted +assignees: 'hugomrdias' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..0dbec0d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '[feature]: ' +labels: enhancement, help wanted +assignees: 'hugomrdias' +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..311a193 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +# Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +## Link to issue + +Please add a link to any relevant issues/tickets + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change that fixes an issue) +- [ ] New feature (non-breaking change that adds functionality) +- [ ] Refactor (non-breaking change that updates existing functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update +- [ ] Comments have been added/updated diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..4157aeb --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Reporting a Vulnerability + +The project team welcomes security reports and is committed to providing prompt attention to security issues. + +Security issues **SHOULD** be reported privately via [email]. + +Security issues **SHOULD NOT** be reported via the public GitHub Issue tracker. + +## Security advisories + +The project team is committed to transparency in the security issue disclosure +process. Security advisories will be published through Github [Security Advisories][sec-advisories]. + +[email]: mailto:support@fission.codes +[sec-advisories]: https://github.com/fission-codes/stack/security/advisories diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..38e5450 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + open-pull-requests-limit: 5 + schedule: + interval: monthly + - package-ecosystem: npm + directory: / + open-pull-requests-limit: 5 + schedule: + interval: weekly diff --git a/.github/release-please-config.json b/.github/release-please-config.json new file mode 100644 index 0000000..dc51bba --- /dev/null +++ b/.github/release-please-config.json @@ -0,0 +1,7 @@ +{ + "separate-pull-requests": true, + "packages": { + "packages/package1": {}, + "packages/package2": {} + } +} diff --git a/.github/release-please-manifest.json b/.github/release-please-manifest.json new file mode 100644 index 0000000..7d06962 --- /dev/null +++ b/.github/release-please-manifest.json @@ -0,0 +1,4 @@ +{ + "packages/package1": "0.0.1", + "packages/package2": "0.0.2" +} diff --git a/.github/workflows/package1.yml b/.github/workflows/package1.yml new file mode 100644 index 0000000..00ea837 --- /dev/null +++ b/.github/workflows/package1.yml @@ -0,0 +1,33 @@ +name: Package1 +env: + CI: true + FORCE_COLOR: 1 +on: + push: + branches: [main] + paths: + - 'packages/package1/**' + - .github/workflows/package1.yml + - pnpm-lock.yaml + pull_request: + paths: + - 'packages/package1/**' + - .github/workflows/package1.yml + - pnpm-lock.yaml +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v2 + with: + version: latest + - uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: pnpm + - run: pnpm install + - run: pnpm run build + - run: pnpm -r --filter package1 run lint + - run: pnpm -r --filter package1 run test + - run: pnpm -r --filter package1 exec depcheck diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7491df1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,61 @@ +name: Release + +permissions: + contents: write + pull-requests: write + pages: write + id-token: write + +env: + CI: true + FORCE_COLOR: 1 +on: + push: + branches: [main] +jobs: + release: + runs-on: ubuntu-latest + outputs: + paths_released: ${{ steps.release.outputs.paths_released }} + steps: + - uses: google-github-actions/release-please-action@v3 + id: release + with: + # needs to be personal token so release PRs can run workflows + token: ${{ secrets.GH_TOKEN }} + command: manifest + config-file: .github/release-please-config.json + manifest-file: .github/release-please-manifest.json + default-branch: main + release-type: node + npm: + needs: release + if: | + contains(fromJson(needs.release.outputs.paths_released), 'packages/package1') || + contains(fromJson(needs.release.outputs.paths_released), 'packages/package2') + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v2 + with: + version: latest + - uses: actions/setup-node@v4 + with: + node-version: lts/* + registry-url: 'https://registry.npmjs.org' + cache: pnpm + - run: pnpm install + - run: pnpm run lint + - run: pnpm run build + - run: pnpm -r publish --access=public + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + docs: + needs: release + if: | + contains(fromJson(needs.release.outputs.paths_released), 'packages/package1') || + contains(fromJson(needs.release.outputs.paths_released), 'packages/package2') + uses: ./.github/workflows/reusable-docs.yml diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml new file mode 100644 index 0000000..9d2015e --- /dev/null +++ b/.github/workflows/reusable-docs.yml @@ -0,0 +1,40 @@ +name: Reusable Deploy Docs +on: + workflow_call: + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: pages + cancel-in-progress: false +permissions: + contents: read + pages: write + id-token: write + +jobs: + deploy-docs: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v2 + with: + version: latest + - uses: actions/setup-node@v4 + with: + node-version: lts/* + registry-url: 'https://registry.npmjs.org' + cache: pnpm + - run: pnpm install + - run: pnpm run lint + - run: pnpm run docs + - uses: actions/configure-pages@v3 + - uses: actions/upload-pages-artifact@v2 + with: + path: ./docs + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e17055 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Build tools and env +node_modules +dist +dist-ssr +*.local +dev-dist +kv-data +.env + +# Editor directories and files +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..f8ee548 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "github.vscode-pull-request-github", + "yoavbls.pretty-ts-errors" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4bb760e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,27 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true, + "source.organizeImports": false + }, + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "html", + "nunjucks", + "json", + "jsonc", + "json5", + "markdown", + "yaml", + "github-actions-workflow" + ], + "javascript.format.enable": false, + "javascript.preferences.importModuleSpecifierEnding": "js", + "typescript.format.enable": false, + "typescript.preferences.importModuleSpecifierEnding": "auto", + "typescript.enablePromptUseWorkspaceTsdk": true +} diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..18f9394 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2023 Filecoin Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..cafeb1d --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Fission + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c07f9d --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +__⚠️ Work in progress!__ + +A layer around the `wnfs` package that provides a `FileSystem` class, transactions, a root tree and some other essentials. + +## Features + +- A file system class that allows for an easy-to-use mutable API. +- A transaction system, rewinding the state if an error occurs. +- Creates a private forest automatically with a RSA modules using the Web Crypto API (supported on multiple platforms) + +## Packages + +- [package1](https://github.com/fission-codes/js-template/tree/master/packages/package1) - description +- [package2](https://github.com/fission-codes/js-template/tree/master/packages/package2) - description + +## Examples + +- [`demo`](https://github.com/fission-codes/js-template/tree/master/examples/demo) - description + +### Checkout examples + +You can use Codesandbox and start hacking right away. + +To clone it locally: + +```bash +npx tiged fission-codes/js-template/examples/demo demo +cd demo +pnpm install +pnpm dev +``` + +You can try any of the examples by replacing `demo` with the name of the example you want to try. + +## Contributing + +Read contributing guidelines [here](.github/CONTRIBUTING.md). + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/hd-template/examples) + +## License + +This project is licensed under either of + +- Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE-APACHE) or + [http://www.apache.org/licenses/LICENSE-2.0][apache]) +- MIT license ([LICENSE-MIT](./LICENSE-MIT) or + [http://opensource.org/licenses/MIT][mit]) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. + +[apache]: https://www.apache.org/licenses/LICENSE-2.0 +[mit]: http://opensource.org/licenses/MIT diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..f86c0ff Binary files /dev/null and b/assets/logo.png differ diff --git a/examples/demo/.codesandbox/tasks.json b/examples/demo/.codesandbox/tasks.json new file mode 100644 index 0000000..4b697fc --- /dev/null +++ b/examples/demo/.codesandbox/tasks.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://codesandbox.io/schemas/tasks.json", + "setupTasks": ["pnpm install"], + "tasks": { + "install-dependencies": { + "name": "Install Dependencies", + "command": "pnpm install", + "restartOn": { + "files": ["package.json", "pnpm-lock.yaml"], + "branch": true + } + }, + "dev": { + "name": "Run Dev Server", + "command": "pnpm dev", + "runAtStart": true + } + } +} diff --git a/examples/demo/README.md b/examples/demo/README.md new file mode 100644 index 0000000..e4a7d8d --- /dev/null +++ b/examples/demo/README.md @@ -0,0 +1,10 @@ +# demo + +## Run locally + +From this directory: + +```bash +pnpm install +pnpm dev +``` diff --git a/examples/demo/index.html b/examples/demo/index.html new file mode 100644 index 0000000..0ea846b --- /dev/null +++ b/examples/demo/index.html @@ -0,0 +1,15 @@ + + + + + + + + Demo + + + +

Hello

+ + + \ No newline at end of file diff --git a/examples/demo/package.json b/examples/demo/package.json new file mode 100644 index 0000000..85c2584 --- /dev/null +++ b/examples/demo/package.json @@ -0,0 +1,34 @@ +{ + "name": "demo", + "type": "module", + "version": "1.0.0", + "private": true, + "description": "", + "author": "Hugo Dias (hugodias.me)", + "license": "MIT", + "keywords": [], + "main": "src/main.jsx", + "scripts": { + "lint": "tsc --build && eslint . && prettier --check '**/*.{js,jsx,ts,tsx,yml,json,css}' --ignore-path ../../.gitignore", + "build": "vite build --force", + "dev": "vite --force", + "serve": "vite preview --port 3000" + }, + "dependencies": { + "package1": "*" + }, + "devDependencies": { + "@babel/core": "^7.23.3", + "@types/node": "^20.9.0", + "typescript": "5.2.2", + "vite": "^4.5.0" + }, + "eslintConfig": { + "extends": [ + "@fission-codes" + ], + "ignorePatterns": [ + "dist" + ] + } +} diff --git a/examples/demo/src/main.ts b/examples/demo/src/main.ts new file mode 100644 index 0000000..a9e1933 --- /dev/null +++ b/examples/demo/src/main.ts @@ -0,0 +1,4 @@ +import { randomBytes } from 'package1' + +// eslint-disable-next-line no-console +console.log(randomBytes(10)) diff --git a/examples/demo/tsconfig.json b/examples/demo/tsconfig.json new file mode 100644 index 0000000..04257e0 --- /dev/null +++ b/examples/demo/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "types": ["vite/client"], + "outDir": "dist", + "noEmit": true + }, + "include": ["src", "test"], + "exclude": ["node_modules", "dist", "out"] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a06e7ea --- /dev/null +++ b/package.json @@ -0,0 +1,50 @@ +{ + "name": "js-template", + "version": "0.0.0", + "private": true, + "workspaces": [ + "packages/*", + "examples/*" + ], + "packageManager": "pnpm@8.6.1", + "engines": { + "node": ">=18" + }, + "scripts": { + "format": "prettier --write '**/*.{js,ts,jsx,tsx,yml,json,css}' --ignore-path .gitignore", + "format:check": "prettier --check '**/*.{js,ts,jsx,tsx,yml,json,css}' --ignore-path .gitignore", + "clean": "rm -rf docs node_modules pnpm-lock.yaml packages/*/{pnpm-lock.yaml,coverage,.nyc_output,dist,node_modules} packages/*/{pnpm-lock.yaml,coverage,.nyc_output,dist,node_modules}", + "lint": "pnpm -r --if-present run lint", + "test": "pnpm -r --if-present run test", + "check": "pnpm -r --if-present run check", + "build": "pnpm -r --if-present run build", + "docs": "typedoc --out docs --plugin typedoc-plugin-missing-exports --plugin typedoc-plugin-zod" + }, + "devDependencies": { + "@fission-codes/eslint-config": "^0.0.3", + "depcheck": "^1.4.7", + "lint-staged": "^15.1.0", + "prettier": "3.1.0", + "simple-git-hooks": "^2.9.0", + "typedoc": "^0.25.3", + "typedoc-plugin-missing-exports": "^2.1.0", + "typedoc-plugin-zod": "^1.1.0", + "typescript": "5.2.2" + }, + "simple-git-hooks": { + "pre-commit": "npx lint-staged" + }, + "lint-staged": { + "*.{js,ts,jsx,tsx,yml,json,css}": "prettier --write", + "*": "eslint --fix" + }, + "prettier": "@fission-codes/eslint-config/prettier.config.js", + "eslintConfig": { + "extends": [ + "@fission-codes" + ], + "ignorePatterns": [ + "docs" + ] + } +} diff --git a/packages/nest/package.json b/packages/nest/package.json new file mode 100644 index 0000000..bc40313 --- /dev/null +++ b/packages/nest/package.json @@ -0,0 +1,107 @@ +{ + "name": "package1", + "type": "module", + "version": "0.0.1", + "description": "Example package description.", + "author": "Hugo Dias (hugodias.me)", + "license": "(Apache-2.0 AND MIT)", + "homepage": "https://github.com/fission-codes/js-template/tree/main/packages/package1", + "repository": { + "url": "fission-codes/js-template", + "directory": "packages/package1" + }, + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "default": "./src/index.js" + }, + "./crypto": { + "types": "./dist/src/crypto.d.ts", + "browser": "./src/crypto-browser.js", + "default": "./src/crypto.js" + } + }, + "main": "src/index.js", + "types": "dist/src/index.d.ts", + "browser": { + "crypto": false, + "./src/crypto.js": "./src/crypto-browser.js" + }, + "typesVersions": { + "*": { + "module1": [ + "dist/src/crypto" + ] + } + }, + "files": [ + "src", + "dist/src/*.d.ts", + "dist/src/*.d.ts.map" + ], + "scripts": { + "lint": "tsc --build && eslint . && prettier --check '**/*.{js,ts,yml,json}' --ignore-path ../../.gitignore", + "build": "tsc --build", + "test": "pnpm run test:node && pnpm run test:browser", + "test:node": "mocha 'test/**/!(*.browser).test.js'", + "test:browser": "playwright-test 'test/**/!(*.node).test.js'" + }, + "dependencies": { + "@ipld/dag-cbor": "^9.0.6", + "@ipld/dag-pb": "^4.0.6", + "compare-versions": "^6.1.0", + "interface-blockstore": "^5.2.7", + "ipfs-unixfs": "^11.1.0", + "ipfs-unixfs-exporter": "^13.2.2", + "ipfs-unixfs-importer": "^15.2.1", + "iso-base": "^2.0.1", + "it-all": "^3.0.4", + "multiformats": "^12.1.3", + "uint8arrays": "^4.0.9", + "wnfs": "^0.1.27" + }, + "devDependencies": { + "@types/assert": "^1.5.9", + "@types/mocha": "^10.0.4", + "@types/node": "^20.9.0", + "assert": "^2.1.0", + "mocha": "^10.2.0", + "playwright-test": "^12.6.0" + }, + "publishConfig": { + "provenance": true + }, + "eslintConfig": { + "extends": [ + "@fission-codes" + ], + "env": { + "mocha": true + }, + "ignorePatterns": [ + "dist" + ], + "rules": { + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "unicorn/no-array-reduce": [ + "off" + ] + } + }, + "depcheck": { + "specials": [ + "bin" + ], + "ignores": [ + "@types/*", + "assert" + ] + } +} diff --git a/packages/nest/readme.md b/packages/nest/readme.md new file mode 100644 index 0000000..f17148c --- /dev/null +++ b/packages/nest/readme.md @@ -0,0 +1,52 @@ +# Package 1 + +[![npm (scoped)](https://img.shields.io/npm/v/%40fission-codes/eslint-config)](https://www.npmjs.com/package/@fission-codes/eslint-config) +[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/fission-codes/stack/eslint-config.yml)](https://github.com/fission-codes/stack/actions/workflows/eslint-config.yml) +[![Built by FISSION](https://img.shields.io/badge/built_by-⌘_Fission-purple.svg)](https://fission.codes) +[![Discord](https://img.shields.io/discord/478735028319158273?&color=mediumslateblue)](https://discord.gg/zAQBDEq) +[![Discourse users]()](https://talk.fission.codes) + +Fission eslint, ts and prettier config. + +## Installation + +```bash +pnpm install package1 +``` + +## Usage + +```js +import { module } from 'package1' +``` + +## Docs + +Check + +## Contributing + +Read contributing guidelines [here](../../.github/CONTRIBUTING.md). + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/hugomrdias/hd-template) + +## License + +This project is licensed under either of + +- Apache License, Version 2.0, ([LICENSE-APACHE](../../LICENSE-APACHE) or + [http://www.apache.org/licenses/LICENSE-2.0][apache]) +- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or + [http://opensource.org/licenses/MIT][mit]) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. + +[apache]: https://www.apache.org/licenses/LICENSE-2.0 +[mit]: http://opensource.org/licenses/MIT diff --git a/packages/nest/src/_unix.ts b/packages/nest/src/_unix.ts new file mode 100644 index 0000000..2e8c7a1 --- /dev/null +++ b/packages/nest/src/_unix.ts @@ -0,0 +1,198 @@ +import type { CID } from 'multiformats' +import type { PBLink, PBNode } from '@ipld/dag-pb' + +import * as DagPB from '@ipld/dag-pb' +import * as Uint8arrays from 'uint8arrays' +import { UnixFS } from 'ipfs-unixfs' +import { exporter } from 'ipfs-unixfs-exporter' +import { importBytes as importer } from 'ipfs-unixfs-importer' +import all from 'it-all' + +import type { BlockStore } from './store.js' +import * as Path from './path/index.js' + +/** + * Create a UnixFS directory. + */ +export function createDirectory( + currentTime: Date, + links: PBLink[] = [] +): PBNode { + const unixDir = new UnixFS({ + type: 'directory', + mtime: { secs: BigInt(Math.round(currentTime.getTime() / 1000)) }, + }) + + return DagPB.createNode(unixDir.marshal(), links) +} + +/** + * Get the bytes of a UnixFS file. + */ +export async function exportFile( + cid: CID, + store: BlockStore, + options?: { offset: number; length: number } +): Promise { + const offset = options?.offset + const length = options?.length + + const fsEntry = await exporter(cid, store) + + if (fsEntry.type === 'file' || fsEntry.type === 'raw') { + return Uint8arrays.concat(await all(fsEntry.content({ offset, length }))) + } else { + throw new Error( + `Expected a file, found a '${fsEntry.type}' (CID: ${cid.toString()})` + ) + } +} + +/** + * Get the CID for some file bytes. + */ +export async function importFile( + bytes: Uint8Array, + store: BlockStore +): Promise { + const { cid } = await importer(bytes, store) + return cid +} + +/** + * Insert a node into UnixFS tree, creating directories when needed + * and overwriting content. + */ +export async function insertNodeIntoTree( + node: PBNode, + path: Path.Distinctive, + store: BlockStore, + fileCID?: CID +): Promise { + const pathKind = Path.kind(path) + const pathParts = Path.unwrap(path) + const name = pathParts[0] + const link = node.Links.find((l) => l.Name === name) + + // Directory + // --------- + if (Path.length(path) > 1) { + let dirNode: PBNode + + if (link?.Hash) { + dirNode = await load(link.Hash, depot) + } else { + dirNode = createDirectory(new Date()) + } + + const newDirNode = await insertNodeIntoTree( + dirNode, + Path.fromKind(pathKind, ...pathParts.slice(1)), + depot, + fileCID + ) + + const dirCID = await store(newDirNode, depot) + const links = link + ? replaceLinkHash(node.Links, name, dirCID) + : addLink(node.Links, name, dirCID) + + return { ...node, Links: links } + } + + // Last part of path + // ----------------- + // Directory + if (pathKind === 'directory') { + if (link) return node + + const dirNode = createDirectory(new Date()) + const dirCID = await store(dirNode, depot) + + const links = addLink(node.Links, name, dirCID) + return { ...node, Links: links } + } + + // File + if (!fileCID) throw new Error('Need a file CID when adding a UnixFS file') + + const links = link + ? replaceLinkHash(node.Links, name, fileCID) + : addLink(node.Links, name, fileCID) + + return { ...node, Links: links } +} + +/** + * Load a UnixFS node. + */ +export async function load(cid: CID, store: BlockStore): Promise { + return DagPB.decode(await depot.getBlock(cid)) +} + +/** + * Remove a node from a UnixFS tree. + */ +export async function removeNodeFromTree( + node: PBNode, + path: Path.Distinctive, + store: BlockStore +): Promise { + const pathKind = Path.kind(path) + const pathParts = Path.unwrap(path) + const name = pathParts[0] + const link = node.Links.find((l) => l.Name === name) + + // Directory + // --------- + if (Path.length(path) > 1) { + let dirNode: PBNode + + if (link?.Hash) { + dirNode = await load(link.Hash, depot) + } else { + return node + } + + const newDirNode = await removeNodeFromTree( + dirNode, + Path.fromKind(pathKind, ...pathParts.slice(1)), + depot + ) + + const dirCID = await store(newDirNode, depot) + const links = link + ? replaceLinkHash(node.Links, name, dirCID) + : addLink(node.Links, name, dirCID) + + return { ...node, Links: links } + } + + // Last part of path + // ----------------- + if (!link) return node + return { ...node, Links: node.Links.filter((l) => l.Name !== name) } +} + +/** + * Store a UnixFS node. + */ +export async function store(node: PBNode, store: BlockStore): Promise { + return depot.putBlock(DagPB.encode(node), DagPB.code) +} + +// ㊙️ + +function addLink(links: PBLink[], name: string, hash: CID): PBLink[] { + return [...links, DagPB.createLink(name, 0, hash)].sort(linkSorter) +} + +function replaceLinkHash(links: PBLink[], name: string, hash: CID): PBLink[] { + return links.map((l) => (l.Name === name ? { ...l, Hash: hash } : l)) +} + +function linkSorter(a: PBLink, b: PBLink): number { + if ((a.Name ?? '') > (b.Name ?? '')) return 1 + if ((a.Name ?? '') < (b.Name ?? '')) return -1 + return 0 +} diff --git a/packages/nest/src/class.ts b/packages/nest/src/class.ts new file mode 100644 index 0000000..2b594e0 --- /dev/null +++ b/packages/nest/src/class.ts @@ -0,0 +1,798 @@ +import debounce from 'debounce-promise' +import { CID } from 'multiformats/cid' +import { + AccessKey, + BlockStore, + PrivateDirectory, + PrivateFile, + PrivateNode, + PublicDirectory, + PublicFile, +} from 'wnfs' + +import type { Repo as CIDLog } from '../repositories/cid-log.js' + +import * as Events from '../events/fileSystem.js' +import * as Path from '../path/index.js' +import * as Rng from './rng.js' +import * as RootTree from './root-tree.js' +import * as Store from './store.js' + +import { EventEmitter, createEmitter } from '../events/emitter.js' +import { EventListener } from '../events/listen.js' +import { Inventory } from '../inventory.js' +import { + Partition, + Partitioned, + PartitionedNonEmpty, + Private, + Public, +} from '../path/index.js' +import { Ticket } from '../ticket/types.js' +import { searchLatest } from './common.js' +import { findPrivateNode, partition as determinePartition } from './mounts.js' +import { TransactionContext } from './transaction.js' +import { + AnySupportedDataType, + DataForType, + DataRootChange, + DataRootUpdater, + DataType, + Dependencies, + DirectoryItem, + DirectoryItemWithKind, + MutationOptions, + MutationResult, + PrivateMutationResult, + PublicMutationResult, + PublishingStatus, + TransactionResult, +} from './types.js' +import { MountedPrivateNode, MountedPrivateNodes } from './types/internal.js' + +/** @internal */ +export type FileSystemOptions = { + cidLog: CIDLog + dependencies: Dependencies + did: string + inventory: Inventory + settleTimeBeforePublish?: number + updateDataRoot?: DataRootUpdater +} + +/** @group File System */ +export class FileSystem { + #blockStore: BlockStore + #eventEmitter: EventEmitter + #inventory: Inventory + #rootTree: RootTree.RootTree + #settleTimeBeforePublish: number + + #privateNodes: MountedPrivateNodes = {} + #rng: Rng.Rng + + did: string + + /** @hidden */ + constructor( + blockStore: BlockStore, + did: string, + inventory: Inventory, + rootTree: RootTree.RootTree, + settleTimeBeforePublish: number + ) { + this.#blockStore = blockStore + this.#inventory = inventory + this.#settleTimeBeforePublish = settleTimeBeforePublish + this.#rootTree = rootTree + + this.#eventEmitter = createEmitter() + this.#rng = Rng.makeRngInterface() + + this.did = did + } + + // INITIALISATION + // -------------- + + /** + * Creates a file system with an empty public tree & an empty private tree at the root. + * @internal + */ + static async empty(opts: FileSystemOptions): Promise { + const { blockStore, did, settleTimeBeforePublish } = opts + + const rootTree = await RootTree.empty() + + return new FileSystem( + blockStore, + did, + rootTree, + settleTimeBeforePublish || 2500 + ) + } + + /** + * Loads an existing file system from a CID. + * @internal + */ + static async fromCID( + cid: CID, + opts: FileSystemOptions + ): Promise { + const { blockStore, did, settleTimeBeforePublish } = opts + + const rootTree = await RootTree.fromCID({ + blockStore, + cid, + }) + + return new FileSystem( + blockStore, + did, + rootTree, + settleTimeBeforePublish || 2500 + ) + } + + // EVENTS + // ------ + + /** + * {@inheritDoc events.EmitterClass.on} + * @group Events + */ + on = ( + eventName: Name, + listener: EventListener + ) => this.#eventEmitter.on(eventName, listener) + + /** + * {@inheritDoc events.EmitterClass.onAny} + * @group Events + */ + onAny = ( + listener: ( + eventName: keyof Events.FileSystem, + eventData: Events.FileSystem[keyof Events.FileSystem] + ) => void | Promise + ) => this.#eventEmitter.onAny(listener) + + /** + * {@inheritDoc events.EmitterClass.off} + * @group Events + */ + off = ( + eventName: Name, + listener: EventListener + ) => this.#eventEmitter.off(eventName, listener) + + /** + * {@inheritDoc events.EmitterClass.offAny} + * @group Events + */ + offAny = ( + listener: ( + eventName: keyof Events.FileSystem, + eventData: Events.FileSystem[keyof Events.FileSystem] + ) => void | Promise + ) => this.#eventEmitter.offAny(listener) + + /** + * {@inheritDoc events.EmitterClass.once} + * @group Events + */ + once = (eventName: Name) => + this.#eventEmitter.once(eventName) + + /** + * {@inheritDoc events.EmitterClass.anyEvent} + * @group Events + */ + anyEvent = () => this.#eventEmitter.anyEvent() + + /** + * {@inheritDoc events.EmitterClass.events} + * @group Events + */ + events = (eventName: Name) => + this.#eventEmitter.events(eventName) + + // MOUNTS + // ------ + + /** + * Mount a private node onto the file system. + * @group Mounting + */ + async mountPrivateNode(node: { + path: Path.Distinctive + capsuleKey?: Uint8Array + }): Promise<{ + path: Path.Distinctive + capsuleKey: Uint8Array + }> { + const mounts = await this.mountPrivateNodes([node]) + return mounts[0] + } + + /** + * Mount private nodes onto the file system. + * @group Mounting + */ + async mountPrivateNodes( + nodes: { + path: Path.Distinctive + capsuleKey?: Uint8Array + }[] + ): Promise< + { + path: Path.Distinctive + capsuleKey: Uint8Array + }[] + > { + const newNodes = await Promise.all( + nodes.map( + async ({ path, capsuleKey }): Promise<[string, MountedPrivateNode]> => { + let privateNode: PrivateNode + + if (capsuleKey) { + const accessKey = AccessKey.fromBytes(capsuleKey) + privateNode = await PrivateNode.load( + accessKey, + this.#rootTree.privateForest, + this.#blockStore + ) + } else { + privateNode = Path.isFile(path) + ? new PrivateFile( + this.#rootTree.privateForest.emptyName(), + new Date(), + this.#rng + ).asNode() + : new PrivateDirectory( + this.#rootTree.privateForest.emptyName(), + new Date(), + this.#rng + ).asNode() + } + + return [ + // Use absolute paths so that you can retrieve the root: privateNodes["/"] + Path.toPosix(path, { absolute: true }), + { node: privateNode, path }, + ] + } + ) + ) + + this.#privateNodes = { + ...this.#privateNodes, + ...Object.fromEntries(newNodes), + } + + return Promise.all( + newNodes.map(async ([_, n]: [string, MountedPrivateNode]) => { + const storeResult = await n.node.store( + this.#rootTree.privateForest, + this.#blockStore, + this.#rng + ) + const [accessKey, privateForest] = storeResult + + this.#rootTree = { ...this.#rootTree, privateForest } + + return { + path: n.path, + capsuleKey: accessKey.toBytes(), + } + }) + ) + } + + /** + * Unmount a private node from the file system. + * @group Mounting + */ + unmountPrivateNode(path: Path.Distinctive): void { + delete this.#privateNodes[Path.toPosix(path)] + } + + // QUERY + // ----- + + /** @group Querying */ + async contentCID(path: Path.File>): Promise { + return this.#transactionContext().contentCID(path) + } + + /** @group Querying */ + async capsuleCID( + path: Path.Distinctive> + ): Promise { + return this.#transactionContext().capsuleCID(path) + } + + /** @group Querying */ + async capsuleKey( + path: Path.Distinctive> + ): Promise { + return this.#transactionContext().capsuleKey(path) + } + + /** @group Querying */ + async exists( + path: Path.Distinctive> + ): Promise { + return this.#transactionContext().exists(path) + } + + /** @group Querying */ + async listDirectory( + path: Path.Directory>, + listOptions: { withItemKind: true } + ): Promise + async listDirectory( + path: Path.Directory>, + listOptions: { withItemKind: false } + ): Promise + async listDirectory( + path: Path.Directory> + ): Promise + async listDirectory( + path: Path.Directory>, + listOptions: { withItemKind: boolean } = { withItemKind: false } + ): Promise { + return this.#transactionContext().listDirectory(path, listOptions) + } + + /** @group Querying */ + ls = this.listDirectory + + /** @group Querying */ + async read( + path: + | Path.File> + | { contentCID: CID } + | { capsuleCID: CID } + | { + capsuleKey: Uint8Array + }, + dataType: D, + options?: { offset: number; length: number } + ): Promise> + async read( + path: + | Path.File> + | { contentCID: CID } + | { capsuleCID: CID } + | { + capsuleKey: Uint8Array + }, + dataType: DataType, + options?: { offset: number; length: number } + ): Promise> { + return this.#transactionContext().read(path, dataType, options) + } + + /** + * Create a permalink to some public file system content. + * @group Querying + */ + permalink( + dataRoot: CID, + path: Path.Distinctive> + ): string { + if (this.#dependencies.depot.permalink) { + return this.#dependencies.depot.permalink(dataRoot, path) + } else { + throw new Error('Not implemented in the used depot component') + } + } + + // MUTATIONS + // --------- + + /** @group Mutating */ + async copy( + from: Path.Distinctive>, + to: Path.File> | Path.Directory>, + mutationOptions?: MutationOptions + ): Promise> + async copy( + from: Path.Distinctive>, + to: + | Path.File> + | Path.Directory>, + mutationOptions: MutationOptions = {} + ): Promise | null> { + return this.#infusedTransaction( + (t) => t.copy(from, to), + to, + mutationOptions + ) + } + + /** @group Mutating */ + cp = this.copy + + /** @group Mutating */ + async createDirectory

( + path: Path.Directory>, + mutationOptions?: MutationOptions + ): Promise< + MutationResult

& { path: Path.Directory> } + > + async createDirectory( + path: Path.Directory>, + mutationOptions: MutationOptions = {} + ): Promise< + MutationResult & { + path: Path.Directory> + } + > { + let finalPath = path + + const mutationResult = await this.#infusedTransaction( + async (t) => { + const creationResult = await t.createDirectory(path) + finalPath = creationResult.path + }, + path, + mutationOptions + ) + + return { + ...mutationResult, + path: finalPath, + } + } + + /** @group Mutating */ + async createFile

( + path: Path.File>, + dataType: DataType, + data: DataForType, + mutationOptions?: MutationOptions + ): Promise< + MutationResult

& { path: Path.File> } + > + async createFile( + path: Path.File>, + dataType: DataType, + data: DataForType, + mutationOptions: MutationOptions = {} + ): Promise< + MutationResult & { + path: Path.File> + } + > { + let finalPath = path + + const mutationResult = await this.#infusedTransaction( + async (t) => { + const creationResult = await t.createFile(path, dataType, data) + finalPath = creationResult.path + }, + path, + mutationOptions + ) + + return { + ...mutationResult, + path: finalPath, + } + } + + /** @group Mutating */ + async ensureDirectory

( + path: Path.Directory>, + mutationOptions?: MutationOptions + ): Promise> + async ensureDirectory( + path: Path.Directory>, + mutationOptions: MutationOptions = {} + ): Promise> { + return this.#infusedTransaction( + (t) => t.ensureDirectory(path), + path, + mutationOptions + ) + } + + /** @group Mutating */ + mkdir = this.ensureDirectory + + /** @group Mutating */ + async move( + from: Path.Distinctive>, + to: Path.File> | Path.Directory>, + mutationOptions?: MutationOptions + ): Promise> + async move( + from: Path.Distinctive>, + to: + | Path.File> + | Path.Directory>, + mutationOptions: MutationOptions = {} + ): Promise> { + return this.#infusedTransaction( + (t) => t.move(from, to), + to, + mutationOptions + ) + } + + /** @group Mutating */ + mv = this.move + + /** @group Mutating */ + async remove( + path: Path.Distinctive>, + mutationOptions: MutationOptions = {} + ): Promise { + const transactionResult = await this.transaction( + (t) => t.remove(path), + mutationOptions + ) + + return { + dataRoot: transactionResult.dataRoot, + publishingStatus: transactionResult.publishingStatus, + } + } + + /** @group Mutating */ + rm = this.remove + + /** @group Mutating */ + async rename

( + path: Path.Distinctive>, + newName: string, + mutationOptions?: MutationOptions + ): Promise> + async rename( + path: Path.Distinctive>, + newName: string, + mutationOptions: MutationOptions = {} + ): Promise> { + return this.#infusedTransaction( + (t) => t.rename(path, newName), + Path.replaceTerminus(path, newName), + mutationOptions + ) + } + + /** @group Mutating */ + async write

( + path: Path.File>, + dataType: DataType, + data: DataForType, + mutationOptions?: MutationOptions + ): Promise> + async write( + path: Path.File>, + dataType: DataType, + data: DataForType, + mutationOptions: MutationOptions = {} + ): Promise> { + return this.#infusedTransaction( + (t) => t.write(path, dataType, data), + path, + mutationOptions + ) + } + + // TRANSACTIONS + // ------------ + + /** @group Transacting */ + async transaction( + handler: (t: TransactionContext) => Promise, + mutationOptions: MutationOptions = {} + ): Promise { + const context = this.#transactionContext() + + // Execute handler + await handler(context) + + // Commit transaction + const { changes, privateNodes, proofs, rootTree } = + await TransactionContext.commit(context) + + this.#privateNodes = privateNodes + this.#rootTree = rootTree + + // Determine data root + const dataRoot = await this.calculateDataRoot() + + // Emit events + changes.forEach(async (change) => { + await this.#eventEmitter.emit('local-change', { + dataRoot, + ...change, + }) + }) + + // Publish + const signal = + mutationOptions.skipPublish === true + ? Promise.resolve(FileSystem.#statusNotPublishing) + : this.#publish(dataRoot, proofs) + + // Fin + return { + changes, + dataRoot, + publishingStatus: signal, + } + } + + // 🛠️ + + /** @group Misc */ + calculateDataRoot(): Promise { + return RootTree.store({ + blockStore: this.#blockStore, + depot: this.#dependencies.depot, + rootTree: this.#rootTree, + }) + } + + // ㊙️ ▒▒ MUTATIONS + + async #infusedTransaction( + handler: (t: TransactionContext) => Promise, + path: Path.Distinctive>, + mutationOptions?: MutationOptions + ): Promise + async #infusedTransaction( + handler: (t: TransactionContext) => Promise, + path: Path.Distinctive>, + mutationOptions?: MutationOptions + ): Promise + async #infusedTransaction( + handler: (t: TransactionContext) => Promise, + path: Path.Distinctive>, + mutationOptions?: MutationOptions + ): Promise> + async #infusedTransaction( + handler: (t: TransactionContext) => Promise, + path: Path.Distinctive>, + mutationOptions: MutationOptions = {} + ): Promise> { + const transactionResult = await this.transaction(handler, mutationOptions) + const partition = determinePartition(path) + + switch (partition.name) { + case 'public': { + const node = + partition.segments.length === 0 + ? this.#rootTree.publicRoot.asNode() + : await this.#rootTree.publicRoot.getNode( + partition.segments, + this.#blockStore + ) + if (!node) + throw new Error('Failed to find needed public node for infusion') + + const fileOrDir: PublicFile | PublicDirectory = node.isFile() + ? node.asFile() + : node.asDir() + + const capsuleCID = await fileOrDir + .store(this.#blockStore) + .then((a) => CID.decode(a)) + const contentCID = node.isFile() + ? CID.decode(node.asFile().contentCid()) + : capsuleCID + + return { + dataRoot: transactionResult.dataRoot, + publishingStatus: transactionResult.publishingStatus, + capsuleCID, + contentCID, + } + } + + case 'private': { + const priv = findPrivateNode(partition.path, this.#privateNodes) + const accessKey = priv.node.isFile() + ? await priv.node + .asFile() + .store(this.#rootTree.privateForest, this.#blockStore, this.#rng) + : await (priv.remainder.length === 0 + ? Promise.resolve(priv.node) + : priv.node + .asDir() + .getNode( + priv.remainder, + searchLatest(), + this.#rootTree.privateForest, + this.#blockStore + ) + ) + .then((node) => { + if (!node) + throw new Error( + 'Failed to find needed private node for infusion' + ) + return node.store( + this.#rootTree.privateForest, + this.#blockStore + ) + }) + .then(([key]) => key) + + return { + dataRoot: transactionResult.dataRoot, + publishingStatus: transactionResult.publishingStatus, + capsuleKey: accessKey.toBytes(), + } + } + } + } + + #transactionContext(): TransactionContext { + return new TransactionContext( + this.#blockStore, + { ...this.#privateNodes }, + this.#rng, + { ...this.#rootTree } + ) + } + + // ㊙️ ▒▒ PUBLISHING + + static readonly #statusNotPublishing: PublishingStatus = { + persisted: false, + reason: 'DISABLED_BY_OPTIONS', + } + + readonly #debouncedDataRootUpdate = debounce( + async ( + args: Array<[dataRoot: CID, proofs: Ticket[]]> + ): Promise => { + const [dataRoot, proofs] = args[args.length - 1] + + await this.#dependencies.depot.flush(dataRoot, proofs) + + let status: PublishingStatus + + if (!this.#updateDataRoot) { + status = { + persisted: false, + reason: 'DATA_ROOT_UPDATER_NOT_CONFIGURED', + } + + return args.map((_) => status) + } + + const rootUpdate = await this.#updateDataRoot(dataRoot, proofs) + + if (rootUpdate.updated) { + await this.#eventEmitter.emit('publish', { dataRoot, proofs }) + status = { persisted: true } + } else { + status = { persisted: false, reason: rootUpdate.reason } + } + + return args.map((_) => status) + }, + (() => this.#settleTimeBeforePublish) as any, + { + accumulate: true, + leading: false, + } + ) + + /** + * Updates the user's data root if it can find a UCAN that allows them to do so. + */ + async #publish(dataRoot: CID, proofs: Ticket[]): Promise { + const debounceResult = await this.#debouncedDataRootUpdate(dataRoot, proofs) + + // The type of `debounceResult` is not correct, issue with `@types/debounce-promise` + return debounceResult as unknown as PublishingStatus + } +} diff --git a/packages/nest/src/codecs.ts b/packages/nest/src/codecs.ts new file mode 100644 index 0000000..717ff46 --- /dev/null +++ b/packages/nest/src/codecs.ts @@ -0,0 +1,86 @@ +import * as Uint8arrays from 'uint8arrays' + +import * as DagCBOR from '@ipld/dag-cbor' +import * as DagPB from '@ipld/dag-pb' +import * as Raw from 'multiformats/codecs/raw' + +import type { CID } from 'multiformats/cid' +import type { BlockCodec } from 'multiformats/codecs/interface' + +// 🧩 + +export type CodecIdentifier = + | typeof DagCBOR.code + | typeof DagCBOR.name + | typeof DagPB.code + | typeof DagPB.name + | typeof Raw.code + | typeof Raw.name + +// 🏔️ + +export const BY_NAME: Record> = { + [DagPB.name]: DagPB, + [DagCBOR.name]: DagCBOR, + [Raw.name]: Raw, +} + +export const BY_CODE: Record> = { + [DagPB.code]: DagPB, + [DagCBOR.code]: DagCBOR, + [Raw.code]: Raw, +} + +export function getByCode(code: number): BlockCodec { + const codec = BY_CODE[code] + if (codec === undefined) { + throw new Error( + `No codec was registered for the code: ${numberHex( + code + )}. Is it part of the multicodec table (https://github.com/multiformats/multicodec/blob/master/table.csv)?` + ) + } + return codec +} + +export function getByName(name: string): BlockCodec { + const codec = BY_NAME[name] + if (codec === undefined) + throw new Error(`No codec was registered for the name: ${name}`) + return codec +} + +export function getByIdentifier(id: CodecIdentifier): BlockCodec { + if (typeof id === 'string') return getByName(id) + return getByCode(id) +} + +// 🛠️ + +export function expect(codecId: CodecIdentifier, cid: CID): void { + const codec = getByIdentifier(codecId) + + if (cid.code !== codec.code) { + const cidCodec = getByCode(cid.code) + throw new Error( + `Expected a ${codec.name} CID, found a ${cidCodec.name} CID instead.` + ) + } +} + +export function isIdentifier( + codeOrName: number | string +): codeOrName is CodecIdentifier { + return typeof codeOrName === 'string' + ? BY_NAME[codeOrName] !== undefined + : BY_CODE[codeOrName] !== undefined +} + +export function numberHex(num: number): string { + const codeUint8Array = new Uint8Array(4) + const numberByteView = new DataView(codeUint8Array.buffer) + numberByteView.setUint32(0, num) + const hex = Uint8arrays.toString(codeUint8Array, 'hex') + const trimmed = hex.replace(/^(00)*/, '') + return `0x${trimmed}` +} diff --git a/packages/nest/src/common.ts b/packages/nest/src/common.ts new file mode 100644 index 0000000..c2bb21a --- /dev/null +++ b/packages/nest/src/common.ts @@ -0,0 +1,40 @@ +import * as Path from './path/index.js' + +export function addOrIncreaseNameNumber( + path: Path.Directory> +): Path.Directory> +export function addOrIncreaseNameNumber( + path: Path.File> +): Path.File> +export function addOrIncreaseNameNumber( + path: Path.Distinctive> +): Path.Distinctive> { + const regex = Path.isFile(path) ? /( \((\d+)\))?(\.[^$]+)?$/ : /( \((\d+)\))$/ + const terminus = Path.terminus(path) + const suffixMatches = terminus.match(regex) + + return Path.replaceTerminus( + path, + suffixMatches === null + ? `${terminus} (1)` + : terminus.replace( + regex, + ` (${Number.parseInt(suffixMatches[2] ?? '0', 10) + 1})${ + suffixMatches[3] ?? '' + }` + ) + ) +} + +export function pathSegmentsWithoutPartition( + path: Path.Distinctive> +): Path.Segments { + return Path.unwrap(Path.removePartition(path)) +} + +/** + * Which `searchLatest` value to use for the private file system actions. + */ +export function searchLatest(): boolean { + return true +} diff --git a/packages/nest/src/data.ts b/packages/nest/src/data.ts new file mode 100644 index 0000000..448fd77 --- /dev/null +++ b/packages/nest/src/data.ts @@ -0,0 +1,62 @@ +import type { AnySupportedDataType, DataType } from './types.js' + +/** + * Convert Uint8Array to `Data`. + */ +export function dataFromBytes(dataType: 'bytes', bytes: Uint8Array): Uint8Array +export function dataFromBytes( + dataType: 'json', + bytes: Uint8Array +): Record +export function dataFromBytes(dataType: 'utf8', bytes: Uint8Array): string +export function dataFromBytes( + dataType: DataType, + bytes: Uint8Array +): AnySupportedDataType +export function dataFromBytes( + dataType: DataType, + bytes: Uint8Array +): AnySupportedDataType { + switch (dataType) { + case 'bytes': { + return bytes + } + + case 'json': { + return JSON.parse(new TextDecoder().decode(bytes)) + } + + case 'utf8': { + return new TextDecoder().decode(bytes) + } + } +} + +/** + * Convert `Data` to Uint8Array. + */ +export function dataToBytes(dataType: 'bytes', data: Uint8Array): Uint8Array +export function dataToBytes( + dataType: 'json', + data: Record +): Uint8Array +export function dataToBytes(dataType: 'utf8', data: string): Uint8Array +export function dataToBytes( + dataType: DataType, + data: AnySupportedDataType +): Uint8Array +export function dataToBytes(dataType: DataType, data: any): Uint8Array { + switch (dataType) { + case 'bytes': { + return data + } + + case 'json': { + return new TextEncoder().encode(JSON.stringify(data)) + } + + case 'utf8': { + return new TextEncoder().encode(data) + } + } +} diff --git a/packages/nest/src/data/sample.ts b/packages/nest/src/data/sample.ts new file mode 100644 index 0000000..eeb2867 --- /dev/null +++ b/packages/nest/src/data/sample.ts @@ -0,0 +1,20 @@ +import * as Path from '../path/index.js' +import type { FileSystem } from '../class.js' + +/** + * Adds some sample to the file system. + */ +export async function addSampleData(fs: FileSystem): Promise { + await fs.mkdir(Path.directory('private', 'Apps')) + await fs.mkdir(Path.directory('private', 'Audio')) + await fs.mkdir(Path.directory('private', 'Documents')) + await fs.mkdir(Path.directory('private', 'Photos')) + await fs.mkdir(Path.directory('private', 'Video')) + + // Files + await fs.write( + Path.file('private', 'Welcome.txt'), + 'utf8', + 'Welcome to your personal transportable encrypted file system 👋' + ) +} diff --git a/packages/nest/src/errors.ts b/packages/nest/src/errors.ts new file mode 100644 index 0000000..c0735a1 --- /dev/null +++ b/packages/nest/src/errors.ts @@ -0,0 +1,20 @@ +import * as Path from './path/index.js' + +export function throwNoAccess( + path: Path.DistinctivePath, + accessType?: string +): never { + throw new Error( + `Expected to have ${ + typeof accessType === 'string' ? accessType + ' ' : '' + }access to the path '${Path.toPosix(path)}'` + ) +} + +export function throwInvalidPartition( + path: Path.Distinctive +): never { + throw new Error( + `Expected either a public or private path, got '${Path.toPosix(path)}'` + ) +} diff --git a/packages/nest/src/mounts.ts b/packages/nest/src/mounts.ts new file mode 100644 index 0000000..438560e --- /dev/null +++ b/packages/nest/src/mounts.ts @@ -0,0 +1,80 @@ +import * as Path from './path/index.js' + +import type { + Partition, + Partitioned, + PartitionedNonEmpty, +} from './path/index.js' +import type { PartitionDiscovery, PartitionDiscoveryNonEmpty } from './types.js' +import type { + MountedPrivateNode, + MountedPrivateNodes, + PrivateNodeQueryResult, +} from './types/internal.js' + +import { throwInvalidPartition, throwNoAccess } from './errors.js' + +/** + * Find a private node based on a given path. + * Throws if it cannot find a node. + * + * This looks in the `privateNodes` record using the POSIX path as the key. + * A directory will end with a forward slash and a file will not. + * + * Starts from the path `/` and works up to given path, + * which could be a file or directory path. + */ +export function findPrivateNode( + path: Path.Distinctive>, + privateNodes: MountedPrivateNodes +): PrivateNodeQueryResult { + const pathKind = Path.kind(path) + const pathWithoutPartition = Path.removePartition(path) + const pathSegments = Path.unwrap(pathWithoutPartition) + + for (let i = 0; i <= pathSegments.length; i++) { + const path = Path.fromKind( + i === pathSegments.length ? pathKind : Path.Kind.Directory, + ...pathSegments.slice(0, i) + ) + + const result: MountedPrivateNode | undefined = + privateNodes[Path.toPosix(path, { absolute: true })] + + if (result !== undefined) { + return { + ...result, + remainder: pathSegments.slice(i), + } + } + } + + throwNoAccess(path) +} + +export function partition

( + path: Path.Distinctive> +): PartitionDiscoveryNonEmpty

+export function partition

( + path: Path.Distinctive> +): PartitionDiscovery

+export function partition(path: Path.Distinctive>): { + name: 'public' | 'private' + path: Path.Distinctive> + segments: Path.Segments +} { + const unwrapped = Path.unwrap(path) + const rest = unwrapped.slice(1) + + switch (unwrapped[0]) { + case 'public': { + return { name: 'public', path: path, segments: rest } + } + case 'private': { + return { name: 'private', path: path, segments: rest } + } + default: { + throwInvalidPartition(path) + } + } +} diff --git a/packages/nest/src/mutations.ts b/packages/nest/src/mutations.ts new file mode 100644 index 0000000..355691d --- /dev/null +++ b/packages/nest/src/mutations.ts @@ -0,0 +1,131 @@ +import type { BlockStore } from 'wnfs' + +import type * as Path from './path/index.js' + +// TODO: import * as Unix from "./unix.js" + +import { searchLatest } from './common.js' +import type { Rng } from './rng.js' +import type { RootTree } from './root-tree.js' +import type { MutationType } from './types.js' +import type { + MountedPrivateNodes, + PrivateNodeQueryResult, + WnfsPrivateResult, + WnfsPublicResult, +} from './types/internal.js' + +// 🏔️ + +export const TYPES: Record = { + ADDED_OR_UPDATED: 'added-or-updated', + REMOVED: 'removed', +} + +// PUBLIC + +export interface PublicParams { + blockStore: BlockStore + pathSegments: Path.Segments + rootTree: RootTree +} + +export type Public = (params: PublicParams) => Promise + +export const publicCreateDirectory = () => { + return async (params: PublicParams): Promise => { + return await params.rootTree.publicRoot.mkdir( + params.pathSegments, + new Date(), + params.blockStore + ) + } +} + +export const publicRemove = + () => + async (params: PublicParams): Promise => { + return await params.rootTree.publicRoot.rm( + params.pathSegments, + params.blockStore + ) + } + +export const publicWrite = + (bytes: Uint8Array) => + async (params: PublicParams): Promise => { + const cid = await Unix.importFile(bytes, params.dependencies.depot) + + return await params.rootTree.publicRoot.write( + params.pathSegments, + cid.bytes, + new Date(), + params.blockStore + ) + } + +// PRIVATE + +export type PrivateParams = { + blockStore: BlockStore + privateNodes: MountedPrivateNodes + rng: Rng + rootTree: RootTree +} & PrivateNodeQueryResult + +export type Private = (params: PrivateParams) => Promise + +export const privateCreateDirectory = () => { + return async (params: PrivateParams): Promise => { + if (params.node.isFile()) + throw new Error('Cannot create a directory inside a file') + + return await params.node + .asDir() + .mkdir( + params.remainder, + searchLatest(), + new Date(), + params.rootTree.privateForest, + params.blockStore, + params.rng + ) + } +} + +export const privateRemove = () => { + return async (params: PrivateParams): Promise => { + if (params.node.isFile()) { + throw new Error('Cannot self-destruct') + } + + return await params.node + .asDir() + .rm( + params.remainder, + searchLatest(), + params.rootTree.privateForest, + params.blockStore + ) + } +} + +export const privateWrite = (bytes: Uint8Array) => { + return async (params: PrivateParams): Promise => { + if (params.node.isFile()) { + throw new Error('Cannot write into a PrivateFile directly') + } + + return await params.node + .asDir() + .write( + params.remainder, + searchLatest(), + bytes, + new Date(), + params.rootTree.privateForest, + params.blockStore, + params.rng + ) + } +} diff --git a/packages/nest/src/path/index.node.test.ts b/packages/nest/src/path/index.node.test.ts new file mode 100644 index 0000000..9f36e27 --- /dev/null +++ b/packages/nest/src/path/index.node.test.ts @@ -0,0 +1,480 @@ +import { strict as assert } from "assert" +import * as fc from "fast-check" +import * as Path from "./index.js" +import { DirectoryPath, FilePath, RootBranch } from "./index.js" + +describe("Path functions", () => { + // CREATION + + it("creates directory paths", () => { + fc.assert( + fc.property(fc.array(fc.hexaString()), data => { + assert.deepEqual( + Path.directory(...data), + { directory: data } + ) + }) + ) + + assert.throws(() => Path.directory("/")) + + // Type testing + const a: Path.Directory> = Path.directory("private") + const b: Path.Directory> = Path.directory("public", "a") + const c: Path.Directory = Path.directory("private", "a", "b") + }) + + it("creates file paths", () => { + fc.assert( + fc.property(fc.array(fc.hexaString()), data => { + assert.deepEqual( + Path.file(...data), + { file: data } + ) + }) + ) + + assert.throws(() => Path.file("/")) + + // Type testing + const a: Path.File> = Path.file("private", "a") + const b: Path.File = Path.file("private", "a", "b") + }) + + it("creates directory paths with fromKind", () => { + fc.assert( + fc.property(fc.array(fc.hexaString()), data => { + assert.deepEqual( + Path.fromKind(Path.Kind.Directory, ...data), + { directory: data } + ) + }) + ) + + // Type testing + const a: Path.Directory> = Path.fromKind(Path.Kind.Directory, "private") + const b: Path.Directory> = Path.fromKind(Path.Kind.Directory, "public", "a") + const c: Path.Directory = Path.fromKind(Path.Kind.Directory, "private", "a", "b") + }) + + it("creates file paths with fromKind", () => { + fc.assert( + fc.property(fc.array(fc.hexaString()), data => { + assert.deepEqual( + Path.fromKind(Path.Kind.File, ...data), + { file: data } + ) + }) + ) + + // Type testing + const a: Path.File> = Path.fromKind(Path.Kind.File, "private", "a") + const b: Path.File = Path.fromKind(Path.Kind.File, "private", "a", "b") + }) + + // POSIX + + it("creates a path from a POSIX formatted string", () => { + assert.deepEqual( + Path.fromPosix("foo/bar/"), + { directory: ["foo", "bar"] } + ) + + assert.deepEqual( + Path.fromPosix("/foo/bar/"), + { directory: ["foo", "bar"] } + ) + + assert.deepEqual( + Path.fromPosix("/"), + { directory: [] } + ) + + assert.deepEqual( + Path.fromPosix("foo/bar"), + { file: ["foo", "bar"] } + ) + + assert.deepEqual( + Path.fromPosix("/foo/bar"), + { file: ["foo", "bar"] } + ) + }) + + it("converts a path to the POSIX format", () => { + assert.equal( + Path.toPosix({ directory: ["foo", "bar"] }), + "foo/bar/" + ) + + assert.equal( + Path.toPosix({ directory: [] }), + "" + ) + + assert.equal( + Path.toPosix({ file: ["foo", "bar"] }), + "foo/bar" + ) + }) + + // 🛠 + + it("can create app-data paths", () => { + const appInfo = { + name: "Tests", + creator: "Fission", + } + + const root: DirectoryPath> = Path.appData( + "private", + appInfo + ) + + assert.deepEqual( + root, + { directory: [RootBranch.Private, "Apps", appInfo.creator, appInfo.name] } + ) + + const dir: DirectoryPath> = Path.appData( + "private", + appInfo, + Path.directory("a") + ) + + assert.deepEqual( + dir, + { directory: [RootBranch.Private, "Apps", appInfo.creator, appInfo.name, "a"] } + ) + + const file: FilePath> = Path.appData( + "public", + appInfo, + Path.file("a") + ) + + assert.deepEqual( + file, + { file: [RootBranch.Public, "Apps", appInfo.creator, appInfo.name, "a"] } + ) + }) + + it("can be combined", () => { + const dir: DirectoryPath = Path.combine( + Path.directory("a"), + Path.directory("b") + ) + + assert.deepEqual( + dir, + { directory: ["a", "b"] } + ) + + const file: FilePath = Path.combine( + Path.directory("a"), + Path.file("b") + ) + + assert.deepEqual( + file, + { file: ["a", "b"] } + ) + + // Type testing + const a: DirectoryPath> = Path.combine( + Path.directory("private"), + Path.directory("a") + ) + + const aa: FilePath> = Path.combine( + Path.directory("public"), + Path.file("a") + ) + + const b: DirectoryPath> = Path.combine( + Path.directory("private"), + Path.directory() + ) + + const bb: FilePath> = Path.combine( + Path.directory("public"), + Path.file() + ) + + const c: DirectoryPath> = Path.combine( + Path.directory("private"), + Path.directory("a") + ) + + const cc: FilePath> = Path.combine( + Path.directory("public"), + Path.file("a") + ) + }) + + it("supports isOnRootBranch", () => { + assert.equal( + Path.isOnRootBranch( + RootBranch.Private, + Path.directory(RootBranch.Private, "a") + ), + true + ) + + assert.equal( + Path.isOnRootBranch( + RootBranch.Public, + Path.directory(RootBranch.Private, "a") + ), + false + ) + }) + + it("supports isDirectory", () => { + assert.equal( + Path.isDirectory( + Path.directory(RootBranch.Private) + ), + true + ) + + assert.equal( + Path.isDirectory( + Path.file("foo") + ), + false + ) + }) + + it("supports isFile", () => { + assert.equal( + Path.isFile( + Path.file("foo") + ), + true + ) + + assert.equal( + Path.isFile( + Path.directory(RootBranch.Private) + ), + false + ) + }) + + it("supports isRootDirectory", () => { + assert.equal( + Path.isRootDirectory( + Path.root() + ), + true + ) + + assert.equal( + Path.isRootDirectory( + Path.directory() + ), + true + ) + + assert.equal( + Path.isRootDirectory( + Path.directory(RootBranch.Private) + ), + false + ) + }) + + it("supports isSamePartition", () => { + assert.equal( + Path.isSamePartition( + Path.directory(RootBranch.Private), + Path.directory(RootBranch.Private) + ), + true + ) + + assert.equal( + Path.isSamePartition( + Path.directory(RootBranch.Private), + Path.directory(RootBranch.Public) + ), + false + ) + }) + + it("supports isSameKind", () => { + assert.equal( + Path.isSameKind( + Path.directory(), + Path.file() + ), + false + ) + + assert.equal( + Path.isSameKind( + Path.file(), + Path.directory() + ), + false + ) + + assert.equal( + Path.isSameKind( + Path.directory(), + Path.directory() + ), + true + ) + + assert.equal( + Path.isSameKind( + Path.file(), + Path.file() + ), + true + ) + }) + + it("has kind", () => { + assert.equal( + Path.kind(Path.directory()), + Path.Kind.Directory + ) + + assert.equal( + Path.kind(Path.file()), + Path.Kind.File + ) + }) + + it("supports map", () => { + assert.deepEqual( + Path.map( + p => [...p, "bar"], + Path.directory("foo") + ), + { directory: ["foo", "bar"] } + ) + + assert.deepEqual( + Path.map( + p => [...p, "bar"], + Path.file("foo") + ), + { file: ["foo", "bar"] } + ) + }) + + it("supports parent", () => { + assert.deepEqual( + Path.parent( + Path.directory("foo") + ), + Path.root() + ) + + assert.deepEqual( + Path.parent( + Path.file("foo") + ), + Path.root() + ) + + assert.equal( + Path.parent( + Path.root() + ), + null + ) + + // Type testing + const a: DirectoryPath> = Path.parent({ + directory: ["private", "a", "b"], + }) + + const a_: DirectoryPath = Path.parent({ + directory: ["random", "a", "b"], + }) + + const b: DirectoryPath> = Path.parent({ + directory: ["private", "a"], + }) + + const b_: DirectoryPath = Path.parent({ + directory: ["random", "a"], + }) + + const c: DirectoryPath = Path.parent({ + directory: ["private"], + }) + + const c_: DirectoryPath = Path.parent({ + directory: ["random"], + }) + + const x: null = Path.parent({ + directory: [], + }) + }) + + it("supports removePartition", () => { + assert.deepEqual( + Path.removePartition( + Path.directory("foo") + ), + { directory: [] } + ) + + assert.deepEqual( + Path.removePartition( + Path.directory("foo", "bar") + ), + Path.directory("bar") + ) + }) + + it("supports replaceTerminus", () => { + assert.deepEqual( + Path.replaceTerminus( + Path.file("private", "a", "b"), + "c" + ), + Path.file("private", "a", "c") + ) + + // Type testing + const a: DirectoryPath> = Path.replaceTerminus({ + directory: ["private", "a"], + }, "b") + + const b: FilePath> = Path.replaceTerminus({ + file: ["private", "a"], + }, "b") + + const c: DirectoryPath = Path.replaceTerminus({ + directory: ["a"], + }, "b") + + const d: FilePath = Path.replaceTerminus({ + file: ["a"], + }, "b") + }) + + it("correctly unwraps", () => { + assert.deepEqual( + Path.unwrap( + Path.directory("foo") + ), + ["foo"] + ) + + assert.deepEqual( + Path.unwrap( + Path.file("foo") + ), + ["foo"] + ) + }) +}) diff --git a/packages/nest/src/path/index.ts b/packages/nest/src/path/index.ts new file mode 100644 index 0000000..180d4be --- /dev/null +++ b/packages/nest/src/path/index.ts @@ -0,0 +1,562 @@ +// 🧩 + +export enum RootBranch { + Exchange = 'exchange', + Private = 'private', + Public = 'public', + Unix = 'unix', + Version = 'version', +} + +export enum Kind { + Directory = 'directory', + File = 'file', +} + +export type Segment = string +export type Segments = Segment[] +export type SegmentsNonEmpty = [Segment, ...Segments] +export type Partitioned

= [P, ...Segments] +export type PartitionedNonEmpty

= [P, Segment, ...Segments] + +/** + * Private partition + */ +export type Private = 'private' | RootBranch.Private + +/** + * Public partition + */ +export type Public = 'public' | RootBranch.Public + +/** + * `RootBranch`es that are accessible through the POSIX file system interface. + */ +export type Partition = Private | Public + +/** + * A directory path. + */ +export interface DirectoryPath

{ + directory: P +} + +/** + * A file path. + */ +export interface FilePath

{ + file: P +} + +/** + * A file or directory path. + */ +export type DistinctivePath

= DirectoryPath

| FilePath

+ +/** + * Alias for `DirectoryPath` + */ +export type Directory

= DirectoryPath

+ +/** + * Alias for `FilePath` + */ +export type File

= FilePath

+ +/** + * Alias for `DistinctivePath` + */ +export type Distinctive

= DistinctivePath

+ +// CREATION + +/** + * Utility function to create a `DirectoryPath` + */ +export function directory

( + ...args: PartitionedNonEmpty

+): DirectoryPath> +export function directory

( + ...args: Partitioned

+): DirectoryPath> +export function directory( + ...args: SegmentsNonEmpty +): DirectoryPath +export function directory(...args: Segments): DirectoryPath +export function directory(...args: Segments): DirectoryPath { + if (args.some((p) => p.includes('/'))) { + throw new Error('Forward slashes `/` are not allowed') + } + return { directory: args } +} + +/** + * Utility function to create a `FilePath` + */ +export function file

( + ...args: PartitionedNonEmpty

+): FilePath> +export function file(...args: SegmentsNonEmpty): FilePath +export function file(...args: Segments): FilePath +export function file(...args: Segments): FilePath { + if (args.some((p) => p.includes('/'))) { + throw new Error('Forward slashes `/` are not allowed') + } + return { file: args } +} + +/** + * Utility function to create a path based on the given `Kind` + */ +export function fromKind

( + kind: Kind.Directory, + ...args: PartitionedNonEmpty

+): DirectoryPath> +export function fromKind

( + kind: Kind.Directory, + ...args: Partitioned

+): DirectoryPath> +export function fromKind( + kind: Kind.Directory, + ...args: SegmentsNonEmpty +): DirectoryPath +export function fromKind( + kind: Kind.Directory, + ...args: Segments +): DirectoryPath +export function fromKind

( + kind: Kind.File, + ...args: PartitionedNonEmpty

+): FilePath> +export function fromKind( + kind: Kind.File, + ...args: SegmentsNonEmpty +): FilePath +export function fromKind(kind: Kind.File, ...args: Segments): FilePath +export function fromKind

( + kind: Kind, + ...args: PartitionedNonEmpty

+): DistinctivePath> +export function fromKind

( + kind: Kind, + ...args: Partitioned

+): DistinctivePath> +export function fromKind( + kind: Kind, + ...args: SegmentsNonEmpty +): DistinctivePath +export function fromKind( + kind: Kind, + ...args: Segments +): DistinctivePath +export function fromKind( + kind: Kind, + ...args: Segments +): DistinctivePath { + return kind === Kind.Directory ? directory(...args) : file(...args) +} + +/** + * Utility function to create a root `DirectoryPath` + */ +export function root(): DirectoryPath { + return { directory: [] } +} + +// POSIX + +/** + * Transform a string into a `DistinctivePath`. + * + * Directories should have the format `path/to/dir/` and + * files should have the format `path/to/file`. + * + * Leading forward slashes are removed too, so you can pass absolute paths. + */ +export function fromPosix(path: string): DistinctivePath { + const split = path.replace(/^\/+/, '').split('/') + if (path.endsWith('/')) return { directory: split.slice(0, -1) } + else if (path === '') return root() + return { file: split } +} + +/** + * Transform a `DistinctivePath` into a string. + * + * Directories will have the format `path/to/dir/` and + * files will have the format `path/to/file`. + */ +export function toPosix( + path: DistinctivePath, + { absolute }: { absolute: boolean } = { absolute: false } +): string { + const prefix = absolute ? '/' : '' + const joinedPath = unwrap(path).join('/') + if (isDirectory(path)) + return prefix + joinedPath + (joinedPath.length ? '/' : '') + return prefix + joinedPath +} + +// 🛠️ + +/** + * Combine two `DistinctivePath`s. + */ +export function combine

( + a: DirectoryPath>, + b: FilePath +): FilePath> +export function combine

( + a: DirectoryPath>, + b: FilePath +): FilePath> +export function combine

( + a: DirectoryPath>, + b: FilePath +): FilePath> +export function combine( + a: DirectoryPath, + b: FilePath +): FilePath +export function combine( + a: DirectoryPath, + b: FilePath +): FilePath +export function combine

( + a: DirectoryPath>, + b: DirectoryPath +): DirectoryPath> +export function combine

( + a: DirectoryPath>, + b: DirectoryPath +): DirectoryPath> +export function combine

( + a: DirectoryPath>, + b: DirectoryPath +): DirectoryPath> +export function combine( + a: DirectoryPath, + b: DirectoryPath +): DirectoryPath +export function combine( + a: DirectoryPath, + b: DirectoryPath +): DirectoryPath +export function combine

( + a: DirectoryPath>, + b: DistinctivePath +): DistinctivePath> +export function combine

( + a: DirectoryPath>, + b: DistinctivePath +): DistinctivePath> +export function combine

( + a: DirectoryPath>, + b: DistinctivePath +): DistinctivePath> +export function combine( + a: DirectoryPath, + b: DistinctivePath +): DistinctivePath +export function combine( + a: DirectoryPath, + b: DistinctivePath +): DistinctivePath +export function combine( + a: DirectoryPath, + b: DistinctivePath +): DistinctivePath { + return map((p) => unwrap(a).concat(p), b) +} + +/** + * Is this `DistinctivePath` a directory? + */ +export function isDirectory

( + path: DistinctivePath

+): path is DirectoryPath

{ + return 'directory' in path +} + +/** + * Is this `DistinctivePath` a file? + */ +export function isFile

(path: DistinctivePath

): path is FilePath

{ + return 'file' in path +} + +/** + * Is this `DistinctivePath` on the given `RootBranch`? + */ +export function isOnRootBranch( + rootBranch: RootBranch, + path: DistinctivePath +): boolean { + return unwrap(path)[0] === rootBranch +} + +/** + * Is this `DistinctivePath` of the given `Partition`? + */ +export function isPartition( + partition: Partition, + path: DistinctivePath +): boolean { + return unwrap(path)[0] === partition +} + +/** + * Is this a partitioned `DistinctivePath`? + */ +export function isPartitioned

( + path: DistinctivePath +): path is DistinctivePath> { + const soCalledPartition = unwrap(path)[0] + return [RootBranch.Private, RootBranch.Public, 'private', 'public'].includes( + soCalledPartition + ) +} + +/** + * Is this partitioned `DistinctivePath` non-empty? + */ +export function isPartitionedNonEmpty

( + path: DistinctivePath +): path is DistinctivePath> { + return isPartitioned(path) && length(path) > 1 +} + +/** + * Is this `DirectoryPath` a root directory? + */ +export function isRootDirectory(path: DirectoryPath): boolean { + return path.directory.length === 0 +} + +/** + * Check if two `DistinctivePath` have the same `Partition`. + */ +export function isSamePartition( + a: DistinctivePath, + b: DistinctivePath +): boolean { + return unwrap(a)[0] === unwrap(b)[0] +} + +/** + * Check if two `DistinctivePath` are of the same kind. + */ +export function isSameKind( + a: DistinctivePath, + b: DistinctivePath +): boolean { + if (isDirectory(a) && isDirectory(b)) return true + else if (isFile(a) && isFile(b)) return true + else return false +} + +/** + * What `Kind` of path are we dealing with? + */ +export function kind

(path: DistinctivePath

): Kind { + if (isDirectory(path)) return Kind.Directory + return Kind.File +} + +/** + * What's the length of a path? + */ +export function length(path: DistinctivePath): number { + return unwrap(path).length +} + +/** + * Map a `DistinctivePath`. + */ +export function map( + fn: (p: A) => B, + path: DistinctivePath +): DistinctivePath { + if (isDirectory(path)) return { directory: fn(path.directory) } + else if (isFile(path)) return { file: fn(path.file) } + return path +} + +/** + * Get the parent directory of a `DistinctivePath`. + */ +export function parent( + path: DistinctivePath<[Partition, Segment, Segment, ...Segments]> +): DirectoryPath> +export function parent( + path: DistinctivePath<[Segment, Segment, Segment, ...Segments]> +): DirectoryPath +export function parent( + path: DistinctivePath> +): DirectoryPath> +export function parent( + path: DistinctivePath<[Partition, Segment]> +): DirectoryPath> +export function parent( + path: DistinctivePath> +): DirectoryPath +export function parent( + path: DistinctivePath +): DirectoryPath +export function parent(path: DistinctivePath<[Segment]>): DirectoryPath<[]> +export function parent(path: DistinctivePath<[]>): null +export function parent( + path: DistinctivePath +): DirectoryPath | undefined +export function parent( + path: DistinctivePath +): DirectoryPath | undefined { + return isDirectory(path) && isRootDirectory(path) + ? undefined + : directory(...unwrap(path).slice(0, -1)) +} + +/** + * Remove the `Partition` of a `DistinctivePath` (ie. the top-level directory) + */ +export function removePartition( + path: DistinctivePath +): DistinctivePath { + return map((p) => (isDirectory(path) || p.length > 1 ? p.slice(1) : p), path) +} + +export function replaceTerminus( + path: FilePath>, + terminus: string +): FilePath> +export function replaceTerminus( + path: DirectoryPath>, + terminus: string +): DirectoryPath> +export function replaceTerminus( + path: DistinctivePath>, + terminus: string +): DistinctivePath> +export function replaceTerminus( + path: FilePath, + terminus: string +): FilePath +export function replaceTerminus( + path: DirectoryPath, + terminus: string +): DirectoryPath +export function replaceTerminus( + path: DistinctivePath, + terminus: string +): DistinctivePath +export function replaceTerminus( + path: DistinctivePath | DistinctivePath, + terminus: string +): DistinctivePath { + return combine(parent(path), fromKind(kind(path), terminus)) +} + +export function rootBranch( + path: DistinctivePath +): { branch: RootBranch; rest: Segments } | undefined { + const unwrapped = unwrap(path) + const firstSegment = unwrapped[0] + const rest = unwrapped.slice(1) + + switch (firstSegment) { + case RootBranch.Exchange: { + return { branch: RootBranch.Exchange, rest } + } + + case RootBranch.Private: { + return { branch: RootBranch.Private, rest } + } + + case RootBranch.Public: { + return { branch: RootBranch.Public, rest } + } + + case RootBranch.Unix: { + return { branch: RootBranch.Unix, rest } + } + + case RootBranch.Version: { + return { branch: RootBranch.Version, rest } + } + + default: { + return undefined + } + } +} + +/** + * Get the last part of the path. + */ +export function terminus( + path: DistinctivePath> +): string +export function terminus(path: DistinctivePath>): string +export function terminus(path: DistinctivePath): string +export function terminus(path: DistinctivePath): string | undefined +export function terminus(path: DistinctivePath): string | undefined { + const u = unwrap(path) + if (u.length === 0) return undefined + return u.at(-1) +} + +/** + * Unwrap a `DistinctivePath`. + */ +export function unwrap

(path: DistinctivePath

): P { + if (isDirectory(path)) { + return path.directory + } else if (isFile(path)) { + return path.file + } + + throw new Error('Path is neither a directory or a file') +} + +/** + * Utility function to prefix a path with a `Partition`. + */ +export function withPartition

( + partition: P, + path: DirectoryPath +): DirectoryPath> +export function withPartition

( + partition: P, + path: DirectoryPath +): DirectoryPath> +export function withPartition

( + partition: P, + path: FilePath +): FilePath> +export function withPartition

( + partition: P, + path: FilePath +): FilePath> +export function withPartition

( + partition: P, + path: DistinctivePath +): DistinctivePath> +export function withPartition

( + partition: P, + path: DistinctivePath +): DistinctivePath> +export function withPartition

( + partition: P, + path: DistinctivePath +): DistinctivePath> { + return combine(directory(partition), path) +} + +// 🔬 + +/** + * Render a raw `Path` to a string for logging purposes. + */ +export function log(path: Segments): string { + return `[ ${path.join(', ')} ]` +} diff --git a/packages/nest/src/queries.ts b/packages/nest/src/queries.ts new file mode 100644 index 0000000..ccf096e --- /dev/null +++ b/packages/nest/src/queries.ts @@ -0,0 +1,287 @@ +import type { + AccessKey, + BlockStore, + PrivateDirectory, + PrivateFile, + PublicDirectory, + PublicNode, +} from 'wnfs' + +import { PrivateNode } from 'wnfs' +import { CID } from 'multiformats' + +import * as Path from './path/index.js' + +import type { Partitioned } from './path/index.js' +import type { Rng } from './rng.js' +import type { RootTree } from './root-tree.js' +import type { DirectoryItem, DirectoryItemWithKind } from './types.js' +import type { + MountedPrivateNodes, + PrivateNodeQueryResult, +} from './types/internal.js' + +import { searchLatest } from './common.js' +import { findPrivateNode } from './mounts.js' + +// PUBLIC + +export interface PublicParams { + blockStore: BlockStore + pathSegments: Path.Segments + rootTree: RootTree +} + +export type Public = (params: PublicParams) => Promise +export type PublicContext = Omit + +export async function publicQuery( + path: Path.Distinctive>, + qry: Public, + context: PublicContext +): Promise { + return await qry({ + blockStore: context.blockStore, + pathSegments: Path.unwrap(Path.removePartition(path)), + rootTree: context.rootTree, + }) +} + +export const publicExists = () => { + return async (params: PublicParams): Promise => { + const result = await params.rootTree.publicRoot.getNode( + params.pathSegments, + params.blockStore + ) + + return result !== null && result !== undefined + } +} + +export const publicListDirectory = () => { + return async (params: PublicParams): Promise => { + return params.rootTree.publicRoot.ls(params.pathSegments, params.blockStore) + } +} + +export const publicListDirectoryWithKind = () => { + return async (params: PublicParams): Promise => { + const dir: PublicDirectory = + params.pathSegments.length === 0 + ? params.rootTree.publicRoot + : await params.rootTree.publicRoot + .getNode(params.pathSegments, params.blockStore) + .then((a) => a.asDir()) + const items: DirectoryItem[] = await dir.ls([], params.blockStore) + + const promises = items.map(async (item): Promise => { + const node: PublicNode = await dir.lookupNode( + item.name, + params.blockStore + ) + const kind = node.isDir() === true ? Path.Kind.Directory : Path.Kind.File + + return { + ...item, + kind, + path: Path.combine( + Path.directory('public', ...params.pathSegments), + Path.fromKind(kind, item.name) + ), + } + }) + + return await Promise.all(promises) + } +} + +export const publicRead = (options?: { offset: number; length: number }) => { + return async (params: PublicParams): Promise => { + const result = await params.rootTree.publicRoot.read( + params.pathSegments, + params.blockStore + ) + + return await publicReadFromCID(CID.decode(result), options)(params) + } +} + +export const publicReadFromCID = ( + cid: CID, + options?: { offset: number; length: number } +) => { + return async (context: PublicContext): Promise => { + // TODO: + // return Unix.exportFile(cid, context.dependencies.depot, options) + return new Uint8Array() + } +} + +// PRIVATE + +export type PrivateParams = { + blockStore: BlockStore + privateNodes: MountedPrivateNodes + rng: Rng + rootTree: RootTree +} & PrivateNodeQueryResult + +export type Private = (params: PrivateParams) => Promise +export type PrivateContext = Omit + +export async function privateQuery( + path: Path.Distinctive>, + qry: Private, + context: PrivateContext +): Promise { + const priv = findPrivateNode(path, context.privateNodes) + + // Perform mutation + return await qry({ + ...priv, + blockStore: context.blockStore, + privateNodes: context.privateNodes, + rng: context.rng, + rootTree: context.rootTree, + }) +} + +export const privateExists = () => { + return async (params: PrivateParams): Promise => { + if (params.node.isFile() === true) return true + + const result = await params.node + .asDir() + .getNode( + params.remainder, + searchLatest(), + params.rootTree.privateForest, + params.blockStore + ) + + return result !== null && result !== undefined + } +} + +export const privateListDirectory = () => { + return async (params: PrivateParams): Promise => { + if (params.node.isFile() === true) throw new Error('Cannot list a file') + const { result } = await params.node + .asDir() + .ls( + params.remainder, + searchLatest(), + params.rootTree.privateForest, + params.blockStore + ) + return result + } +} + +export const privateListDirectoryWithKind = () => { + return async (params: PrivateParams): Promise => { + if (params.node.isFile() === true) throw new Error('Cannot list a file') + + const dir: PrivateDirectory = + params.remainder.length === 0 + ? params.node.asDir() + : await params.node + .asDir() + .getNode( + params.remainder, + searchLatest(), + params.rootTree.privateForest, + params.blockStore + ) + .then((a) => a.asDir()) + const items: DirectoryItem[] = await dir + .ls([], searchLatest(), params.rootTree.privateForest, params.blockStore) + .then((a) => a.result) + + const parentPath = Path.combine( + Path.directory('private', ...Path.unwrap(params.path)), + Path.directory(...params.remainder) + ) + + if (!Path.isDirectory(parentPath)) { + throw new Error("Didn't expect a file path") + } + + const promises = items.map( + async (item: DirectoryItem): Promise => { + const node: PrivateNode = await dir.lookupNode( + item.name, + searchLatest(), + params.rootTree.privateForest, + params.blockStore + ) + + const kind = + node.isDir() === true ? Path.Kind.Directory : Path.Kind.File + + return { + ...item, + kind, + path: Path.combine(parentPath, Path.fromKind(kind, item.name)), + } + } + ) + + return await Promise.all(promises) + } +} + +export const privateRead = (options?: { offset: number; length: number }) => { + return async (params: PrivateParams): Promise => { + // TODO: Respect `offset` and `length` options when private streaming API is exposed in rs-wnfs + // const offset = options?.offset + // const length = options?.length + + let bytes + + if (params.node.isFile() === true) { + bytes = await params.node + .asFile() + .getContent(params.rootTree.privateForest, params.blockStore) + } else { + const { result } = await params.node + .asDir() + .read( + params.remainder, + searchLatest(), + params.rootTree.privateForest, + params.blockStore + ) + bytes = result + } + + return bytes + } +} + +export const privateReadFromAccessKey = ( + accessKey: AccessKey, + options?: { offset: number; length: number } +) => { + return async (context: PrivateContext): Promise => { + // TODO: Respect `offset` and `length` options when private streaming API is exposed in rs-wnfs + // const offset = options?.offset + // const length = options?.length + + // Retrieve node + const node = await PrivateNode.load( + accessKey, + context.rootTree.privateForest, + context.blockStore + ) + + if (node.isFile() === true) { + const file: PrivateFile = node.asFile() + + // TODO: Respect the offset and length options when available in rs-wnfs + return file.getContent(context.rootTree.privateForest, context.blockStore) + } else { + throw new Error('Expected a file, found a directory') + } + } +} diff --git a/packages/nest/src/rng.ts b/packages/nest/src/rng.ts new file mode 100644 index 0000000..7fad503 --- /dev/null +++ b/packages/nest/src/rng.ts @@ -0,0 +1,14 @@ +import { webcrypto } from 'iso-base/crypto' + +export interface Rng { + randomBytes: (count: number) => Uint8Array +} + +export function makeRngInterface(): Rng { + return { + /** Returns random bytes of specified length */ + randomBytes(count: number): Uint8Array { + return webcrypto.getRandomValues(new Uint8Array(count)) + }, + } +} diff --git a/packages/nest/src/root-tree.ts b/packages/nest/src/root-tree.ts new file mode 100644 index 0000000..f162ed5 --- /dev/null +++ b/packages/nest/src/root-tree.ts @@ -0,0 +1,22 @@ +import type { Blockstore } from 'interface-blockstore' +import type { CID } from 'multiformats' +import type { PrivateForest, PublicDirectory } from 'wnfs' + +/** + * The tree that ties different file systems together. + */ +export abstract class RootTree { + abstract privateForest: PrivateForest + abstract publicRoot: PublicDirectory + + abstract commit(privateForest: PrivateForest): Promise + abstract store(): Promise + + static async create(_blockstore: Blockstore): Promise { + throw new Error('Not implemented!') + } + + static async fromCID(_blockstore: Blockstore, _cid: CID): Promise { + throw new Error('Not implemented!') + } +} diff --git a/packages/nest/src/root-tree/basic.ts b/packages/nest/src/root-tree/basic.ts new file mode 100644 index 0000000..25c9074 --- /dev/null +++ b/packages/nest/src/root-tree/basic.ts @@ -0,0 +1,281 @@ +import type { PBLink, PBNode } from '@ipld/dag-pb' +import type { Blockstore } from 'interface-blockstore' + +import * as DagPB from '@ipld/dag-pb' +import * as Raw from 'multiformats/codecs/raw' +import * as Uint8Arrays from 'uint8arrays' + +import { webcrypto } from 'iso-base/crypto' +import { CID } from 'multiformats' +import { PrivateForest, PublicDirectory } from 'wnfs' + +// import * as Unix from './unix.js' + +import * as Store from '../store.js' +import * as Version from '../version.js' + +import { RootBranch } from '../path/index.js' +import { makeRngInterface } from '../rng.js' +import type { RootTree } from '../root-tree.js' + +// CLASS + +export class BasicRootTree implements RootTree { + readonly #blockstore: Blockstore + readonly #exchangeRoot: PublicDirectory + readonly #unix: PBNode + readonly #version: string + + publicRoot: PublicDirectory + privateForest: PrivateForest + + constructor({ + blockstore, + exchangeRoot, + publicRoot, + privateForest, + unix, + version, + }: { + blockstore: Blockstore + exchangeRoot: PublicDirectory + publicRoot: PublicDirectory + privateForest: PrivateForest + unix: PBNode + version: string + }) { + this.#blockstore = blockstore + this.#exchangeRoot = exchangeRoot + this.#unix = unix + this.#version = version + + this.publicRoot = publicRoot + this.privateForest = privateForest + } + + /** + * Create a new root tree. + */ + static async create(blockstore: Blockstore): Promise { + const currentTime = new Date() + + return new BasicRootTree({ + blockstore, + + exchangeRoot: new PublicDirectory(currentTime), + publicRoot: new PublicDirectory(currentTime), + privateForest: await createPrivateForest(), + unix: Unix.createDirectory(currentTime), + version: Version.latest, + }) + } + + /** + * Load an existing root tree. + */ + static async fromCID( + cid: CID, + blockstore: Blockstore + ): Promise { + const currentTime = new Date() + + // Retrieve links + const links = await linksFromCID(depot, cid) + + // Retrieve all pieces + async function handleLink( + name: string, + present: (cid: CID) => Promise, + missing: () => T | Promise + ): Promise { + if (links[name]) { + return present(links[name]) + } else { + console.warn( + `Missing '${name}' link in the root tree from '${cid.toString()}'. Creating a new link.` + ) + return await missing() + } + } + + const exchangeRoot = await handleLink( + RootBranch.Exchange, + (cid) => PublicDirectory.load(cid.bytes, blockStore), + () => new PublicDirectory(currentTime) + ) + + const publicRoot = await handleLink( + RootBranch.Public, + (cid) => PublicDirectory.load(cid.bytes, blockStore), + () => new PublicDirectory(currentTime) + ) + + const privateForest = await handleLink( + RootBranch.Private, + (cid) => PrivateForest.load(cid.bytes, blockStore), + () => createPrivateForest() + ) + + const unix = await handleLink( + RootBranch.Unix, + (cid) => Unix.load(cid, depot), + () => Unix.createDirectory(currentTime) + ) + + const version = await handleLink( + RootBranch.Version, + async (cid) => { + const string = new TextDecoder().decode(await DAG.getRaw(depot, cid)) + const semVer = SemVer.fromString(string) + if (!semVer) + throw new Error(`Invalid file system version detected '${string}'`) + return semVer + }, + () => Version.v2 + ) + + // Compose + return { + exchangeRoot, + publicRoot, + privateForest, + unix, + version, + } + } + + async commit(_privateForest: PrivateForest): Promise { + throw new Error('Not implemented!') + + // const unixTree = await changes.reduce(async (oldRootPromise, change) => { + // const oldRoot = await oldRootPromise + + // if (!Path.isPartition('public', change.path)) { + // return oldRoot + // } + + // const path = Path.removePartition(change.path) + + // if (change.type === 'removed') { + // return Unix.removeNodeFromTree( + // oldRoot, + // path, + // context.#dependencies.depot + // ) + // } + + // const contentCID = + // Path.isFile(change.path) && + // Path.isPartitionedNonEmpty(change.path) + // ? await context.contentCID(change.path).then((a) => a ?? undefined) + // : undefined + + // return Unix.insertNodeIntoTree( + // oldRoot, + // path, + // context.#dependencies.depot, + // contentCID + // ) + // }, Promise.resolve(context.#rootTree.unix)) + } + + async store(): Promise { + const wnfsStore = Store.wnfsStore(this.#blockstore) + + // Store all pieces + const exchangeRoot = await this.#exchangeRoot.store(wnfsStore) + const privateForest = await this.privateForest.store(wnfsStore) + const publicRoot = await this.publicRoot.store(wnfsStore) + + const unixTree = await Unix.store(this.#unix, this.#blockstore) + + const versionBytes = Raw.encode(new TextEncoder().encode(this.#version)) + const version = await this.#blockstore.put( + await Store.cid(versionBytes, Raw.code), + versionBytes + ) + + // Store root tree + const links = [ + { + Name: RootBranch.Exchange, + Hash: CID.decode(exchangeRoot), + }, + { + Name: RootBranch.Private, + Hash: CID.decode(privateForest), + }, + { + Name: RootBranch.Public, + Hash: CID.decode(publicRoot), + }, + { + Name: RootBranch.Unix, + Hash: unixTree, + }, + { + Name: RootBranch.Version, + Hash: version, + }, + ] + + const node = DagPB.createNode(new Uint8Array([8, 1]), links) + const nodeBytes = DagPB.encode(node) + + const rootCID = await this.#blockstore.put( + await Store.cid(nodeBytes, DagPB.code), + nodeBytes + ) + + // Fin + return rootCID + } +} + +// ㊙️ + +/** + * Create a new `PrivateForest` + */ +async function createPrivateForest(): Promise { + const rng = makeRngInterface() + + const rsaKey = await webcrypto.subtle.generateKey( + { + name: 'RSASSA-PKCS1-v1_5', + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { name: 'SHA-256' }, + }, + false, + ['sign', 'verify'] + ) + + const rsaMod = await webcrypto.subtle + .exportKey('jwk', rsaKey.publicKey) + .then((a) => { + if (typeof a.n === 'string') return a.n + else throw new Error('Expected public RSA key to have `n` property') + }) + .then((n) => Uint8Arrays.fromString(n, 'base64url')) + + return new PrivateForest(rng, rsaMod) +} + +/** + * Retrieve the links of a root tree. + */ +export async function linksFromCID( + cid: CID, + blockStore: Blockstore +): Promise> { + // Get the root node, + // which is stored as DAG-PB. + const node = DagPB.decode(await blockStore.get(cid)) + + return node.Links.reduce((acc: Record, link: PBLink) => { + return typeof link.Name === 'string' + ? { ...acc, [link.Name]: link.Hash } + : acc + }, {}) +} diff --git a/packages/nest/src/store.ts b/packages/nest/src/store.ts new file mode 100644 index 0000000..7922d59 --- /dev/null +++ b/packages/nest/src/store.ts @@ -0,0 +1,36 @@ +import type { Blockstore } from 'interface-blockstore' + +import { CID } from 'multiformats/cid' +import { sha256 } from 'multiformats/hashes/sha2' + +import * as Codecs from './codecs.js' + +// 🧩 + +export interface WnfsBlockStore { + getBlock: (cid: Uint8Array) => Promise + putBlock: (bytes: Uint8Array, code: number) => Promise +} + +// 🛠️ + +export async function cid(bytes: Uint8Array, codecId: number): Promise { + const codec = Codecs.getByCode(codecId) + const multihash = await sha256.digest(bytes) + + return CID.createV1(codec.code, multihash) +} + +export function wnfsStore(blockstore: Blockstore): WnfsBlockStore { + return { + async getBlock(cid: Uint8Array): Promise { + const decodedCid = CID.decode(cid) + return await blockstore.get(decodedCid) + }, + + async putBlock(bytes: Uint8Array, codecId: number): Promise { + await blockstore.put(await cid(bytes, codecId), bytes) + return bytes + }, + } +} diff --git a/packages/nest/src/transaction.ts b/packages/nest/src/transaction.ts new file mode 100644 index 0000000..bb83f95 --- /dev/null +++ b/packages/nest/src/transaction.ts @@ -0,0 +1,640 @@ +import { CID } from 'multiformats' +import type { BlockStore, PrivateForest, PrivateNode, PublicNode } from 'wnfs' +import { AccessKey, PublicFile } from 'wnfs' + +import * as Path from './path/index.js' +import * as Mutations from './mutations.js' +import * as Queries from './queries.js' + +// import * as Unix from './unix.js' + +import type { + Partition, + Partitioned, + PartitionedNonEmpty, + Private, + Public, +} from './path/index.js' + +import { + addOrIncreaseNameNumber, + pathSegmentsWithoutPartition, + searchLatest, +} from './common.js' + +import { dataFromBytes, dataToBytes } from './data.js' +import { partition as determinePartition, findPrivateNode } from './mounts.js' +import type { Rng } from './rng.js' +import type { RootTree } from './root-tree.js' + +import type { + AnySupportedDataType, + DataForType, + DataType, + DirectoryItem, + DirectoryItemWithKind, + MutationType, +} from './types.js' + +import type { + MountedPrivateNodes, + PrivateNodeQueryResult, +} from './types/internal.js' + +// CLASS + +/** @group File System */ +export class TransactionContext { + readonly #blockStore: BlockStore + readonly #rng: Rng + + #privateNodes: MountedPrivateNodes + #rootTree: RootTree + + readonly #changes: Set<{ + type: MutationType + path: Path.Distinctive> + }> + + /** @internal */ + constructor( + blockStore: BlockStore, + privateNodes: MountedPrivateNodes, + rng: Rng, + rootTree: RootTree + ) { + this.#blockStore = blockStore + this.#privateNodes = privateNodes + this.#rng = rng + this.#rootTree = rootTree + + this.#changes = new Set() + } + + /** @internal */ + static async commit(context: TransactionContext): Promise<{ + changes: Array<{ + path: Path.Distinctive> + type: MutationType + }> + privateNodes: MountedPrivateNodes + rootTree: RootTree + }> { + const changes = [...context.#changes] + + // Private forest + const newForest = await changes.reduce( + async (oldForestPromise, change): Promise => { + const oldForest = await oldForestPromise + + if (!Path.isPartition('private', change.path)) { + return oldForest + } + + const maybeNode = findPrivateNode( + change.path as Path.Distinctive>, + context.#privateNodes + ) + + const [_newAccessKey, newForest] = await maybeNode.node.store( + oldForest, + context.#blockStore, + context.#rng + ) + return newForest + }, + Promise.resolve(context.#rootTree.privateForest) + ) + + // Replace forest + const rootTree = await context.#rootTree.commit(newForest) + + // Fin + return { + changes: changes, + privateNodes: context.#privateNodes, + rootTree: rootTree, + } + } + + // QUERIES + + /** @group Querying */ + async contentCID( + path: Path.File> + ): Promise { + const result = await this.#rootTree.publicRoot.getNode( + pathSegmentsWithoutPartition(path), + this.#blockStore + ) + + const maybeNode: PublicNode | undefined = result ?? undefined + return maybeNode?.isFile() === true + ? CID.decode(maybeNode.asFile().contentCid()) + : undefined + } + + /** @group Querying */ + async capsuleCID( + path: Path.Distinctive> + ): Promise { + const result = await this.#rootTree.publicRoot.getNode( + pathSegmentsWithoutPartition(path), + this.#blockStore + ) + + const maybeNode: PublicNode | undefined = result ?? undefined + return maybeNode === undefined + ? undefined + : CID.decode( + maybeNode.isFile() + ? await maybeNode.asFile().store(this.#blockStore) + : await maybeNode.asDir().store(this.#blockStore) + ) + } + + /** @group Querying */ + async capsuleKey( + path: Path.Distinctive> + ): Promise { + let priv: PrivateNodeQueryResult + + try { + priv = findPrivateNode(path, this.#privateNodes) + } catch { + return undefined + } + + return priv.remainder.length === 0 || priv.node.isFile() + ? await priv.node + .store(this.#rootTree.privateForest, this.#blockStore, this.#rng) + .then(([accessKey]: [AccessKey, PrivateForest]) => + accessKey.toBytes() + ) + : await priv.node + .asDir() + .getNode( + priv.remainder, + searchLatest(), + this.#rootTree.privateForest, + this.#blockStore + ) + .then(async (result: PrivateNode | undefined) => { + return result === undefined + ? undefined + : await result + .store( + this.#rootTree.privateForest, + this.#blockStore, + this.#rng + ) + .then(([accessKey]: [AccessKey, PrivateForest]) => + accessKey.toBytes() + ) + }) + } + + /** @group Querying */ + async exists( + path: Path.Distinctive> + ): Promise { + return await this.#query(path, { + public: Queries.publicExists(), + private: Queries.privateExists(), + }) + } + + /** @group Querying */ + async listDirectory( + path: Path.Directory>, + listOptions: { withItemKind: true } + ): Promise + async listDirectory( + path: Path.Directory>, + listOptions: { withItemKind: false } + ): Promise + async listDirectory( + path: Path.Directory> + ): Promise + async listDirectory( + path: Path.Directory>, + listOptions?: { withItemKind: boolean } + ): Promise + async listDirectory( + path: Path.Directory>, + listOptions?: { withItemKind: boolean } + ): Promise { + if (listOptions?.withItemKind === true) { + return await this.#query(path, { + public: Queries.publicListDirectoryWithKind(), + private: Queries.privateListDirectoryWithKind(), + }) + } + + return await this.#query(path, { + public: Queries.publicListDirectory(), + private: Queries.privateListDirectory(), + }) + } + + /** @group Querying */ + ls = this.listDirectory + + /** @group Querying */ + async read( + arg: + | Path.File> + | { contentCID: CID } + | { capsuleCID: CID } + | { + capsuleKey: Uint8Array + }, + dataType: DataType, + options?: { offset: number; length: number } + ): Promise> + async read( + arg: + | Path.File> + | { contentCID: CID } + | { capsuleCID: CID } + | { + capsuleKey: Uint8Array + }, + dataType: DataType, + options?: { offset: number; length: number } + ): Promise> { + let bytes + + if ('contentCID' in arg) { + // Public content from content CID + bytes = await Queries.publicReadFromCID( + arg.contentCID, + options + )(this.#publicContext()) + } else if ('capsuleCID' in arg) { + // Public content from capsule CID + const publicFile: PublicFile = await PublicFile.load( + arg.capsuleCID.bytes, + this.#blockStore + ) + + return await this.read( + { contentCID: CID.decode(publicFile.contentCid()) }, + dataType, + options + ) + } else if ('capsuleKey' in arg) { + // Private content from capsule key + bytes = await Queries.privateReadFromAccessKey( + AccessKey.fromBytes(arg.capsuleKey), + options + )(this.#privateContext()) + } else if ('file' in arg || 'directory' in arg) { + // Public or private from path + bytes = await this.#query(arg, { + public: Queries.publicRead(options), + private: Queries.privateRead(options), + }) + } else { + // ⚠️ + throw new Error('Invalid argument') + } + + return dataFromBytes(dataType, bytes) + } + + // MUTATIONS + + /** @group Mutating */ + async copy( + fromParam: Path.Distinctive>, + toParam: + | Path.File> + | Path.Directory> + ): Promise { + const from = fromParam + let to = toParam + + if (Path.isDirectory(fromParam) && Path.isFile(toParam)) + throw new Error('Cannot copy a directory to a file') + if (Path.isFile(fromParam) && Path.isDirectory(toParam)) + to = Path.combine(toParam, Path.file(Path.terminus(from))) + + if (Path.isFile(from) && Path.isFile(to)) { + await this.#manualCopyFile(from, to) + } else if (Path.isDirectory(from) && Path.isDirectory(to)) { + await this.#manualCopyDirectory(from, to) + } + + // NOOP + throw new Error( + `Copy no-op, from '${Path.toPosix(from)}' to '${Path.toPosix(to)}'` + ) + } + + /** @group Mutating */ + cp = this.copy + + /** @group Mutating */ + async createDirectory( + path: Path.Directory> + ): Promise<{ path: Path.Directory> }> { + if (await this.exists(path)) { + const newPath = addOrIncreaseNameNumber(path) + return await this.createDirectory(newPath) + } else { + await this.ensureDirectory(path) + return { path: path } + } + } + + /** @group Mutating */ + async createFile( + path: Path.File>, + dataType: DataType, + data: DataForType + ): Promise<{ path: Path.File> }> { + if (await this.exists(path)) { + const newPath = addOrIncreaseNameNumber(path) + return await this.createFile(newPath, dataType, data) + } else { + await this.write(path, dataType, data) + return { path: path } + } + } + + /** @group Mutating */ + async ensureDirectory( + path: Path.Directory> + ): Promise { + const partition = determinePartition(path) + + switch (partition.name) { + case 'public': { + await this.#publicMutation( + partition.path, + Mutations.publicCreateDirectory(), + Mutations.TYPES.ADDED_OR_UPDATED + ) + break + } + + case 'private': { + await this.#privateMutation( + partition.path, + Mutations.privateCreateDirectory(), + Mutations.TYPES.ADDED_OR_UPDATED + ) + break + } + } + } + + mkdir = this.ensureDirectory + + async move( + fromParam: Path.Distinctive>, + toParam: + | Path.File> + | Path.Directory> + ): Promise { + const from = fromParam + let to = toParam + + if (Path.isDirectory(fromParam) && Path.isFile(toParam)) + throw new Error('Cannot move a directory to a file') + if (Path.isFile(fromParam) && Path.isDirectory(toParam)) + to = Path.combine(toParam, Path.file(Path.terminus(from))) + + await this.#manualMove(from, to) + } + + /** @group Mutating */ + mv = this.move + + /** @group Mutating */ + async remove( + path: Path.Distinctive> + ): Promise { + const partition = determinePartition(path) + + switch (partition.name) { + case 'public': { + await this.#publicMutation( + partition.path, + Mutations.publicRemove(), + Mutations.TYPES.REMOVED + ) + break + } + + case 'private': { + await this.#privateMutation( + partition.path, + Mutations.privateRemove(), + Mutations.TYPES.REMOVED + ) + break + } + } + } + + /** @group Mutating */ + rm = this.remove + + /** @group Mutating */ + async rename( + path: Path.Distinctive>, + newName: string + ): Promise { + const fromPath = path + const toPath = Path.replaceTerminus(fromPath, newName) + + await this.move(fromPath, toPath) + } + + /** @group Mutating */ + async write( + path: Path.File>, + dataType: DataType, + data: DataForType + ): Promise { + const bytes = dataToBytes(dataType, data) + const partition = determinePartition(path) + + switch (partition.name) { + case 'public': { + await this.#publicMutation( + partition.path, + Mutations.publicWrite(bytes), + Mutations.TYPES.ADDED_OR_UPDATED + ) + break + } + + case 'private': { + await this.#privateMutation( + partition.path, + Mutations.privateWrite(bytes), + Mutations.TYPES.ADDED_OR_UPDATED + ) + break + } + } + } + + // ㊙️ ▒▒ QUERIES + + async #query( + path: Path.Distinctive>, + queryFunctions: { + public: Queries.Public + private: Queries.Private + } + ): Promise { + const partition = determinePartition(path) + + switch (partition.name) { + case 'public': { + return await Queries.publicQuery( + partition.path, + queryFunctions.public, + this.#publicContext() + ) + } + + case 'private': { + return await Queries.privateQuery( + partition.path, + queryFunctions.private, + this.#privateContext() + ) + } + } + } + + // ㊙️ ▒▒ MUTATIONS + + async #manualCopyFile( + from: Path.File>, + to: Path.File> + ): Promise { + await this.write(to, 'bytes', await this.read(from, 'bytes')) + } + + async #manualCopyDirectory( + from: Path.Directory>, + to: Path.Directory> + ): Promise { + if (Path.isPartitionedNonEmpty(to)) await this.ensureDirectory(to) + + // Copies everything under `fromDir/` to `toDir/` + // eg. `public/docs/fromDir/a/b/c.txt` -> `private/docs/toDir/a/b/c.txt` + const listing = await this.listDirectory(from, { withItemKind: true }) + if (listing.length === 0) return + + await listing.reduce( + async ( + acc: Promise, + item: DirectoryItemWithKind + ): Promise => { + await acc + + item.kind === 'directory' + ? await this.#manualCopyDirectory( + Path.combine(from, Path.directory(item.name)), + Path.combine(to, Path.directory(item.name)) + ) + : await this.#manualCopyFile( + Path.combine(from, Path.file(item.name)), + Path.combine(to, Path.file(item.name)) + ) + }, + Promise.resolve() + ) + } + + async #manualMove( + from: Path.Distinctive>, + to: + | Path.File> + | Path.Directory> + ): Promise { + await this.copy(from, to) + await this.remove(from) + } + + async #publicMutation( + path: Path.Distinctive>, + mut: Mutations.Public, + mutType: MutationType + ): Promise { + const result = await mut({ + blockStore: this.#blockStore, + pathSegments: Path.unwrap(Path.removePartition(path)), + rootTree: this.#rootTree, + }) + + // Replace public root + this.#rootTree = { ...this.#rootTree, publicRoot: result.rootDir } + + // Mark node as changed + this.#changes.add({ + type: mutType, + path: path, + }) + } + + async #privateMutation( + path: Path.Distinctive>, + mut: Mutations.Private, + mutType: MutationType + ): Promise { + const priv = findPrivateNode(path, this.#privateNodes) + + // Perform mutation + const result = await mut({ + ...priv, + blockStore: this.#blockStore, + privateNodes: this.#privateNodes, + rng: this.#rng, + rootTree: this.#rootTree, + }) + + // Mark node as changed + this.#changes.add({ + type: mutType, + path: path, + }) + + // Replace forest + this.#rootTree = { ...this.#rootTree, privateForest: result.forest } + + // Replace private node + const nodePosix = Path.toPosix(priv.path, { absolute: true }) + const node = result.rootDir.asNode() + + this.#privateNodes[nodePosix] = { + node, + path: priv.path, + } + } + + // ㊙️ + + #publicContext(): Queries.PublicContext { + return { + blockStore: this.#blockStore, + rootTree: this.#rootTree, + } + } + + #privateContext(): Queries.PrivateContext { + return { + blockStore: this.#blockStore, + privateNodes: this.#privateNodes, + rng: this.#rng, + rootTree: this.#rootTree, + } + } +} diff --git a/packages/nest/src/types.ts b/packages/nest/src/types.ts new file mode 100644 index 0000000..2abf9e3 --- /dev/null +++ b/packages/nest/src/types.ts @@ -0,0 +1,110 @@ +import type { CID } from 'multiformats' +import type * as Path from './path/index.js' + +/** @group File System */ +export type AnySupportedDataType = + | Uint8Array + | Record + | string + +/** @group File System */ +export interface DataRootChange { + dataRoot: CID + publishingStatus: Promise +} + +/** @group File System */ +export type DataType = 'bytes' | 'json' | 'utf8' + +/** @group File System */ +export type DataForType = D extends 'bytes' + ? Uint8Array + : D extends 'json' + ? Record + : D extends 'utf8' + ? string + : never + +/** @group File System */ +export interface DirectoryItem { + metadata: { created: number; modified: number } + name: string +} + +/** @group File System */ +export type DirectoryItemWithKind = DirectoryItem & { + kind: Path.Kind + path: Path.Distinctive> +} + +/** @group File System */ +export interface MutationOptions { + skipPublish?: boolean +} + +/** @group File System */ +export type MutationResult

= P extends Path.Public + ? PublicMutationResult + : P extends Path.Private + ? PrivateMutationResult + : never + +/** @group File System */ +export type MutationType = 'added-or-updated' | 'removed' + +/** @group File System */ +export type PartitionDiscovery

= P extends Path.Public + ? { + name: 'public' + path: Path.File> + segments: Path.Segments + } + : P extends Path.Private + ? { + name: 'private' + path: Path.File> + segments: Path.Segments + } + : never + +/** @group File System */ +export type PartitionDiscoveryNonEmpty

= + P extends Path.Public + ? { + name: 'public' + path: Path.File> + segments: Path.Segments + } + : P extends Path.Private + ? { + name: 'private' + path: Path.File> + segments: Path.Segments + } + : never + +/** @group File System */ +export type PublicMutationResult = DataRootChange & { + capsuleCID: CID + contentCID: CID +} + +/** @group File System */ +export type PrivateMutationResult = DataRootChange & { + capsuleKey: Uint8Array +} + +/** @group File System */ +export interface TransactionResult { + changes: Array<{ + path: Path.Distinctive> + type: MutationType + }> + dataRoot: CID + publishingStatus: Promise +} + +/** @group File System */ +export type PublishingStatus = + | { persisted: true } + | { persisted: false; reason: string } diff --git a/packages/nest/src/types/internal.ts b/packages/nest/src/types/internal.ts new file mode 100644 index 0000000..5dd2864 --- /dev/null +++ b/packages/nest/src/types/internal.ts @@ -0,0 +1,28 @@ +import type { + PrivateDirectory, + PrivateForest, + PrivateNode, + PublicDirectory, +} from 'wnfs' +import type * as Path from '../path/index.js' + +// 🧩 + +export type MountedPrivateNodes = Record + +export interface MountedPrivateNode { + node: PrivateNode + path: Path.Distinctive +} + +export type PrivateNodeQueryResult = MountedPrivateNode & { + remainder: Path.Segments +} + +export interface WnfsPrivateResult { + rootDir: PrivateDirectory + forest: PrivateForest +} +export interface WnfsPublicResult { + rootDir: PublicDirectory +} diff --git a/packages/nest/src/types/params.ts b/packages/nest/src/types/params.ts new file mode 100644 index 0000000..168d375 --- /dev/null +++ b/packages/nest/src/types/params.ts @@ -0,0 +1,5 @@ +export interface RecoverFileSystemParams { + newUsername: string + oldUsername: string + readKey: Uint8Array +} diff --git a/packages/nest/src/version.ts b/packages/nest/src/version.ts new file mode 100644 index 0000000..de31e9b --- /dev/null +++ b/packages/nest/src/version.ts @@ -0,0 +1,20 @@ +import { compare, satisfies } from 'compare-versions' + +export const isSupported = ( + fsVersion: string +): true | 'too-high' | 'too-low' => { + if (satisfies(fsVersion, `^${latest}`)) { + return true + } else if (compare(fsVersion, latest, '>')) { + return 'too-high' + } + + return 'too-low' +} + +// VERSIONS + +export const v1 = '1.0.0' +export const latest = v1 + +export const supported = [latest] diff --git a/packages/nest/test/class.test.ts b/packages/nest/test/class.test.ts new file mode 100644 index 0000000..013c195 --- /dev/null +++ b/packages/nest/test/class.test.ts @@ -0,0 +1,1081 @@ +import assert from 'assert' +import { + assertUnixFsDirectory, + assertUnixFsFile, + assertUnixNodeRemoval, +} from '../../tests/helpers/filesystem.js' + +import * as Path from '../src/path/index.js' +import * as Unix from './unix.js' + +import { + account, + agent, + authority, + depot, + identifier, + manners, + storage, +} from '../../tests/helpers/components.js' +import { CID } from '../common/cid.js' +import { Inventory } from '../inventory.js' +import { Ticket } from '../ticket/types.js' +import { FileSystem } from './class.js' + +describe('File System Class', async () => { + let fs: FileSystem + let mounts: { + path: Path.Distinctive + capsuleKey: Uint8Array + }[] + + const fsOpts = { + dependencies: { account, agent, depot, identifier, manners }, + settleTimeBeforePublish: 250, + } + + // HOOKS + // ----- + + beforeEach(async () => { + const did = await identifier.did() + const cidLog = await CIDLog.create({ did, storage }) + + const cabinet = await Cabinet.create({ storage }) + const inventory = new Inventory(authority.clerk, cabinet) + + const updateDataRoot = async ( + dataRoot: CID, + proofs: Ticket[] + ): Promise<{ updated: true } | { updated: false; reason: string }> => { + return { updated: true } + } + + fs = await FileSystem.empty({ + ...fsOpts, + cidLog, + did, + inventory, + updateDataRoot, + }) + + mounts = await fs.mountPrivateNodes([{ path: Path.root() }]) + + await cabinet.addTicket( + 'file_system', + await authority.clerk.tickets.fileSystem.create(Path.root(), did) + ) + }) + + // LOADING + // ------- + + it('loads a file system and capsule keys + content cids', async () => { + const publicPath = Path.file('public', 'nested-public', 'public.txt') + const privatePath = Path.file('private', 'nested-private', 'private.txt') + + const { contentCID } = await fs.write(publicPath, 'utf8', 'public') + const { capsuleKey, dataRoot } = await fs.write( + privatePath, + 'utf8', + 'private' + ) + + const contentBytes = await Unix.exportFile(contentCID, depot) + + assert.equal(new TextDecoder().decode(contentBytes), 'public') + + const did = await identifier.did() + const cidLog = await CIDLog.create({ did, storage }) + + const cabinet = await Cabinet.create({ storage }) + const inventory = new Inventory(authority.clerk, cabinet) + + const loadedFs = await FileSystem.fromCID(dataRoot, { + ...fsOpts, + cidLog, + did, + inventory, + }) + await loadedFs.mountPrivateNodes([ + // TODO: Needs to be fixed in rs-wnfs + // { path: Path.removePartition(privatePath), capsuleKey }, + { path: Path.root(), capsuleKey: mounts[0].capsuleKey }, + ]) + + assert.equal(await loadedFs.read(publicPath, 'utf8'), 'public') + assert.equal(await loadedFs.read(privatePath, 'utf8'), 'private') + }) + + it('loads a file system and capsule keys + content cids after multiple changes', async () => { + const publicPath = Path.file('public', 'nested-public', 'public.txt') + const privatePath = Path.file('private', 'nested-private', 'private.txt') + + await fs.write(publicPath, 'utf8', 'public') + await fs.write(privatePath, 'utf8', 'private') + + await fs.write(Path.file('public', 'part.two'), 'utf8', 'public-2') + const { dataRoot } = await fs.write( + Path.file('private', 'part.two'), + 'utf8', + 'private-2' + ) + const capsuleKey = await fs.capsuleKey(Path.directory('private')) + + const did = await identifier.did() + const cidLog = await CIDLog.create({ did, storage }) + + const cabinet = await Cabinet.create({ storage }) + const inventory = new Inventory(authority.clerk, cabinet) + + const loadedFs = await FileSystem.fromCID(dataRoot, { + ...fsOpts, + cidLog, + did, + inventory, + }) + + if (capsuleKey) { + await loadedFs.mountPrivateNodes([{ path: Path.root(), capsuleKey }]) + } else { + throw new Error('Expected a capsule key') + } + + assert.equal(await loadedFs.read(publicPath, 'utf8'), 'public') + assert.equal(await loadedFs.read(privatePath, 'utf8'), 'private') + }) + + it('loads a private file system given an older capsule key', async () => { + const privatePath = Path.file('private', 'nested-private', 'private.txt') + const oldCapsuleKey = await fs.capsuleKey(Path.directory('private')) + + const did = await identifier.did() + const cidLog = await CIDLog.create({ did, storage }) + + const cabinet = await Cabinet.create({ storage }) + const inventory = new Inventory(authority.clerk, cabinet) + + const { dataRoot } = await fs.write(privatePath, 'utf8', 'private') + const loadedFs = await FileSystem.fromCID(dataRoot, { + ...fsOpts, + cidLog, + did, + inventory, + }) + + if (oldCapsuleKey) { + await loadedFs.mountPrivateNodes([ + { path: Path.root(), capsuleKey: oldCapsuleKey }, + ]) + } else { + throw new Error('Expected a capsule key') + } + + assert.equal(await loadedFs.read(privatePath, 'utf8'), 'private') + + await loadedFs.write(privatePath, 'utf8', 'new content') + + assert.equal(await loadedFs.read(privatePath, 'utf8'), 'new content') + }) + + // READING & WRITING + // ----------------- + + it('writes and reads public files', async () => { + const path = Path.file('public', 'a') + const bytes = new TextEncoder().encode('🚀') + + const { contentCID } = await fs.write(path, 'bytes', bytes) + + assert.equal(await fs.read(path, 'utf8'), '🚀') + await assertUnixFsFile(fsOpts, fs, path, bytes) + }) + + it('writes and reads private files', async () => { + const path = Path.file('private', 'a') + + const { capsuleKey } = await fs.write(path, 'json', { foo: 'bar', a: 1 }) + + assert.deepEqual(await fs.read(path, 'json'), { foo: 'bar', a: 1 }) + }) + + it('writes and reads deeply nested files', async () => { + const pathPublic = Path.file('public', 'a', 'b', 'c.txt') + const pathPrivate = Path.file('private', 'a', 'b', 'c.txt') + + await fs.write(pathPublic, 'utf8', '🌍') + await fs.write(pathPrivate, 'utf8', '🔐') + + assert.equal(await fs.exists(pathPublic), true) + assert.equal(await fs.exists(pathPrivate), true) + + await assertUnixFsFile( + fsOpts, + fs, + pathPublic, + new TextEncoder().encode('🌍') + ) + }) + + it('creates files', async () => { + await fs.write(Path.file('private', 'File'), 'utf8', '🧞') + await fs.createFile(Path.file('private', 'File'), 'utf8', '🧞') + + assert.equal(await fs.exists(Path.file('private', 'File (1)')), true) + + await fs.createFile(Path.file('private', 'File'), 'utf8', '🧞') + + assert.equal(await fs.exists(Path.file('private', 'File (2)')), true) + + await fs.createFile(Path.file('private', 'File (1)'), 'utf8', '🧞') + + assert.equal(await fs.read(Path.file('private', 'File (3)'), 'utf8'), '🧞') + }) + + it('creates files with extensions', async () => { + await fs.write(Path.file('private', 'File.7z'), 'utf8', '🧞') + await fs.createFile(Path.file('private', 'File.7z'), 'utf8', '🧞') + + assert.equal(await fs.exists(Path.file('private', 'File (1).7z')), true) + + await fs.createFile(Path.file('private', 'File.7z'), 'utf8', '🧞') + + assert.equal(await fs.exists(Path.file('private', 'File (2).7z')), true) + + await fs.createFile(Path.file('private', 'File (1).7z'), 'utf8', '🧞') + + assert.equal( + await fs.read(Path.file('private', 'File (3).7z'), 'utf8'), + '🧞' + ) + }) + + it('retrieves public content using a CID', async () => { + const { contentCID, capsuleCID } = await fs.write( + Path.file('public', 'file'), + 'utf8', + '🌍' + ) + + assert.equal(await fs.read({ contentCID }, 'utf8'), '🌍') + + assert.equal(await fs.read({ capsuleCID }, 'utf8'), '🌍') + }) + + it('retrieves private content using a capsule key', async () => { + const { capsuleKey } = await fs.write( + Path.file('private', 'file'), + 'utf8', + '🔐' + ) + + assert.equal(await fs.read({ capsuleKey }, 'utf8'), '🔐') + }) + + // DIRECTORIES + // ----------- + + it('ensures directories and checks for existence', async () => { + await fs.ensureDirectory(Path.directory('public', 'a')) + await fs.ensureDirectory(Path.directory('public', 'a', 'b')) + await fs.ensureDirectory(Path.directory('public', 'a', 'b', 'c')) + + await fs.ensureDirectory(Path.directory('private', 'a')) + await fs.ensureDirectory(Path.directory('private', 'a', 'b')) + await fs.ensureDirectory(Path.directory('private', 'a', 'b', 'c')) + + assert.equal(await fs.exists(Path.directory('public', 'a')), true) + assert.equal(await fs.exists(Path.directory('public', 'a', 'b')), true) + assert.equal(await fs.exists(Path.directory('public', 'a', 'b', 'c')), true) + + assert.equal(await fs.exists(Path.directory('private', 'a')), true) + assert.equal(await fs.exists(Path.directory('private', 'a', 'b')), true) + assert.equal( + await fs.exists(Path.directory('private', 'a', 'b', 'c')), + true + ) + + // Does not throw for existing dirs + await fs.ensureDirectory(Path.directory('public', 'a')) + await fs.ensureDirectory(Path.directory('public', 'a', 'b')) + + await fs.ensureDirectory(Path.directory('private', 'a')) + await fs.ensureDirectory(Path.directory('private', 'a', 'b')) + + await assertUnixFsDirectory(fsOpts, fs, Path.directory('public', 'a')) + await assertUnixFsDirectory(fsOpts, fs, Path.directory('public', 'a', 'b')) + }) + + it('lists public directories', async () => { + await fs.ensureDirectory(Path.directory('public', 'a')) + await fs.write(Path.file('public', 'a-file'), 'utf8', '🧞') + await fs.ensureDirectory(Path.directory('public', 'a', 'b')) + await fs.write(Path.file('public', 'a', 'b-file'), 'utf8', '💃') + + const a = await fs.listDirectory(Path.directory('public')) + assert.deepEqual( + a.map((i) => i.name), + ['a', 'a-file'] + ) + + const b = await fs.listDirectory(Path.directory('public', 'a')) + assert.deepEqual( + b.map((i) => i.name), + ['b', 'b-file'] + ) + }) + + it('lists public directories with item kind', async () => { + const pathDirA = Path.directory('public', 'a') + const pathFileA = Path.file('public', 'a-file') + const pathDirB = Path.directory('public', 'a', 'b') + const pathFileB = Path.file('public', 'a', 'b-file') + + await fs.ensureDirectory(pathDirA) + await fs.write(pathFileA, 'utf8', '🧞') + await fs.ensureDirectory(pathDirB) + await fs.write(pathFileB, 'utf8', '💃') + + const a = await fs.listDirectory(Path.directory('public'), { + withItemKind: true, + }) + assert.deepEqual( + a.map((i) => i.kind), + [Path.Kind.Directory, Path.Kind.File] + ) + assert.deepEqual( + a.map((i) => i.path), + [pathDirA, pathFileA] + ) + + const b = await fs.listDirectory(Path.directory('public', 'a'), { + withItemKind: true, + }) + assert.deepEqual( + b.map((i) => i.kind), + [Path.Kind.Directory, Path.Kind.File] + ) + assert.deepEqual( + b.map((i) => i.path), + [pathDirB, pathFileB] + ) + }) + + it('lists private directories', async () => { + await fs.ensureDirectory(Path.directory('private', 'a')) + await fs.write(Path.file('private', 'a-file'), 'utf8', '🧞') + await fs.ensureDirectory(Path.directory('private', 'a', 'b')) + await fs.write(Path.file('private', 'a', 'b-file'), 'utf8', '💃') + + const a = await fs.listDirectory(Path.directory('private')) + assert.deepEqual( + a.map((i) => i.name), + ['a', 'a-file'] + ) + + const b = await fs.listDirectory(Path.directory('private', 'a')) + assert.deepEqual( + b.map((i) => i.name), + ['b', 'b-file'] + ) + }) + + it('lists private directories with item kind', async () => { + const pathDirA = Path.directory('private', 'a') + const pathFileA = Path.file('private', 'a-file') + const pathDirB = Path.directory('private', 'a', 'b') + const pathFileB = Path.file('private', 'a', 'b-file') + + await fs.ensureDirectory(pathDirA) + await fs.write(pathFileA, 'utf8', '🧞') + await fs.ensureDirectory(pathDirB) + await fs.write(pathFileB, 'utf8', '💃') + + const a = await fs.listDirectory(Path.directory('private'), { + withItemKind: true, + }) + assert.deepEqual( + a.map((i) => i.kind), + [Path.Kind.Directory, Path.Kind.File] + ) + assert.deepEqual( + a.map((i) => i.path), + [pathDirA, pathFileA] + ) + + const b = await fs.listDirectory(Path.directory('private', 'a'), { + withItemKind: true, + }) + assert.deepEqual( + b.map((i) => i.kind), + [Path.Kind.Directory, Path.Kind.File] + ) + assert.deepEqual( + b.map((i) => i.path), + [pathDirB, pathFileB] + ) + }) + + it('creates directories', async () => { + await fs.ensureDirectory(Path.directory('private', 'Directory')) + await fs.createDirectory(Path.directory('private', 'Directory')) + + assert.equal( + await fs.exists(Path.directory('private', 'Directory (1)')), + true + ) + + await fs.createDirectory(Path.directory('private', 'Directory')) + + assert.equal( + await fs.exists(Path.directory('private', 'Directory (2)')), + true + ) + + await fs.createDirectory(Path.directory('private', 'Directory (1)')) + + assert.equal( + await fs.exists(Path.directory('private', 'Directory (3)')), + true + ) + }) + + it('creates directories with extensions', async () => { + await fs.ensureDirectory(Path.directory('private', 'Directory.7z')) + await fs.createDirectory(Path.directory('private', 'Directory.7z')) + + assert.equal( + await fs.exists(Path.directory('private', 'Directory.7z (1)')), + true + ) + + await fs.createDirectory(Path.directory('private', 'Directory.7z')) + + assert.equal( + await fs.exists(Path.directory('private', 'Directory.7z (2)')), + true + ) + + await fs.createDirectory(Path.directory('private', 'Directory.7z (1)')) + + assert.equal( + await fs.exists(Path.directory('private', 'Directory.7z (3)')), + true + ) + }) + + // CIDS & REFS + // ----------- + + it('can get a content CID for an existing public file', async () => { + const path = Path.file('public', 'a', 'b', 'file') + + const { contentCID } = await fs.write(path, 'utf8', '💃') + const cid = await fs.contentCID(path) + + assert.equal(cid?.toString(), contentCID.toString()) + }) + + it('can get a capsule CID for an existing public file', async () => { + const path = Path.file('public', 'a', 'b', 'file') + + const { capsuleCID } = await fs.write(path, 'utf8', '💃') + const cid = await fs.capsuleCID(path) + + assert.equal(cid?.toString(), capsuleCID.toString()) + }) + + it('can get a capsule CID for an existing public directory', async () => { + const path = Path.directory('public', 'a', 'b', 'directory') + + const { capsuleCID } = await fs.ensureDirectory(path) + const cid = await fs.capsuleCID(path) + + assert.equal(cid?.toString(), capsuleCID.toString()) + }) + + it('can get a capsule key for an existing private file', async () => { + const path = Path.file('private', 'a', 'b', 'file') + + const { capsuleKey } = await fs.write(path, 'utf8', '💃') + const key = await fs.capsuleKey(path) + + assert.equal(key ? JSON.stringify(key) : null, JSON.stringify(capsuleKey)) + }) + + it('can get a capsule CID for an existing private directory', async () => { + const path = Path.directory('private', 'a', 'b', 'directory') + + const { capsuleKey } = await fs.ensureDirectory(path) + const key = await fs.capsuleKey(path) + + assert.equal(key ? JSON.stringify(key) : null, JSON.stringify(capsuleKey)) + }) + + it('can get a capsule CID for a mounted private directory', async () => { + const path = Path.directory('private') + const key = await fs.capsuleKey(path) + + assert.notEqual(key ? JSON.stringify(key) : null, null) + }) + + // REMOVE + // ------ + + it('removes public files', async () => { + const path = Path.file('public', 'a', 'b', 'file') + + await fs.write(path, 'utf8', '💃') + await fs.remove(path) + + assert.equal(await fs.exists(path), false) + + await assertUnixNodeRemoval(fsOpts, fs, path) + }) + + it('removes private files', async () => { + const path = Path.file('private', 'a', 'b', 'file') + + await fs.write(path, 'utf8', '💃') + await fs.remove(path) + + assert.equal(await fs.exists(path), false) + }) + + it('removes public directories', async () => { + const path = Path.directory('public', 'a', 'b', 'directory') + + await fs.ensureDirectory(path) + await fs.remove(path) + + assert.equal(await fs.exists(path), false) + + await assertUnixNodeRemoval(fsOpts, fs, path) + }) + + it('removes private directories', async () => { + const path = Path.directory('private', 'a', 'b', 'directory') + + await fs.ensureDirectory(path) + await fs.remove(path) + + assert.equal(await fs.exists(path), false) + }) + + // COPYING + // ------- + + it('copies public files', async () => { + const fromPath = Path.file('public', 'a', 'b', 'file') + const toPath = Path.file('public', 'a', 'b', 'c', 'd', 'file') + + await fs.write(fromPath, 'utf8', '💃') + await fs.copy(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + }) + + it('copies public files into a directory that already exists', async () => { + await fs.ensureDirectory(Path.directory('public', 'a', 'b', 'c', 'd')) + + const fromPath = Path.file('public', 'a', 'b', 'file') + const toPath = Path.file('public', 'a', 'b', 'c', 'd', 'file') + + await fs.write(fromPath, 'utf8', '💃') + await fs.copy(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + }) + + it('copies private files', async () => { + const fromPath = Path.file('private', 'a', 'b', 'file') + const toPath = Path.file('private', 'a', 'b', 'c', 'd', 'file') + + await fs.write(fromPath, 'utf8', '💃') + await fs.copy(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + }) + + it('copies private files into a directory that already exists', async () => { + await fs.ensureDirectory(Path.directory('private', 'a', 'b', 'c', 'd')) + + const fromPath = Path.file('private', 'a', 'b', 'file') + const toPath = Path.file('private', 'a', 'b', 'c', 'd', 'file') + + await fs.write(fromPath, 'utf8', '💃') + await fs.copy(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + }) + + it('copies public directories', async () => { + const fromPath = Path.directory('public', 'b', 'c') + const toPath = Path.directory('public', 'a', 'b', 'c', 'd', 'e') + + await fs.write(Path.combine(fromPath, Path.file('file')), 'utf8', '💃') + await fs.write( + Path.combine(fromPath, Path.file('nested', 'file')), + 'utf8', + '🧞' + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-empty')) + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-2', 'deeply-nested')) + ) + + await fs.copy(fromPath, toPath) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('file')), 'utf8'), + '💃' + ) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('nested', 'file')), 'utf8'), + '🧞' + ) + + assert.equal( + await fs.exists(Path.combine(toPath, Path.directory('nested-empty'))), + true + ) + + assert.equal( + await fs.exists( + Path.combine(toPath, Path.directory('nested-2', 'deeply-nested')) + ), + true + ) + + await fs.copy(Path.directory('public', 'a', 'b'), Path.directory('public')) + + assert.equal( + await fs.exists( + Path.directory('public', 'b', 'c', 'nested-2', 'deeply-nested') + ), + true + ) + }) + + it('copies private directories', async () => { + const fromPath = Path.directory('private', 'b', 'c') + const toPath = Path.directory('private', 'a', 'b', 'c', 'd', 'e') + + await fs.write(Path.combine(fromPath, Path.file('file')), 'utf8', '💃') + await fs.write( + Path.combine(fromPath, Path.file('nested', 'file')), + 'utf8', + '🧞' + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-empty')) + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-2', 'deeply-nested')) + ) + + await fs.copy(fromPath, toPath) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('file')), 'utf8'), + '💃' + ) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('nested', 'file')), 'utf8'), + '🧞' + ) + + assert.equal( + await fs.exists(Path.combine(toPath, Path.directory('nested-empty'))), + true + ) + + assert.equal( + await fs.exists( + Path.combine(toPath, Path.directory('nested-2', 'deeply-nested')) + ), + true + ) + + await fs.copy(Path.directory('private', 'a'), Path.directory('private')) + + assert.equal( + await fs.exists( + Path.directory('private', 'b', 'c', 'nested-2', 'deeply-nested') + ), + true + ) + }) + + // MOVING + // ------ + + it('moves public files', async () => { + const fromPath = Path.file('public', 'a', 'b', 'file') + const toPath = Path.file('public', 'a', 'b', 'c', 'd', 'file') + + await fs.write(fromPath, 'utf8', '💃') + await fs.move(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + assert.equal(await fs.exists(fromPath), false) + }) + + it('moves private files', async () => { + const fromPath = Path.file('private', 'a', 'b', 'file') + const toPath = Path.file('private', 'a', 'b', 'c', 'd', 'file') + + await fs.write(fromPath, 'utf8', '💃') + await fs.move(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + assert.equal(await fs.exists(fromPath), false) + }) + + it('moves public directories', async () => { + const fromPath = Path.directory('public', 'b', 'c') + const toPath = Path.directory('public', 'a', 'b', 'c', 'd', 'e') + + await fs.write(Path.combine(fromPath, Path.file('file')), 'utf8', '💃') + await fs.write( + Path.combine(fromPath, Path.file('nested', 'file')), + 'utf8', + '🧞' + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-empty')) + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-2', 'deeply-nested')) + ) + + await fs.move(fromPath, toPath) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('file')), 'utf8'), + '💃' + ) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('nested', 'file')), 'utf8'), + '🧞' + ) + + assert.equal( + await fs.exists(Path.combine(toPath, Path.directory('nested-empty'))), + true + ) + + assert.equal( + await fs.exists( + Path.combine(toPath, Path.directory('nested-2', 'deeply-nested')) + ), + true + ) + + assert.equal(await fs.exists(fromPath), false) + + await fs.move(Path.directory('public', 'a'), Path.directory('public')) + + assert.equal( + await fs.exists( + Path.directory('public', 'b', 'c', 'nested-2', 'deeply-nested') + ), + false + ) + + assert.equal(await fs.exists(Path.directory('public', 'a')), false) + + assert.equal( + await fs.exists( + Path.directory( + 'public', + 'a', + 'b', + 'c', + 'd', + 'e', + 'nested-2', + 'deeply-nested' + ) + ), + false + ) + }) + + it('moves private directories', async () => { + const fromPath = Path.directory('private', 'b', 'c') + const toPath = Path.directory('private', 'a', 'b', 'c', 'd', 'e') + + await fs.write(Path.combine(fromPath, Path.file('file')), 'utf8', '💃') + await fs.write( + Path.combine(fromPath, Path.file('nested', 'file')), + 'utf8', + '🧞' + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-empty')) + ) + await fs.ensureDirectory( + Path.combine(fromPath, Path.directory('nested-2', 'deeply-nested')) + ) + + await fs.move(fromPath, toPath) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('file')), 'utf8'), + '💃' + ) + + assert.equal( + await fs.read(Path.combine(toPath, Path.file('nested', 'file')), 'utf8'), + '🧞' + ) + + assert.equal( + await fs.exists(Path.combine(toPath, Path.directory('nested-empty'))), + true + ) + + assert.equal( + await fs.exists( + Path.combine(toPath, Path.directory('nested-2', 'deeply-nested')) + ), + true + ) + + assert.equal(await fs.exists(fromPath), false) + + await fs.move(Path.directory('private', 'a'), Path.directory('private')) + + assert.equal( + await fs.exists( + Path.directory('public', 'b', 'c', 'nested-2', 'deeply-nested') + ), + false + ) + + assert.equal(await fs.exists(Path.directory('public', 'a')), false) + + assert.equal( + await fs.exists( + Path.directory( + 'public', + 'a', + 'b', + 'c', + 'd', + 'e', + 'nested-2', + 'deeply-nested' + ) + ), + false + ) + }) + + it('moves a public file to the private partition', async () => { + const fromPath = Path.file('public', 'a', 'b', 'file') + const toPath = Path.file('private', 'a', 'b', 'c', 'd', 'file') + + const { capsuleCID } = await fs.write(fromPath, 'utf8', '💃') + const { capsuleKey } = await fs.move(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + assert.equal(await fs.exists(fromPath), false) + }) + + it('moves a private file to the public partition', async () => { + const fromPath = Path.file('private', 'a', 'b', 'file') + const toPath = Path.file('public', 'a', 'b', 'c', 'd', 'file') + + const { capsuleKey } = await fs.write(fromPath, 'utf8', '💃') + const { capsuleCID } = await fs.move(fromPath, toPath) + + assert.equal(await fs.read(toPath, 'utf8'), '💃') + assert.equal(await fs.exists(fromPath), false) + }) + + // RENAMING + // -------- + + it('renames public files', async () => { + await fs.write(Path.file('public', 'a'), 'bytes', new Uint8Array()) + await fs.rename(Path.file('public', 'a'), 'b') + + assert.equal(await fs.exists(Path.file('public', 'a')), false) + + assert.equal(await fs.exists(Path.file('public', 'b')), true) + }) + + it('renames private files', async () => { + await fs.write(Path.file('private', 'a'), 'bytes', new Uint8Array()) + await fs.rename(Path.file('private', 'a'), 'b') + + assert.equal(await fs.exists(Path.file('private', 'a')), false) + + assert.equal(await fs.exists(Path.file('private', 'b')), true) + }) + + it('renames public directories', async () => { + await fs.ensureDirectory(Path.directory('public', 'a')) + await fs.rename(Path.directory('public', 'a'), 'b') + + assert.equal(await fs.exists(Path.directory('public', 'a')), false) + + assert.equal(await fs.exists(Path.directory('public', 'b')), true) + }) + + it('renames private directories', async () => { + await fs.ensureDirectory(Path.directory('private', 'a')) + await fs.rename(Path.directory('private', 'a'), 'b') + + assert.equal(await fs.exists(Path.directory('private', 'a')), false) + + assert.equal(await fs.exists(Path.directory('private', 'b')), true) + }) + + // PUBLISHING + // ---------- + + it('publishes & debounces by default', async () => { + await new Promise((resolve) => + setTimeout(resolve, fsOpts.settleTimeBeforePublish * 1.5) + ) + + const promise: Promise = new Promise((resolve, reject) => { + setTimeout(reject, 10000) + fs.once('publish') + .then((event) => event.dataRoot) + .then(resolve, reject) + }) + + const a = await fs.write( + Path.file('private', 'a'), + 'bytes', + new Uint8Array() + ) + const b = await fs.write( + Path.file('private', 'b'), + 'bytes', + new Uint8Array() + ) + const c = await fs.write( + Path.file('private', 'c'), + 'bytes', + new Uint8Array() + ) + const d = await fs.write( + Path.file('private', 'd'), + 'bytes', + new Uint8Array() + ) + + assert.equal((await promise).toString(), d.dataRoot.toString()) + + assert.equal((await a.publishingStatus).persisted, true) + assert.equal((await b.publishingStatus).persisted, true) + assert.equal((await c.publishingStatus).persisted, true) + assert.equal((await d.publishingStatus).persisted, true) + }) + + it("doesn't publish when asked not to do so", async () => { + let published = false + + fs.on('publish', () => { + published = true + }) + + await fs.mkdir(Path.directory('private', 'dir'), { skipPublish: true }) + await fs.write(Path.file('public', 'file'), 'bytes', new Uint8Array(), { + skipPublish: true, + }) + await fs.cp(Path.file('public', 'file'), Path.file('private', 'file'), { + skipPublish: true, + }) + await fs.mv( + Path.file('private', 'file'), + Path.file('private', 'dir', 'file'), + { skipPublish: true } + ) + await fs.rename(Path.file('private', 'dir', 'file'), 'renamed', { + skipPublish: true, + }) + await fs.rm(Path.file('private', 'dir', 'renamed'), { skipPublish: true }) + + await new Promise((resolve) => + setTimeout(resolve, fsOpts.settleTimeBeforePublish * 1.5) + ) + + assert.equal(published, false) + }) + + // EVENTS + // ------ + // Other than "publish" + + it('emits an event for a mutation', async () => { + const eventPromise: Promise = new Promise((resolve, reject) => { + setTimeout(reject, 10000) + + fs.on('local-change', ({ dataRoot }) => { + resolve(dataRoot) + }) + }) + + const mutationResult = await fs.write( + Path.file('private', 'file'), + 'bytes', + new Uint8Array() + ) + + assert.equal( + (await eventPromise).toString(), + mutationResult.dataRoot.toString() + ) + }) + + // TRANSACTIONS + // ------------ + + it('commits a transaction', async () => { + await fs.transaction(async (t) => { + await t.write(Path.file('private', 'file'), 'utf8', '💃') + await t.write( + Path.file('public', 'file'), + 'bytes', + await t.read(Path.file('private', 'file'), 'bytes') + ) + }) + + assert.equal(await fs.read(Path.file('public', 'file'), 'utf8'), '💃') + }) + + it("doesn't commit a transaction when an error occurs inside of the transaction", async () => { + const tracker = new assert.CallTracker() + + async function transaction() { + await fs + .transaction(async (t) => { + await t.write(Path.file('private', 'file'), 'utf8', '💃') + throw new Error('Whoops') + }) + .catch((e) => {}) + } + + const tracked = tracker.calls(transaction, 1) + + await tracked() + tracker.verify() + + try { + await fs.read(Path.file('private', 'file'), 'utf8') + } catch (e) { + assert(e) + } + }) +}) diff --git a/packages/nest/tsconfig.json b/packages/nest/tsconfig.json new file mode 100644 index 0000000..dd412b7 --- /dev/null +++ b/packages/nest/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "module": "NodeNext", + "moduleResolution": "NodeNext" + }, + "include": [ + "src", + "test" + ], + "exclude": [ + "node_modules", + "dist", + "out" + ], + "typedocOptions": { + "entryPoints": [ + "src/index.js", + "src/module1.js" + ], + "includeVersion": true, + "excludeExternals": true, + "internalModule": "" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..410e236 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,5495 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@fission-codes/eslint-config': + specifier: ^0.0.3 + version: 0.0.3 + depcheck: + specifier: ^1.4.7 + version: 1.4.7 + lint-staged: + specifier: ^15.1.0 + version: 15.1.0 + prettier: + specifier: 3.1.0 + version: 3.1.0 + simple-git-hooks: + specifier: ^2.9.0 + version: 2.9.0 + typedoc: + specifier: ^0.25.3 + version: 0.25.3(typescript@5.2.2) + typedoc-plugin-missing-exports: + specifier: ^2.1.0 + version: 2.1.0(typedoc@0.25.3) + typedoc-plugin-zod: + specifier: ^1.1.0 + version: 1.1.0(typedoc@0.25.3) + typescript: + specifier: 5.2.2 + version: 5.2.2 + + examples/demo: + dependencies: + package1: + specifier: '*' + version: link:../../packages/nest + devDependencies: + '@babel/core': + specifier: ^7.23.3 + version: 7.23.3 + '@types/node': + specifier: ^20.9.0 + version: 20.9.0 + typescript: + specifier: 5.2.2 + version: 5.2.2 + vite: + specifier: ^4.5.0 + version: 4.5.0(@types/node@20.9.0) + + packages/nest: + dependencies: + '@ipld/dag-cbor': + specifier: ^9.0.6 + version: 9.0.6 + '@ipld/dag-pb': + specifier: ^4.0.6 + version: 4.0.6 + compare-versions: + specifier: ^6.1.0 + version: 6.1.0 + interface-blockstore: + specifier: ^5.2.7 + version: 5.2.7 + ipfs-unixfs: + specifier: ^11.1.0 + version: 11.1.0 + ipfs-unixfs-exporter: + specifier: ^13.2.2 + version: 13.2.2 + ipfs-unixfs-importer: + specifier: ^15.2.1 + version: 15.2.1 + iso-base: + specifier: ^2.0.1 + version: 2.0.1 + it-all: + specifier: ^3.0.4 + version: 3.0.4 + multiformats: + specifier: ^12.1.3 + version: 12.1.3 + uint8arrays: + specifier: ^4.0.9 + version: 4.0.9 + wnfs: + specifier: ^0.1.27 + version: 0.1.27 + devDependencies: + '@types/assert': + specifier: ^1.5.9 + version: 1.5.9 + '@types/mocha': + specifier: ^10.0.4 + version: 10.0.4 + '@types/node': + specifier: ^20.9.0 + version: 20.9.0 + assert: + specifier: ^2.1.0 + version: 2.1.0 + mocha: + specifier: ^10.2.0 + version: 10.2.0 + playwright-test: + specifier: ^12.6.0 + version: 12.6.0 + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@arr/every@1.0.1: + resolution: {integrity: sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==} + engines: {node: '>=4'} + dev: true + + /@assemblyscript/loader@0.9.4: + resolution: {integrity: sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA==} + dev: false + + /@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.20 + chalk: 2.4.2 + dev: true + + /@babel/compat-data@7.23.3: + resolution: {integrity: sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.23.3: + resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.3 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3) + '@babel/helpers': 7.23.2 + '@babel/parser': 7.23.3 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.3 + '@babel/types': 7.23.3 + convert-source-map: 2.0.0 + debug: 4.3.4(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.23.0: + resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + dev: true + + /@babel/generator@7.23.3: + resolution: {integrity: sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + dev: true + + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.3 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.22.1 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.23.0 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.3 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + dev: true + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.23.2: + resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.3 + '@babel/types': 7.23.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser@7.23.0: + resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.0 + dev: true + + /@babel/parser@7.23.3: + resolution: {integrity: sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.3 + dev: true + + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.23.3 + '@babel/types': 7.23.3 + dev: true + + /@babel/traverse@7.23.2: + resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 + debug: 4.3.4(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/traverse@7.23.3: + resolution: {integrity: sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.3 + '@babel/types': 7.23.3 + debug: 4.3.4(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.23.0: + resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@babel/types@7.23.3: + resolution: {integrity: sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@es-joy/jsdoccomment@0.40.1: + resolution: {integrity: sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg==} + engines: {node: '>=16'} + dependencies: + comment-parser: 1.4.0 + esquery: 1.5.0 + jsdoc-type-pratt-parser: 4.0.0 + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.5: + resolution: {integrity: sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.5: + resolution: {integrity: sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.5: + resolution: {integrity: sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.5: + resolution: {integrity: sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.5: + resolution: {integrity: sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.5: + resolution: {integrity: sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.5: + resolution: {integrity: sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.5: + resolution: {integrity: sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.5: + resolution: {integrity: sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.5: + resolution: {integrity: sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.5: + resolution: {integrity: sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.5: + resolution: {integrity: sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.5: + resolution: {integrity: sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.5: + resolution: {integrity: sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.5: + resolution: {integrity: sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.5: + resolution: {integrity: sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.5: + resolution: {integrity: sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.5: + resolution: {integrity: sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.5: + resolution: {integrity: sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.5: + resolution: {integrity: sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.5: + resolution: {integrity: sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.5: + resolution: {integrity: sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.52.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.52.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4(supports-color@8.1.1) + espree: 9.6.1 + globals: 13.23.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.52.0: + resolution: {integrity: sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@fission-codes/eslint-config@0.0.3: + resolution: {integrity: sha512-yyCd36LKx2K7XKdLDl5jEryUuKIkY3tvgBvfqVSffcRZ+r+lMx7UHJH5uaIj3Z05L899TJ/xkFlHlmlv0Jev3Q==} + dependencies: + '@typescript-eslint/eslint-plugin': 6.9.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + eslint: 8.52.0 + eslint-config-prettier: 9.0.0(eslint@8.52.0) + eslint-config-standard: 17.1.0(eslint-plugin-import@2.29.0)(eslint-plugin-n@16.2.0)(eslint-plugin-promise@6.1.1)(eslint@8.52.0) + eslint-config-standard-with-typescript: 39.1.1(@typescript-eslint/eslint-plugin@6.9.0)(eslint-plugin-import@2.29.0)(eslint-plugin-n@16.2.0)(eslint-plugin-promise@6.1.1)(eslint@8.52.0)(typescript@5.2.2) + eslint-plugin-eslint-comments: 3.2.0(eslint@8.52.0) + eslint-plugin-etc: 2.0.3(eslint@8.52.0)(typescript@5.2.2) + eslint-plugin-html: 7.1.0 + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0) + eslint-plugin-jsdoc: 46.8.2(eslint@8.52.0) + eslint-plugin-jsonc: 2.10.0(eslint@8.52.0) + eslint-plugin-markdown: 3.0.1(eslint@8.52.0) + eslint-plugin-n: 16.2.0(eslint@8.52.0) + eslint-plugin-no-only-tests: 3.1.0 + eslint-plugin-promise: 6.1.1(eslint@8.52.0) + eslint-plugin-react: 7.33.2(eslint@8.52.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.52.0) + eslint-plugin-unicorn: 48.0.1(eslint@8.52.0) + eslint-plugin-yml: 1.10.0(eslint@8.52.0) + typescript: 5.2.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.1 + debug: 4.3.4(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + dev: true + + /@ipld/dag-cbor@9.0.6: + resolution: {integrity: sha512-3kNab5xMppgWw6DVYx2BzmFq8t7I56AGWfp5kaU1fIPkwHVpBRglJJTYsGtbVluCi/s/q97HZM3bC+aDW4sxbQ==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + cborg: 4.0.5 + multiformats: 12.1.3 + dev: false + + /@ipld/dag-pb@4.0.6: + resolution: {integrity: sha512-wOij3jfDKZsb9yjhQeHp+TQy0pu1vmUkGv324xciFFZ7xGbDfAGTQW03lSA5aJ/7HBBNYgjEE0nvHmNW1Qjfag==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + multiformats: 12.1.3 + dev: false + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@multiformats/murmur3@2.1.7: + resolution: {integrity: sha512-Yf0UpAaONjed+8PTt5NM/GG4Z4Ai4m1qfT7bqevjnkwRQ12K+0jxtRomirz+VJx4PokpA2St1ZSD1iMkZTqPRQ==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + multiformats: 12.1.3 + murmurhash3js-revisited: 3.0.0 + dev: false + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@phenomnomnominal/tsquery@5.0.1(typescript@5.2.2): + resolution: {integrity: sha512-3nVv+e2FQwsW8Aw6qTU6f+1rfcJ3hrcnvH/mu9i8YhxO+9sqbOfpL8m6PbET5+xKOlz/VSbp0RoYWYCtIsnmuA==} + peerDependencies: + typescript: ^3 || ^4 || ^5 + dependencies: + esquery: 1.5.0 + typescript: 5.2.2 + dev: true + + /@polka/url@0.5.0: + resolution: {integrity: sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==} + dev: true + + /@polka/url@1.0.0-next.23: + resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==} + dev: true + + /@types/assert@1.5.9: + resolution: {integrity: sha512-uQ+/hp0DbfrhnJFgiqHlsrLTGgr8HZGssV7vYN8XunlvyJkzArcyBy/9e5Rey2T7lpL7jVuoNI/8CWCDCwISgg==} + dev: true + + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + dev: true + + /@types/json-schema@7.0.14: + resolution: {integrity: sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/mdast@3.0.14: + resolution: {integrity: sha512-gVZ04PGgw1qLZKsnWnyFv4ORnaJ+DXLdHTVSFbU8yX6xZ34Bjg4Q32yPkmveUP1yItXReKfB0Aknlh/3zxTKAw==} + dependencies: + '@types/unist': 2.0.9 + dev: true + + /@types/minimatch@3.0.5: + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + dev: true + + /@types/mocha@10.0.4: + resolution: {integrity: sha512-xKU7bUjiFTIttpWaIZ9qvgg+22O1nmbA+HRxdlR+u6TWsGfmFdXrheJoK4fFxrHNVIOBDvDNKZG+LYBpMHpX3w==} + dev: true + + /@types/node@20.9.0: + resolution: {integrity: sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/normalize-package-data@2.4.3: + resolution: {integrity: sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==} + dev: true + + /@types/parse-json@4.0.1: + resolution: {integrity: sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng==} + dev: true + + /@types/semver@7.5.4: + resolution: {integrity: sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==} + dev: true + + /@types/unist@2.0.9: + resolution: {integrity: sha512-zC0iXxAv1C1ERURduJueYzkzZ2zaGyc+P2c95hgkikHPr3z8EdUZOlgEQ5X0DRmwDZn+hekycQnoeiiRVrmilQ==} + dev: true + + /@types/yargs-parser@21.0.2: + resolution: {integrity: sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==} + dev: true + + /@types/yargs@17.0.29: + resolution: {integrity: sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA==} + dependencies: + '@types/yargs-parser': 21.0.2 + dev: true + + /@typescript-eslint/eslint-plugin@6.9.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.9.0 + '@typescript-eslint/type-utils': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.9.0 + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.52.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/experimental-utils@5.62.0(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@typescript-eslint/utils': 5.62.0(eslint@8.52.0)(typescript@5.2.2) + eslint: 8.52.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/parser@6.9.0(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.9.0 + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/typescript-estree': 6.9.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.9.0 + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.52.0 + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + dev: true + + /@typescript-eslint/scope-manager@6.9.0: + resolution: {integrity: sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/visitor-keys': 6.9.0 + dev: true + + /@typescript-eslint/type-utils@6.9.0(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.9.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.52.0 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/types@6.9.0: + resolution: {integrity: sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.2.2): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.4(supports-color@8.1.1) + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@6.9.0(typescript@5.2.2): + resolution: {integrity: sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/visitor-keys': 6.9.0 + debug: 4.3.4(supports-color@8.1.1) + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.62.0(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + '@types/json-schema': 7.0.14 + '@types/semver': 7.5.4 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) + eslint: 8.52.0 + eslint-scope: 5.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@6.9.0(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + '@types/json-schema': 7.0.14 + '@types/semver': 7.5.4 + '@typescript-eslint/scope-manager': 6.9.0 + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/typescript-estree': 6.9.0(typescript@5.2.2) + eslint: 8.52.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@6.9.0: + resolution: {integrity: sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.9.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /@vue/compiler-core@3.3.7: + resolution: {integrity: sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==} + dependencies: + '@babel/parser': 7.23.0 + '@vue/shared': 3.3.7 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + dev: true + + /@vue/compiler-dom@3.3.7: + resolution: {integrity: sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==} + dependencies: + '@vue/compiler-core': 3.3.7 + '@vue/shared': 3.3.7 + dev: true + + /@vue/compiler-sfc@3.3.7: + resolution: {integrity: sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==} + dependencies: + '@babel/parser': 7.23.0 + '@vue/compiler-core': 3.3.7 + '@vue/compiler-dom': 3.3.7 + '@vue/compiler-ssr': 3.3.7 + '@vue/reactivity-transform': 3.3.7 + '@vue/shared': 3.3.7 + estree-walker: 2.0.2 + magic-string: 0.30.5 + postcss: 8.4.31 + source-map-js: 1.0.2 + dev: true + + /@vue/compiler-ssr@3.3.7: + resolution: {integrity: sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==} + dependencies: + '@vue/compiler-dom': 3.3.7 + '@vue/shared': 3.3.7 + dev: true + + /@vue/reactivity-transform@3.3.7: + resolution: {integrity: sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==} + dependencies: + '@babel/parser': 7.23.0 + '@vue/compiler-core': 3.3.7 + '@vue/shared': 3.3.7 + estree-walker: 2.0.2 + magic-string: 0.30.5 + dev: true + + /@vue/shared@3.3.7: + resolution: {integrity: sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==} + dev: true + + /acorn-jsx@5.3.2(acorn@8.11.2): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.2 + dev: true + + /acorn-loose@8.4.0: + resolution: {integrity: sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ==} + engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.11.2 + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + dev: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-colors@4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes@5.0.0: + resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-sequence-parser@1.1.1: + resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.5 + is-array-buffer: 3.0.2 + dev: true + + /array-differ@3.0.0: + resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==} + engines: {node: '>=8'} + dev: true + + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-string: 1.0.7 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + + /arrify@2.0.1: + resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} + engines: {node: '>=8'} + dev: true + + /arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + dev: true + + /assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + dependencies: + call-bind: 1.0.5 + is-nan: 1.3.2 + object-is: 1.1.5 + object.assign: 4.1.4 + util: 0.12.5 + dev: true + + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base-x@4.0.0: + resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /bigint-mod-arith@3.3.1: + resolution: {integrity: sha512-pX/cYW3dCa87Jrzv6DAr8ivbbJRzEX5yGhdt8IutnX/PCIXfpx+mabWNK/M8qqh+zQ0J3thftUBHW0ByuUlG0w==} + engines: {node: '>=10.4.0'} + dev: false + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bl@5.1.0: + resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} + dependencies: + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 3.6.2 + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + dev: true + + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001561 + electron-to-chromium: 1.4.581 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + /builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + dev: true + + /builtins@5.0.1: + resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} + dependencies: + semver: 7.5.4 + dev: true + + /c8@8.0.1: + resolution: {integrity: sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w==} + engines: {node: '>=12'} + hasBin: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@istanbuljs/schema': 0.1.3 + find-up: 5.0.0 + foreground-child: 2.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.1.6 + rimraf: 3.0.2 + test-exclude: 6.0.0 + v8-to-istanbul: 9.1.3 + yargs: 17.7.2 + yargs-parser: 21.1.1 + dev: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: true + + /callsite@1.0.0: + resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + + /camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + dev: true + + /caniuse-lite@1.0.30001561: + resolution: {integrity: sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==} + dev: true + + /cborg@4.0.5: + resolution: {integrity: sha512-q8TAjprr8pn9Fp53rOIGp/UFDdFY6os2Nq62YogPSIzczJD9M6g2b6igxMkpCiZZKJ0kn/KzDLDvG+EqBIEeCg==} + hasBin: true + dev: false + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /character-entities-legacy@1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + dev: true + + /character-entities@1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + dev: true + + /character-reference-invalid@1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /clean-regexp@1.0.0: + resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} + engines: {node: '>=4'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: true + + /cli-spinners@2.9.1: + resolution: {integrity: sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==} + engines: {node: '>=6'} + dev: true + + /cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + + /cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: true + + /comment-parser@1.4.0: + resolution: {integrity: sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==} + engines: {node: '>= 12.0.0'} + dev: true + + /compare-versions@6.1.0: + resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} + dev: false + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.1 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + + /cp-file@10.0.0: + resolution: {integrity: sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==} + engines: {node: '>=14.16'} + dependencies: + graceful-fs: 4.2.11 + nested-error-stacks: 2.1.1 + p-event: 5.0.1 + dev: true + + /cpy@10.1.0: + resolution: {integrity: sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==} + engines: {node: '>=16'} + dependencies: + arrify: 3.0.0 + cp-file: 10.0.0 + globby: 13.2.2 + junk: 4.0.1 + micromatch: 4.0.5 + nested-error-stacks: 2.1.1 + p-filter: 3.0.0 + p-map: 6.0.0 + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /crypto-random-string@4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: true + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /debug@4.3.4(supports-color@8.1.1): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + + /decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 + object-keys: 1.1.1 + dev: true + + /depcheck@1.4.7: + resolution: {integrity: sha512-1lklS/bV5chOxwNKA/2XUUk/hPORp8zihZsXflr8x0kLwmcZ9Y9BsS6Hs3ssvA+2wUVbG0U2Ciqvm1SokNjPkA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@babel/parser': 7.23.0 + '@babel/traverse': 7.23.2 + '@vue/compiler-sfc': 3.3.7 + callsite: 1.0.0 + camelcase: 6.3.0 + cosmiconfig: 7.1.0 + debug: 4.3.4(supports-color@8.1.1) + deps-regex: 0.2.0 + findup-sync: 5.0.0 + ignore: 5.2.4 + is-core-module: 2.13.1 + js-yaml: 3.14.1 + json5: 2.2.3 + lodash: 4.17.21 + minimatch: 7.4.6 + multimatch: 5.0.0 + please-upgrade-node: 3.2.0 + readdirp: 3.6.0 + require-package-name: 2.0.1 + resolve: 1.22.8 + resolve-from: 5.0.0 + semver: 7.5.4 + yargs: 16.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /deps-regex@0.2.0: + resolution: {integrity: sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==} + dev: true + + /detect-file@1.0.0: + resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} + engines: {node: '>=0.10.0'} + dev: true + + /diff@5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: true + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true + + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /electron-to-chromium@1.4.581: + resolution: {integrity: sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==} + dev: true + + /emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: true + + /err-code@3.0.1: + resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} + dev: false + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.13 + dev: true + + /es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-set-tostringtag: 2.0.2 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + iterator.prototype: 1.1.2 + safe-array-concat: 1.0.1 + dev: true + + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.0 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /esbuild-plugin-wasm@1.1.0: + resolution: {integrity: sha512-0bQ6+1tUbySSnxzn5jnXHMDvYnT0cN/Wd4Syk8g/sqAIJUg7buTIi22svS3Qz6ssx895NT+TgLPb33xi1OkZig==} + engines: {node: '>=0.10.0'} + dev: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /esbuild@0.19.5: + resolution: {integrity: sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.5 + '@esbuild/android-arm64': 0.19.5 + '@esbuild/android-x64': 0.19.5 + '@esbuild/darwin-arm64': 0.19.5 + '@esbuild/darwin-x64': 0.19.5 + '@esbuild/freebsd-arm64': 0.19.5 + '@esbuild/freebsd-x64': 0.19.5 + '@esbuild/linux-arm': 0.19.5 + '@esbuild/linux-arm64': 0.19.5 + '@esbuild/linux-ia32': 0.19.5 + '@esbuild/linux-loong64': 0.19.5 + '@esbuild/linux-mips64el': 0.19.5 + '@esbuild/linux-ppc64': 0.19.5 + '@esbuild/linux-riscv64': 0.19.5 + '@esbuild/linux-s390x': 0.19.5 + '@esbuild/linux-x64': 0.19.5 + '@esbuild/netbsd-x64': 0.19.5 + '@esbuild/openbsd-x64': 0.19.5 + '@esbuild/sunos-x64': 0.19.5 + '@esbuild/win32-arm64': 0.19.5 + '@esbuild/win32-ia32': 0.19.5 + '@esbuild/win32-x64': 0.19.5 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: true + + /eslint-compat-utils@0.1.2(eslint@8.52.0): + resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + eslint: 8.52.0 + dev: true + + /eslint-config-prettier@9.0.0(eslint@8.52.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.52.0 + dev: true + + /eslint-config-standard-with-typescript@39.1.1(@typescript-eslint/eslint-plugin@6.9.0)(eslint-plugin-import@2.29.0)(eslint-plugin-n@16.2.0)(eslint-plugin-promise@6.1.1)(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-t6B5Ep8E4I18uuoYeYxINyqcXb2UbC0SOOTxRtBSt2JUs+EzeXbfe2oaiPs71AIdnoWhXDO2fYOHz8df3kV84A==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^6.4.0 + eslint: ^8.0.1 + eslint-plugin-import: ^2.25.2 + eslint-plugin-n: '^15.0.0 || ^16.0.0 ' + eslint-plugin-promise: ^6.0.0 + typescript: '*' + dependencies: + '@typescript-eslint/eslint-plugin': 6.9.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + eslint: 8.52.0 + eslint-config-standard: 17.1.0(eslint-plugin-import@2.29.0)(eslint-plugin-n@16.2.0)(eslint-plugin-promise@6.1.1)(eslint@8.52.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0) + eslint-plugin-n: 16.2.0(eslint@8.52.0) + eslint-plugin-promise: 6.1.1(eslint@8.52.0) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-config-standard@17.1.0(eslint-plugin-import@2.29.0)(eslint-plugin-n@16.2.0)(eslint-plugin-promise@6.1.1)(eslint@8.52.0): + resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: ^8.0.1 + eslint-plugin-import: ^2.25.2 + eslint-plugin-n: '^15.0.0 || ^16.0.0 ' + eslint-plugin-promise: ^6.0.0 + dependencies: + eslint: 8.52.0 + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0) + eslint-plugin-n: 16.2.0(eslint@8.52.0) + eslint-plugin-promise: 6.1.1(eslint@8.52.0) + dev: true + + /eslint-etc@5.2.1(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-lFJBSiIURdqQKq9xJhvSJFyPA+VeTh5xvk24e8pxVL7bwLBtGF60C/KRkLTMrvCZ6DA3kbPuYhLWY0TZMlqTsg==} + peerDependencies: + eslint: ^8.0.0 + typescript: '>=4.0.0' + dependencies: + '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.52.0)(typescript@5.2.2) + eslint: 8.52.0 + tsutils: 3.21.0(typescript@5.2.2) + tsutils-etc: 1.4.2(tsutils@3.21.0)(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.13.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint@8.52.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + debug: 3.2.7 + eslint: 8.52.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-es-x@7.2.0(eslint@8.52.0): + resolution: {integrity: sha512-9dvv5CcvNjSJPqnS5uZkqb3xmbeqRLnvXKK7iI5+oK/yTusyc46zbBZKENGsOfojm/mKfszyZb+wNqNPAPeGXA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + '@eslint-community/regexpp': 4.10.0 + eslint: 8.52.0 + dev: true + + /eslint-plugin-eslint-comments@3.2.0(eslint@8.52.0): + resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} + engines: {node: '>=6.5.0'} + peerDependencies: + eslint: '>=4.19.1' + dependencies: + escape-string-regexp: 1.0.5 + eslint: 8.52.0 + ignore: 5.2.4 + dev: true + + /eslint-plugin-etc@2.0.3(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-o5RS/0YwtjlGKWjhKojgmm82gV1b4NQUuwk9zqjy9/EjxNFKKYCaF+0M7DkYBn44mJ6JYFZw3Ft249dkKuR1ew==} + peerDependencies: + eslint: ^8.0.0 + typescript: '>=4.0.0' + dependencies: + '@phenomnomnominal/tsquery': 5.0.1(typescript@5.2.2) + '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.52.0)(typescript@5.2.2) + eslint: 8.52.0 + eslint-etc: 5.2.1(eslint@8.52.0)(typescript@5.2.2) + requireindex: 1.2.0 + tslib: 2.6.2 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-html@7.1.0: + resolution: {integrity: sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==} + dependencies: + htmlparser2: 8.0.2 + dev: true + + /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0): + resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.52.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint@8.52.0) + hasown: 2.0.0 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-jsdoc@46.8.2(eslint@8.52.0): + resolution: {integrity: sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ==} + engines: {node: '>=16'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@es-joy/jsdoccomment': 0.40.1 + are-docs-informative: 0.0.2 + comment-parser: 1.4.0 + debug: 4.3.4(supports-color@8.1.1) + escape-string-regexp: 4.0.0 + eslint: 8.52.0 + esquery: 1.5.0 + is-builtin-module: 3.2.1 + semver: 7.5.4 + spdx-expression-parse: 3.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-jsonc@2.10.0(eslint@8.52.0): + resolution: {integrity: sha512-9d//o6Jyh4s1RxC9fNSt1+MMaFN2ruFdXPG9XZcb/mR2KkfjADYiNL/hbU6W0Cyxfg3tS/XSFuhl5LgtMD8hmw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + eslint: 8.52.0 + eslint-compat-utils: 0.1.2(eslint@8.52.0) + jsonc-eslint-parser: 2.4.0 + natural-compare: 1.4.0 + dev: true + + /eslint-plugin-markdown@3.0.1(eslint@8.52.0): + resolution: {integrity: sha512-8rqoc148DWdGdmYF6WSQFT3uQ6PO7zXYgeBpHAOAakX/zpq+NvFYbDA/H7PYzHajwtmaOzAwfxyl++x0g1/N9A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.52.0 + mdast-util-from-markdown: 0.8.5 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-n@16.2.0(eslint@8.52.0): + resolution: {integrity: sha512-AQER2jEyQOt1LG6JkGJCCIFotzmlcCZFur2wdKrp1JX2cNotC7Ae0BcD/4lLv3lUAArM9uNS8z/fsvXTd0L71g==} + engines: {node: '>=16.0.0'} + peerDependencies: + eslint: '>=7.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + builtins: 5.0.1 + eslint: 8.52.0 + eslint-plugin-es-x: 7.2.0(eslint@8.52.0) + get-tsconfig: 4.7.2 + ignore: 5.2.4 + is-core-module: 2.13.1 + minimatch: 3.1.2 + resolve: 1.22.8 + semver: 7.5.4 + dev: true + + /eslint-plugin-no-only-tests@3.1.0: + resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==} + engines: {node: '>=5.0.0'} + dev: true + + /eslint-plugin-promise@6.1.1(eslint@8.52.0): + resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.52.0 + dev: true + + /eslint-plugin-react-hooks@4.6.0(eslint@8.52.0): + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.52.0 + dev: true + + /eslint-plugin-react@7.33.2(eslint@8.52.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.2 + doctrine: 2.1.0 + es-iterator-helpers: 1.0.15 + eslint: 8.52.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.10 + dev: true + + /eslint-plugin-unicorn@48.0.1(eslint@8.52.0): + resolution: {integrity: sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==} + engines: {node: '>=16'} + peerDependencies: + eslint: '>=8.44.0' + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + ci-info: 3.9.0 + clean-regexp: 1.0.0 + eslint: 8.52.0 + esquery: 1.5.0 + indent-string: 4.0.0 + is-builtin-module: 3.2.1 + jsesc: 3.0.2 + lodash: 4.17.21 + pluralize: 8.0.0 + read-pkg-up: 7.0.1 + regexp-tree: 0.1.27 + regjsparser: 0.10.0 + semver: 7.5.4 + strip-indent: 3.0.0 + dev: true + + /eslint-plugin-yml@1.10.0(eslint@8.52.0): + resolution: {integrity: sha512-53SUwuNDna97lVk38hL/5++WXDuugPM9SUQ1T645R0EHMRCdBIIxGye/oOX2qO3FQ7aImxaUZJU/ju+NMUBrLQ==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.52.0 + eslint-compat-utils: 0.1.2(eslint@8.52.0) + lodash: 4.17.21 + natural-compare: 1.4.0 + yaml-eslint-parser: 1.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.52.0: + resolution: {integrity: sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.52.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.23.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.2 + acorn-jsx: 5.3.2(acorn@8.11.2) + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: true + + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: true + + /exit-hook@4.0.0: + resolution: {integrity: sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ==} + engines: {node: '>=18'} + dev: true + + /expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + dependencies: + homedir-polyfill: 1.0.3 + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.1.1 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /findup-sync@5.0.0: + resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==} + engines: {node: '>= 10.13.0'} + dependencies: + detect-file: 1.0.0 + is-glob: 4.0.3 + micromatch: 4.0.5 + resolve-dir: 1.0.1 + dev: true + + /flat-cache@3.1.1: + resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==} + engines: {node: '>=12.0.0'} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + dev: true + + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /foreground-child@2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 3.0.7 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: true + + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /global-modules@1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + dev: true + + /global-prefix@1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + dev: true + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 4.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /hamt-sharding@3.0.2: + resolution: {integrity: sha512-f0DzBD2tSmLFdFsLAvOflIBqFPjerbA7BfmwO8mVho/5hXwgyyYhv+ijIzidQf/DpDX3bRjAQvhGoBFj+DBvPw==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + sparse-array: 1.3.2 + uint8arrays: 4.0.9 + dev: false + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: true + + /homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + dependencies: + parse-passwd: 1.0.0 + dev: true + + /hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + dev: true + + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + + /interface-blockstore@5.2.7: + resolution: {integrity: sha512-B9UplmgUdQg15f/6xDJEbQYcjMm568cnqJsxSZYbDD0s6eQX5gKh58sd9H3aJEMosIy8T4vz9MwWWZuAOc3hQQ==} + dependencies: + interface-store: 5.1.5 + multiformats: 12.1.3 + dev: false + + /interface-store@5.1.5: + resolution: {integrity: sha512-X0KnJBk3o+YL13MxZBMwa88/b3Mdrpm0yPzkSTKDDVn9BSPH7UK6W+ZtIPO2bxKOQVmq7zqOwAnYnpfqWjb6/g==} + dev: false + + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + hasown: 2.0.0 + side-channel: 1.0.4 + dev: true + + /ipfs-unixfs-exporter@13.2.2: + resolution: {integrity: sha512-poCxSte+SdQzuPc/Sm+gx/86VJu+IEsW6/Cfkq29yEUZDG8QuCvTkvuqAysKAYuN40aR9SjYqwYFRW/hsvspSw==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + '@ipld/dag-cbor': 9.0.6 + '@ipld/dag-pb': 4.0.6 + '@multiformats/murmur3': 2.1.7 + err-code: 3.0.1 + hamt-sharding: 3.0.2 + interface-blockstore: 5.2.7 + ipfs-unixfs: 11.1.0 + it-filter: 3.0.4 + it-last: 3.0.4 + it-map: 3.0.5 + it-parallel: 3.0.6 + it-pipe: 3.0.1 + it-pushable: 3.2.3 + multiformats: 12.1.3 + p-queue: 7.4.1 + progress-events: 1.0.0 + uint8arrays: 4.0.9 + dev: false + + /ipfs-unixfs-importer@15.2.1: + resolution: {integrity: sha512-9ArBh7Xfz8gUSe8pq9c9ilBOXd1bbT3L+4xnI6w/usWLwnNT14p8WbFZjDD0MO1/PrD0PTUZuHNDS2l4EO+wPg==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + '@ipld/dag-pb': 4.0.6 + '@multiformats/murmur3': 2.1.7 + err-code: 3.0.1 + hamt-sharding: 3.0.2 + interface-blockstore: 5.2.7 + interface-store: 5.1.5 + ipfs-unixfs: 11.1.0 + it-all: 3.0.4 + it-batch: 3.0.4 + it-first: 3.0.4 + it-parallel-batch: 3.0.4 + multiformats: 12.1.3 + progress-events: 1.0.0 + rabin-wasm: 0.1.5 + uint8arraylist: 2.4.7 + uint8arrays: 4.0.9 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /ipfs-unixfs@11.1.0: + resolution: {integrity: sha512-Lq37nKLJOpRFjx3rcg3y+ZwUxBX7jluKfIt5UPp6wb1L3dP0sj1yaLR0Yg2CdGYvHWyUpZD1iTnT8upL0ToDOw==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + err-code: 3.0.1 + protons-runtime: 5.2.0 + uint8arraylist: 2.4.7 + dev: false + + /is-alphabetical@1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + dev: true + + /is-alphanumerical@1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + dependencies: + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + dev: true + + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-decimal@1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-hexadecimal@1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + dev: true + + /is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + dev: true + + /is-map@2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + dev: true + + /is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + dev: true + + /is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + dev: true + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-set@2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + dev: true + + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.13 + dev: true + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: true + + /is-weakmap@2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /iso-base@2.0.1: + resolution: {integrity: sha512-ip0nUW9oZP+LG6mslSgdJPt9NWZOq1qIOKpoUIdm8sq/87VwY8WZXw9ptCkhdJclY+r4feFbZuu9P/OFDqCvkQ==} + dependencies: + base-x: 4.0.0 + bigint-mod-arith: 3.3.1 + dev: false + + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /it-all@3.0.4: + resolution: {integrity: sha512-UMiy0i9DqCHBdWvMbzdYvVGa5/w4t1cc4nchpbnjdLhklglv8mQeEYnii0gvKESJuL1zV32Cqdb33R6/GPfxpQ==} + dev: false + + /it-batch@3.0.4: + resolution: {integrity: sha512-WRu2mqOYIs+T9k7+yxSK9VJdk0UE4R0jKQsWQcti5c6vhb1FhjC2+yCB5XBrctQ9edNfCMU/wVzdDj8qSwimbA==} + dev: false + + /it-filter@3.0.4: + resolution: {integrity: sha512-e0sz+st4sudK/zH6GZ/gRTRP8A/ADuJFCYDmRgMbZvR79y5+v4ZXav850bBZk5wL9zXaYZFxS1v/6Qi+Vjwh5g==} + dependencies: + it-peekable: 3.0.3 + dev: false + + /it-first@3.0.4: + resolution: {integrity: sha512-FtQl84iTNxN5EItP/JgL28V2rzNMkCzTUlNoj41eVdfix2z1DBuLnBqZ0hzYhGGa1rMpbQf0M7CQSA2adlrLJg==} + dev: false + + /it-last@3.0.4: + resolution: {integrity: sha512-Ns+KTsQWhs0KCvfv5X3Ck3lpoYxHcp4zUp4d+AOdmC8cXXqDuoZqAjfWhgCbxJubXyIYWdfE2nRcfWqgvZHP8Q==} + dev: false + + /it-map@3.0.5: + resolution: {integrity: sha512-hB0TDXo/h4KSJJDSRLgAPmDroiXP6Fx1ck4Bzl3US9hHfZweTKsuiP0y4gXuTMcJlS6vj0bb+f70rhkD47ZA3w==} + dependencies: + it-peekable: 3.0.3 + dev: false + + /it-merge@3.0.3: + resolution: {integrity: sha512-FYVU15KC5pb/GQX1Ims+lee8d4pdqGVCpWr0lkNj8o4xuNo7jY71k6GuEiWdP+T7W1bJqewSxX5yoTy5yZpRVA==} + dependencies: + it-pushable: 3.2.3 + dev: false + + /it-parallel-batch@3.0.4: + resolution: {integrity: sha512-O1omh8ss8+UtXiMjE+8kM5C20DT0Ma4VtKVfrSHOJU0UHZ+iWBXarabzPYEp+WiuQmrv+klDPPlTZ9KaLN9xOA==} + dependencies: + it-batch: 3.0.4 + dev: false + + /it-parallel@3.0.6: + resolution: {integrity: sha512-i7UM7I9LTkDJw3YIqXHFAPZX6CWYzGc+X3irdNrVExI4vPazrJdI7t5OqrSVN8CONXLAunCiqaSV/zZRbQR56A==} + dependencies: + p-defer: 4.0.0 + dev: false + + /it-peekable@3.0.3: + resolution: {integrity: sha512-Wx21JX/rMzTEl9flx3DGHuPV1KQFGOl8uoKfQtmZHgPQtGb89eQ6RyVd82h3HuP9Ghpt0WgBDlmmdWeHXqyx7w==} + dev: false + + /it-pipe@3.0.1: + resolution: {integrity: sha512-sIoNrQl1qSRg2seYSBH/3QxWhJFn9PKYvOf/bHdtCBF0bnghey44VyASsWzn5dAx0DCDDABq1hZIuzKmtBZmKA==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dependencies: + it-merge: 3.0.3 + it-pushable: 3.2.3 + it-stream-types: 2.0.1 + dev: false + + /it-pushable@3.2.3: + resolution: {integrity: sha512-gzYnXYK8Y5t5b/BnJUr7glfQLO4U5vyb05gPx/TyTw+4Bv1zM9gFk4YsOrnulWefMewlphCjKkakFvj1y99Tcg==} + dependencies: + p-defer: 4.0.0 + dev: false + + /it-stream-types@2.0.1: + resolution: {integrity: sha512-6DmOs5r7ERDbvS4q8yLKENcj6Yecr7QQTqWApbZdfAUTEC947d+PEha7PCqhm//9oxaLYL7TWRekwhoXl2s6fg==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dev: false + + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.4 + set-function-name: 2.0.1 + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsdoc-type-pratt-parser@4.0.0: + resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} + engines: {node: '>=12.0.0'} + dev: true + + /jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsonc-eslint-parser@2.4.0: + resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + semver: 7.5.4 + dev: true + + /jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.7 + array.prototype.flat: 1.3.2 + object.assign: 4.1.4 + object.values: 1.1.7 + dev: true + + /junk@4.0.1: + resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} + engines: {node: '>=12.20'} + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + dev: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /lint-staged@15.1.0: + resolution: {integrity: sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==} + engines: {node: '>=18.12.0'} + hasBin: true + dependencies: + chalk: 5.3.0 + commander: 11.1.0 + debug: 4.3.4(supports-color@8.1.1) + execa: 8.0.1 + lilconfig: 2.1.0 + listr2: 7.0.2 + micromatch: 4.0.5 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /listr2@7.0.2: + resolution: {integrity: sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==} + engines: {node: '>=16.0.0'} + dependencies: + cli-truncate: 3.1.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 5.0.1 + rfdc: 1.3.0 + wrap-ansi: 8.1.0 + dev: true + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /log-symbols@5.1.0: + resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} + engines: {node: '>=12'} + dependencies: + chalk: 5.3.0 + is-unicode-supported: 1.3.0 + dev: true + + /log-update@5.0.1: + resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + ansi-escapes: 5.0.0 + cli-cursor: 4.0.0 + slice-ansi: 5.0.0 + strip-ansi: 7.1.0 + wrap-ansi: 8.1.0 + dev: true + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: true + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /lunr@2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + dev: true + + /magic-string@0.30.5: + resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: true + + /marked@4.3.0: + resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} + engines: {node: '>= 12'} + hasBin: true + dev: true + + /matchit@1.1.0: + resolution: {integrity: sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==} + engines: {node: '>=6'} + dependencies: + '@arr/every': 1.0.1 + dev: true + + /mdast-util-from-markdown@0.8.5: + resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==} + dependencies: + '@types/mdast': 3.0.14 + mdast-util-to-string: 2.0.0 + micromark: 2.11.4 + parse-entities: 2.0.0 + unist-util-stringify-position: 2.0.3 + transitivePeerDependencies: + - supports-color + dev: true + + /mdast-util-to-string@2.0.0: + resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==} + dev: true + + /merge-options@3.0.4: + resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} + engines: {node: '>=10'} + dependencies: + is-plain-obj: 2.1.0 + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromark@2.11.4: + resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==} + dependencies: + debug: 4.3.4(supports-color@8.1.1) + parse-entities: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.0.1: + resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + /mocha@10.2.0: + resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} + engines: {node: '>= 14.0.0'} + hasBin: true + dependencies: + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.4(supports-color@8.1.1) + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 7.2.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.3 + nanoid: 3.3.3 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.2.1 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + dev: true + + /mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + dev: true + + /mrmime@1.0.1: + resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + engines: {node: '>=10'} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /multiformats@12.1.3: + resolution: {integrity: sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dev: false + + /multimatch@5.0.0: + resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} + engines: {node: '>=10'} + dependencies: + '@types/minimatch': 3.0.5 + array-differ: 3.0.0 + array-union: 2.1.0 + arrify: 2.0.1 + minimatch: 3.1.2 + dev: true + + /murmurhash3js-revisited@3.0.0: + resolution: {integrity: sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g==} + engines: {node: '>=8.0.0'} + dev: false + + /nanoid@3.3.3: + resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /nanoid@5.0.3: + resolution: {integrity: sha512-I7X2b22cxA4LIHXPSqbBCEQSL+1wv8TuoefejsX4HFWyC6jc5JG7CEaxOltiKjc1M+YCS2YkrZZcj4+dytw9GA==} + engines: {node: ^18 || >=20} + hasBin: true + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /nested-error-stacks@2.1.1: + resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} + dev: true + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.8 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path@5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-is@1.1.5: + resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + dev: true + + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /ora@7.0.1: + resolution: {integrity: sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==} + engines: {node: '>=16'} + dependencies: + chalk: 5.3.0 + cli-cursor: 4.0.0 + cli-spinners: 2.9.1 + is-interactive: 2.0.0 + is-unicode-supported: 1.3.0 + log-symbols: 5.1.0 + stdin-discarder: 0.1.0 + string-width: 6.1.0 + strip-ansi: 7.1.0 + dev: true + + /p-defer@4.0.0: + resolution: {integrity: sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==} + engines: {node: '>=12'} + dev: false + + /p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-timeout: 5.1.0 + dev: true + + /p-filter@3.0.0: + resolution: {integrity: sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-map: 5.5.0 + dev: true + + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + dependencies: + aggregate-error: 4.0.1 + dev: true + + /p-map@6.0.0: + resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} + engines: {node: '>=16'} + dev: true + + /p-queue@7.4.1: + resolution: {integrity: sha512-vRpMXmIkYF2/1hLBKisKeVYJZ8S2tZ0zEAmIJgdVKP2nq0nh4qCdf8bgw+ZgKrkh71AOCaqzwbJJk1WtdcF3VA==} + engines: {node: '>=12'} + dependencies: + eventemitter3: 5.0.1 + p-timeout: 5.1.0 + dev: false + + /p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + + /p-timeout@6.1.2: + resolution: {integrity: sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==} + engines: {node: '>=14.16'} + dev: true + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-entities@2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.22.13 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + dev: true + + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + + /playwright-core@1.39.0: + resolution: {integrity: sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==} + engines: {node: '>=16'} + hasBin: true + dev: true + + /playwright-test@12.6.0: + resolution: {integrity: sha512-8cZOErrbSzyq5fnf7LjudgXNzWz+qJaJ9fI/iodq3I3ysRlebL3xYcevxPhGSVN2/YJDgIe6EMZirNwTfynNGQ==} + engines: {node: '>=16.0.0'} + hasBin: true + dependencies: + acorn-loose: 8.4.0 + assert: 2.1.0 + buffer: 6.0.3 + c8: 8.0.1 + camelcase: 8.0.0 + chokidar: 3.5.3 + cpy: 10.1.0 + esbuild: 0.19.5 + esbuild-plugin-wasm: 1.1.0 + events: 3.3.0 + execa: 8.0.1 + exit-hook: 4.0.0 + globby: 13.2.2 + kleur: 4.1.5 + lilconfig: 2.1.0 + lodash: 4.17.21 + merge-options: 3.0.4 + nanoid: 5.0.3 + ora: 7.0.1 + p-timeout: 6.1.2 + path-browserify: 1.0.1 + playwright-core: 1.39.0 + polka: 0.5.2 + premove: 4.0.0 + process: 0.11.10 + sade: 1.8.1 + sirv: 2.0.3 + source-map: 0.6.1 + source-map-support: 0.5.21 + stream-browserify: 3.0.0 + tempy: 3.1.0 + test-exclude: 6.0.0 + util: 0.12.5 + v8-to-istanbul: 9.1.3 + dev: true + + /please-upgrade-node@3.2.0: + resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} + dependencies: + semver-compare: 1.0.0 + dev: true + + /pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + dev: true + + /polka@0.5.2: + resolution: {integrity: sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==} + dependencies: + '@polka/url': 0.5.0 + trouter: 2.0.1 + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /premove@4.0.0: + resolution: {integrity: sha512-zim/Hr4+FVdCIM7zL9b9Z0Wfd5Ya3mnKtiuDv7L5lzYzanSq6cOcVJ7EFcgK4I0pt28l8H0jX/x3nyog380XgQ==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /prettier@3.1.0: + resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /progress-events@1.0.0: + resolution: {integrity: sha512-zIB6QDrSbPfRg+33FZalluFIowkbV5Xh1xSuetjG+rlC5he6u2dc6VQJ0TbMdlN3R1RHdpOqxEFMKTnQ+itUwA==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + dev: false + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: true + + /protons-runtime@5.2.0: + resolution: {integrity: sha512-jL3VSbXllgm17zurKQ/z+Ath0w+4BknJ+l/NLocfjAB8hbeASOZTNtb7zK3nDsKq2pHK9YFumNQvpkZ6gFfWhA==} + dependencies: + uint8arraylist: 2.4.7 + uint8arrays: 4.0.9 + dev: false + + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /rabin-wasm@0.1.5: + resolution: {integrity: sha512-uWgQTo7pim1Rnj5TuWcCewRDTf0PEFTSlaUjWP4eY9EbLV9em08v89oCz/WO+wRxpYuO36XEHp4wgYQnAgOHzA==} + hasBin: true + dependencies: + '@assemblyscript/loader': 0.9.4 + bl: 5.1.0 + debug: 4.3.4(supports-color@8.1.1) + minimist: 1.2.8 + node-fetch: 2.7.0 + readable-stream: 3.6.2 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true + + /read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: true + + /read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + dependencies: + '@types/normalize-package-data': 2.4.3 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: true + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + + /regexp-tree@0.1.27: + resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} + hasBin: true + dev: true + + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: true + + /regjsparser@0.10.0: + resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} + hasBin: true + dependencies: + jsesc: 0.5.0 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /require-package-name@2.0.1: + resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==} + dev: true + + /requireindex@1.2.0: + resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} + engines: {node: '>=0.10.5'} + dev: true + + /resolve-dir@1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + dependencies: + mri: 1.2.0 + dev: true + + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + /safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-regex: 1.1.4 + dev: true + + /semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + dev: true + + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + dev: true + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /serialize-javascript@6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + dependencies: + randombytes: 2.1.0 + dev: true + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.1 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /shiki@0.14.5: + resolution: {integrity: sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==} + dependencies: + ansi-sequence-parser: 1.1.1 + jsonc-parser: 3.2.0 + vscode-oniguruma: 1.7.0 + vscode-textmate: 8.0.0 + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /simple-git-hooks@2.9.0: + resolution: {integrity: sha512-waSQ5paUQtyGC0ZxlHmcMmD9I1rRXauikBwX31bX58l5vTOhCEcBC5Bi+ZDkPXTjDnZAF8TbCqKBY+9+sVPScw==} + hasBin: true + requiresBuild: true + dev: true + + /sirv@2.0.3: + resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} + engines: {node: '>= 10'} + dependencies: + '@polka/url': 1.0.0-next.23 + mrmime: 1.0.1 + totalist: 3.0.1 + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + dev: true + + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /sparse-array@1.3.2: + resolution: {integrity: sha512-ZT711fePGn3+kQyLuv1fpd3rNSkNF8vd5Kv2D+qnOANeyKs3fx6bUMGWRPvgTTcYV64QMqZKZwcuaQSP3AZ0tg==} + dev: false + + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.16 + dev: true + + /spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.16 + dev: true + + /spdx-license-ids@3.0.16: + resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /stdin-discarder@0.1.0: + resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + bl: 5.1.0 + dev: true + + /stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: true + + /string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /string-width@6.1.0: + resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} + engines: {node: '>=16'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 10.3.0 + strip-ansi: 7.1.0 + dev: true + + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 + side-channel: 1.0.4 + dev: true + + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: true + + /strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: true + + /tempy@3.1.0: + resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} + engines: {node: '>=14.16'} + dependencies: + is-stream: 3.0.0 + temp-dir: 3.0.0 + type-fest: 2.19.0 + unique-string: 3.0.0 + dev: true + + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + dev: true + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + + /trouter@2.0.1: + resolution: {integrity: sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==} + engines: {node: '>=6'} + dependencies: + matchit: 1.1.0 + dev: true + + /ts-api-utils@1.0.3(typescript@5.2.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.2.2 + dev: true + + /tsconfig-paths@3.14.2: + resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /tsutils-etc@1.4.2(tsutils@3.21.0)(typescript@5.2.2): + resolution: {integrity: sha512-2Dn5SxTDOu6YWDNKcx1xu2YUy6PUeKrWZB/x2cQ8vY2+iz3JRembKn/iZ0JLT1ZudGNwQQvtFX9AwvRHbXuPUg==} + hasBin: true + peerDependencies: + tsutils: ^3.0.0 + typescript: '>=4.0.0' + dependencies: + '@types/yargs': 17.0.29 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 + yargs: 17.7.2 + dev: true + + /tsutils@3.21.0(typescript@5.2.2): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 5.2.2 + dev: true + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: true + + /type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: true + + /type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: true + + /type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: true + + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + + /typedoc-plugin-missing-exports@2.1.0(typedoc@0.25.3): + resolution: {integrity: sha512-+1DhqZCEu7Vu5APnrqpPwl31D+hXpt1fV0Le9ycCRL1eLVdatdl6KVt4SEVwPxnEpKwgOn2dNX6I9+0F1aO2aA==} + peerDependencies: + typedoc: 0.24.x || 0.25.x + dependencies: + typedoc: 0.25.3(typescript@5.2.2) + dev: true + + /typedoc-plugin-zod@1.1.0(typedoc@0.25.3): + resolution: {integrity: sha512-LaQdkYyVVL8CX+4R0GJuOyDa1meiG3M85FiBTPvlikCGaRkTNGSEBZTbx3gQHAsNQ5NWJpLvYJQB6gMhcO8bWw==} + peerDependencies: + typedoc: 0.23.x || 0.24.x || 0.25.x + dependencies: + typedoc: 0.25.3(typescript@5.2.2) + dev: true + + /typedoc@0.25.3(typescript@5.2.2): + resolution: {integrity: sha512-Ow8Bo7uY1Lwy7GTmphRIMEo6IOZ+yYUyrc8n5KXIZg1svpqhZSWgni2ZrDhe+wLosFS8yswowUzljTAV/3jmWw==} + engines: {node: '>= 16'} + hasBin: true + peerDependencies: + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x + dependencies: + lunr: 2.3.9 + marked: 4.3.0 + minimatch: 9.0.3 + shiki: 0.14.5 + typescript: 5.2.2 + dev: true + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /uint8arraylist@2.4.7: + resolution: {integrity: sha512-ohRElqR6C5dd60vRFLq40MCiSnUe1AzkpHvbCEMCGGP6zMoFYECsjdhL6bR1kTK37ONNRDuHQ3RIpScRYcYYIg==} + dependencies: + uint8arrays: 4.0.9 + dev: false + + /uint8arrays@4.0.9: + resolution: {integrity: sha512-iHU8XJJnfeijILZWzV7RgILdPHqe0mjJvyzY4mO8aUUtHsDbPa2Gc8/02Kc4zeokp2W6Qq8z9Ap1xkQ1HfbKwg==} + dependencies: + multiformats: 12.1.3 + dev: false + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.5 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /unique-string@3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} + dependencies: + crypto-random-string: 4.0.0 + dev: true + + /unist-util-stringify-position@2.0.3: + resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + dependencies: + '@types/unist': 2.0.9 + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.1 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.12 + which-typed-array: 1.1.13 + dev: true + + /v8-to-istanbul@9.1.3: + resolution: {integrity: sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.20 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + dev: true + + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: true + + /vite@4.5.0(@types/node@20.9.0): + resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.9.0 + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vscode-oniguruma@1.7.0: + resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} + dev: true + + /vscode-textmate@8.0.0: + resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} + dev: true + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.13 + dev: true + + /which-collection@1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + dependencies: + is-map: 2.0.2 + is-set: 2.0.2 + is-weakmap: 2.0.1 + is-weakset: 2.0.2 + dev: true + + /which-typed-array@1.1.13: + resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + + /which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wnfs@0.1.27: + resolution: {integrity: sha512-9cC53nL3Nd303gykf6WNLYoxBsGkR9sgG2PMLMRcaMD3Ygzd6Q9sUFz7dPhYNWUPIH9VUGLM58MA16c03HrX0Q==} + dev: false + + /workerpool@6.2.1: + resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml-eslint-parser@1.2.2: + resolution: {integrity: sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==} + engines: {node: ^14.17.0 || >=16.0.0} + dependencies: + eslint-visitor-keys: 3.4.3 + lodash: 4.17.21 + yaml: 2.3.4 + dev: true + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + + /yaml@2.3.4: + resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} + engines: {node: '>= 14'} + dev: true + + /yargs-parser@20.2.4: + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} + dev: true + + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + dev: true + + /yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..1598933 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - 'packages/*' + - 'examples/*' diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3883f91 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@fission-codes/eslint-config/tsconfig.json", + "typedocOptions": { + "entryPointStrategy": "packages", + "entryPoints": ["packages/package1"], + "excludeExternals": true, + "darkHighlightTheme": "github-dark", + "sourceLinkExternal": true, + "navigationLinks": { + "Github": "https://github.com/fission-code/js-template" + } + } +}