From 1c2604bea0e842df904ecdd274ae67a8a3d2aed9 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:10:57 +0100 Subject: [PATCH] Initial Release --- .github/CODEOWNERS | 17 + .github/CONTRIBUTOR_AND_GUIDES/CODE-AUDIT.md | 14 + .../CONTRIBUTOR_AND_GUIDES/CODE_OF_CONDUCT.md | 132 + .../CONTRIBUTOR_AND_GUIDES/CONTRIBUTING.md | 106 + .../USER_SUBMITTED_GUIDES.md | 44 + .github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md | 286 + .github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh | 86 + .../install/AppName-install.md | 353 + .../install/AppName-install.sh | 83 + .../CONTRIBUTOR_AND_GUIDES/json/AppName.json | 34 + .../CONTRIBUTOR_AND_GUIDES/json/AppName.md | 13 + .../DISCUSSION_TEMPLATE/request-script.yml | 35 + .github/FUNDING.yml | 2 + .github/ISSUE_TEMPLATE/bug_report.yml | 100 + .github/ISSUE_TEMPLATE/config.yml | 11 + .github/ISSUE_TEMPLATE/feature_request.yml | 33 + .github/ISSUE_TEMPLATE/frontend_report.yml | 75 + .github/ISSUE_TEMPLATE/task.yml | 25 + .github/autolabeler-config.json | 76 + .github/changelog-pr-config.json | 97 + .github/pull_request_template.md | 25 + .../runner/docker/gh-runner-self.dockerfile | 68 + .github/workflows/auto-update-app-headers.yml | 106 + .github/workflows/autolabeler.yml | 90 + .../backup/check_and_update_json_date.yml | 60 + .github/workflows/backup/shellcheck.yml | 60 + .../workflows/backup/update_json_date.yml.bak | 88 + .../backup/validate-formatting.yaml.bak | 133 + .../workflows/backup/validate-scripts.yml.bak | 234 + .github/workflows/changelog-pr.yml | 226 + .github/workflows/close-discussion.yml | 122 + .../workflows/create-docker-for-runner.yml | 37 + .github/workflows/delete-json-branch.yml | 28 + .github/workflows/frontend-cicd.yml | 78 + .github/workflows/github-release.yml | 57 + .github/workflows/script-test.yml | 177 + .github/workflows/script_format.yml | 243 + .../scripts/app-test/pr-alpine-install.func | 86 + .../workflows/scripts/app-test/pr-build.func | 260 + .../scripts/app-test/pr-create-lxc.sh | 163 + .../scripts/app-test/pr-install.func | 93 + .../workflows/scripts/generate-app-headers.sh | 34 + .github/workflows/scripts/update-json.sh | 20 + .github/workflows/scripts/update_json_date.sh | 23 + .github/workflows/update-json-date.yml | 131 + .github/workflows/validate-filenames.yml | 161 + .vscode/.editorconfig | 16 + .vscode/extensions.json | 8 + .vscode/settings.json | 5 + CHANGELOG.md | 13 + LICENSE | 2 +- README.md | 44 + SECURITY.md | 23 + api/.env.example | 5 + api/go.mod | 32 + api/go.sum | 83 + api/main.go | 450 + ct/alpine.sh | 38 + ct/debian.sh | 42 + ct/ubuntu.sh | 42 + frontend/.eslintrc.json | 5 + frontend/.gitignore | 39 + frontend/.prettierignore | 5 + frontend/.prettierrc | 3 + frontend/LICENSE | 21 + frontend/components.json | 17 + frontend/next.config.mjs | 25 + frontend/package-lock.json | 10147 ++++++++++++++++ frontend/package.json | 92 + frontend/postcss.config.mjs | 8 + frontend/public/defaultimg.png | Bin 0 -> 77312 bytes frontend/public/json | 1 + frontend/public/logo.png | Bin 0 -> 64142 bytes frontend/src/__tests__/app/page.test.tsx | 11 + .../__tests__/public/validate-json.test.ts | 53 + frontend/src/__tests__/setupTests.ts | 4 + frontend/src/app/api/categories/route.ts | 56 + frontend/src/app/category-view/page.tsx | 276 + frontend/src/app/data/page.tsx | 198 + frontend/src/app/favicon.ico | Bin 0 -> 1841 bytes .../json-editor/_components/Categories.tsx | 117 + .../json-editor/_components/InstallMethod.tsx | 240 + .../src/app/json-editor/_components/Note.tsx | 130 + .../src/app/json-editor/_schemas/schemas.ts | 45 + frontend/src/app/json-editor/page.tsx | 355 + frontend/src/app/layout.tsx | 94 + frontend/src/app/manifest.ts | 28 + frontend/src/app/not-found.tsx | 20 + frontend/src/app/page.tsx | 137 + frontend/src/app/robots.ts | 14 + .../scripts/_components/ScriptAccordion.tsx | 132 + .../scripts/_components/ScriptInfoBlocks.tsx | 223 + .../app/scripts/_components/ScriptItem.tsx | 107 + .../_components/ScriptItems/Alerts.tsx | 35 + .../_components/ScriptItems/Buttons.tsx | 81 + .../ScriptItems/DefaultPassword.tsx | 42 + .../ScriptItems/DefaultSettings.tsx | 51 + .../_components/ScriptItems/Description.tsx | 13 + .../ScriptItems/InstallCommand.tsx | 85 + .../_components/ScriptItems/InterFaces.tsx | 41 + .../_components/ScriptItems/Tooltips.tsx | 52 + .../src/app/scripts/_components/Sidebar.tsx | 43 + frontend/src/app/scripts/page.tsx | 79 + frontend/src/app/sitemap.ts | 23 + frontend/src/components/ApplicationChart.tsx | 193 + frontend/src/components/CommandMenu.tsx | 128 + frontend/src/components/Footer.tsx | 43 + frontend/src/components/Modal.tsx | 29 + frontend/src/components/Navbar.tsx | 86 + frontend/src/components/TextCopyBlock.tsx | 28 + frontend/src/components/handleCopy.tsx | 10 + frontend/src/components/theme-provider.tsx | 8 + frontend/src/components/ui/accordion.tsx | 57 + frontend/src/components/ui/alert.tsx | 59 + .../components/ui/animated-gradient-text.tsx | 26 + frontend/src/components/ui/badge.tsx | 39 + frontend/src/components/ui/button.tsx | 108 + frontend/src/components/ui/calendar.tsx | 66 + frontend/src/components/ui/card.tsx | 89 + .../src/components/ui/code-copy-button.tsx | 62 + frontend/src/components/ui/codeblock.tsx | 138 + frontend/src/components/ui/command.tsx | 155 + frontend/src/components/ui/dialog.tsx | 122 + frontend/src/components/ui/dropdown-menu.tsx | 200 + frontend/src/components/ui/input.tsx | 25 + frontend/src/components/ui/label.tsx | 26 + .../src/components/ui/navigation-menu.tsx | 128 + frontend/src/components/ui/number-ticker.tsx | 61 + frontend/src/components/ui/particles.tsx | 283 + frontend/src/components/ui/popover.tsx | 31 + frontend/src/components/ui/select.tsx | 160 + frontend/src/components/ui/separator.tsx | 31 + frontend/src/components/ui/sheet.tsx | 140 + frontend/src/components/ui/sonner.tsx | 31 + .../components/ui/star-on-github-button.tsx | 57 + frontend/src/components/ui/switch.tsx | 29 + frontend/src/components/ui/table.tsx | 120 + frontend/src/components/ui/tabs.tsx | 55 + frontend/src/components/ui/textarea.tsx | 22 + frontend/src/components/ui/theme-toggle.tsx | 47 + frontend/src/components/ui/tooltip.tsx | 30 + frontend/src/config/siteConfig.tsx | 72 + frontend/src/lib/data.ts | 10 + frontend/src/lib/time.ts | 7 + frontend/src/lib/types.ts | 58 + frontend/src/lib/utils.ts | 6 + frontend/src/styles/globals.css | 95 + frontend/tailwind.config.ts | 180 + frontend/tsconfig.json | 33 + frontend/vitest.config.mjs | 11 + install/alpine-install.sh | 25 + install/debian-install.sh | 28 + install/ubuntu-install.sh | 28 + json/alpine.json | 39 + json/code-server.json | 41 + json/debian.json | 34 + json/filebrowser.json | 39 + json/host-backup.json | 43 + json/ubuntu.json | 34 + misc/alpine-install.func | 189 + misc/api.func | 123 + misc/build.func | 1275 ++ misc/code-server.sh | 96 + misc/container-restore-from-backup.sh | 86 + misc/core-restore-from-backup.sh | 86 + misc/filebrowser.sh | 131 + misc/frigate-support.sh | 93 + misc/host-backup.sh | 79 + misc/hw-acceleration.sh | 116 + misc/images/logo-81x112.png | Bin 0 -> 5483 bytes misc/images/logo.png | Bin 0 -> 64142 bytes misc/install.func | 272 + misc/pyenv.sh | 159 + misc/usb-passthrough.sh | 51 + vm/debian-vm.sh | 512 + 175 files changed, 25348 insertions(+), 1 deletion(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/CODE-AUDIT.md create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/CODE_OF_CONDUCT.md create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/CONTRIBUTING.md create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/USER_SUBMITTED_GUIDES.md create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/json/AppName.json create mode 100644 .github/CONTRIBUTOR_AND_GUIDES/json/AppName.md create mode 100644 .github/DISCUSSION_TEMPLATE/request-script.yml create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/frontend_report.yml create mode 100644 .github/ISSUE_TEMPLATE/task.yml create mode 100644 .github/autolabeler-config.json create mode 100644 .github/changelog-pr-config.json create mode 100644 .github/pull_request_template.md create mode 100644 .github/runner/docker/gh-runner-self.dockerfile create mode 100644 .github/workflows/auto-update-app-headers.yml create mode 100644 .github/workflows/autolabeler.yml create mode 100644 .github/workflows/backup/check_and_update_json_date.yml create mode 100644 .github/workflows/backup/shellcheck.yml create mode 100644 .github/workflows/backup/update_json_date.yml.bak create mode 100644 .github/workflows/backup/validate-formatting.yaml.bak create mode 100644 .github/workflows/backup/validate-scripts.yml.bak create mode 100644 .github/workflows/changelog-pr.yml create mode 100644 .github/workflows/close-discussion.yml create mode 100644 .github/workflows/create-docker-for-runner.yml create mode 100644 .github/workflows/delete-json-branch.yml create mode 100644 .github/workflows/frontend-cicd.yml create mode 100644 .github/workflows/github-release.yml create mode 100644 .github/workflows/script-test.yml create mode 100644 .github/workflows/script_format.yml create mode 100644 .github/workflows/scripts/app-test/pr-alpine-install.func create mode 100644 .github/workflows/scripts/app-test/pr-build.func create mode 100644 .github/workflows/scripts/app-test/pr-create-lxc.sh create mode 100644 .github/workflows/scripts/app-test/pr-install.func create mode 100644 .github/workflows/scripts/generate-app-headers.sh create mode 100644 .github/workflows/scripts/update-json.sh create mode 100644 .github/workflows/scripts/update_json_date.sh create mode 100644 .github/workflows/update-json-date.yml create mode 100644 .github/workflows/validate-filenames.yml create mode 100644 .vscode/.editorconfig create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 api/.env.example create mode 100644 api/go.mod create mode 100644 api/go.sum create mode 100644 api/main.go create mode 100644 ct/alpine.sh create mode 100644 ct/debian.sh create mode 100644 ct/ubuntu.sh create mode 100644 frontend/.eslintrc.json create mode 100644 frontend/.gitignore create mode 100644 frontend/.prettierignore create mode 100644 frontend/.prettierrc create mode 100644 frontend/LICENSE create mode 100644 frontend/components.json create mode 100644 frontend/next.config.mjs create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/postcss.config.mjs create mode 100644 frontend/public/defaultimg.png create mode 100644 frontend/public/json create mode 100644 frontend/public/logo.png create mode 100644 frontend/src/__tests__/app/page.test.tsx create mode 100644 frontend/src/__tests__/public/validate-json.test.ts create mode 100644 frontend/src/__tests__/setupTests.ts create mode 100644 frontend/src/app/api/categories/route.ts create mode 100644 frontend/src/app/category-view/page.tsx create mode 100644 frontend/src/app/data/page.tsx create mode 100644 frontend/src/app/favicon.ico create mode 100644 frontend/src/app/json-editor/_components/Categories.tsx create mode 100644 frontend/src/app/json-editor/_components/InstallMethod.tsx create mode 100644 frontend/src/app/json-editor/_components/Note.tsx create mode 100644 frontend/src/app/json-editor/_schemas/schemas.ts create mode 100644 frontend/src/app/json-editor/page.tsx create mode 100644 frontend/src/app/layout.tsx create mode 100644 frontend/src/app/manifest.ts create mode 100644 frontend/src/app/not-found.tsx create mode 100644 frontend/src/app/page.tsx create mode 100644 frontend/src/app/robots.ts create mode 100644 frontend/src/app/scripts/_components/ScriptAccordion.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItem.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/Buttons.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/DefaultPassword.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/DefaultSettings.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/Description.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/InstallCommand.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/InterFaces.tsx create mode 100644 frontend/src/app/scripts/_components/ScriptItems/Tooltips.tsx create mode 100644 frontend/src/app/scripts/_components/Sidebar.tsx create mode 100644 frontend/src/app/scripts/page.tsx create mode 100644 frontend/src/app/sitemap.ts create mode 100644 frontend/src/components/ApplicationChart.tsx create mode 100644 frontend/src/components/CommandMenu.tsx create mode 100644 frontend/src/components/Footer.tsx create mode 100644 frontend/src/components/Modal.tsx create mode 100644 frontend/src/components/Navbar.tsx create mode 100644 frontend/src/components/TextCopyBlock.tsx create mode 100644 frontend/src/components/handleCopy.tsx create mode 100644 frontend/src/components/theme-provider.tsx create mode 100644 frontend/src/components/ui/accordion.tsx create mode 100644 frontend/src/components/ui/alert.tsx create mode 100644 frontend/src/components/ui/animated-gradient-text.tsx create mode 100644 frontend/src/components/ui/badge.tsx create mode 100644 frontend/src/components/ui/button.tsx create mode 100644 frontend/src/components/ui/calendar.tsx create mode 100644 frontend/src/components/ui/card.tsx create mode 100644 frontend/src/components/ui/code-copy-button.tsx create mode 100644 frontend/src/components/ui/codeblock.tsx create mode 100644 frontend/src/components/ui/command.tsx create mode 100644 frontend/src/components/ui/dialog.tsx create mode 100644 frontend/src/components/ui/dropdown-menu.tsx create mode 100644 frontend/src/components/ui/input.tsx create mode 100644 frontend/src/components/ui/label.tsx create mode 100644 frontend/src/components/ui/navigation-menu.tsx create mode 100644 frontend/src/components/ui/number-ticker.tsx create mode 100644 frontend/src/components/ui/particles.tsx create mode 100644 frontend/src/components/ui/popover.tsx create mode 100644 frontend/src/components/ui/select.tsx create mode 100644 frontend/src/components/ui/separator.tsx create mode 100644 frontend/src/components/ui/sheet.tsx create mode 100644 frontend/src/components/ui/sonner.tsx create mode 100644 frontend/src/components/ui/star-on-github-button.tsx create mode 100644 frontend/src/components/ui/switch.tsx create mode 100644 frontend/src/components/ui/table.tsx create mode 100644 frontend/src/components/ui/tabs.tsx create mode 100644 frontend/src/components/ui/textarea.tsx create mode 100644 frontend/src/components/ui/theme-toggle.tsx create mode 100644 frontend/src/components/ui/tooltip.tsx create mode 100644 frontend/src/config/siteConfig.tsx create mode 100644 frontend/src/lib/data.ts create mode 100644 frontend/src/lib/time.ts create mode 100644 frontend/src/lib/types.ts create mode 100644 frontend/src/lib/utils.ts create mode 100644 frontend/src/styles/globals.css create mode 100644 frontend/tailwind.config.ts create mode 100644 frontend/tsconfig.json create mode 100644 frontend/vitest.config.mjs create mode 100644 install/alpine-install.sh create mode 100644 install/debian-install.sh create mode 100644 install/ubuntu-install.sh create mode 100644 json/alpine.json create mode 100644 json/code-server.json create mode 100644 json/debian.json create mode 100644 json/filebrowser.json create mode 100644 json/host-backup.json create mode 100644 json/ubuntu.json create mode 100644 misc/alpine-install.func create mode 100644 misc/api.func create mode 100644 misc/build.func create mode 100644 misc/code-server.sh create mode 100644 misc/container-restore-from-backup.sh create mode 100644 misc/core-restore-from-backup.sh create mode 100644 misc/filebrowser.sh create mode 100644 misc/frigate-support.sh create mode 100644 misc/host-backup.sh create mode 100644 misc/hw-acceleration.sh create mode 100644 misc/images/logo-81x112.png create mode 100644 misc/images/logo.png create mode 100644 misc/install.func create mode 100644 misc/pyenv.sh create mode 100644 misc/usb-passthrough.sh create mode 100644 vm/debian-vm.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..b25e618 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,17 @@ +# +# CODEOWNERS for ProxmoxVE +# + +# Order is important; the last matching pattern takes the most +# precedence. + + +# Codeowners for specific folders and files +# Remember ending folders with / + + +# Set default reviewers +* @community-scripts/Contributor + +# All changes in frontend +/frontend/ @community-scripts/Frontend-Dev diff --git a/.github/CONTRIBUTOR_AND_GUIDES/CODE-AUDIT.md b/.github/CONTRIBUTOR_AND_GUIDES/CODE-AUDIT.md new file mode 100644 index 0000000..158a5c6 --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/CODE-AUDIT.md @@ -0,0 +1,14 @@ +
+ +
+

Exploring the Scripts and Steps Involved in an Application LXC Installation

+ +1) [adguard.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/adguard.sh): This script collects system parameters. (Also holds the function to update the application.) +2) [build.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/build.func): Adds user settings and integrates collected information. +3) [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/create_lxc.sh): Constructs the LXC container. +4) [adguard-install.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/install/adguard-install.sh): Executes functions from [install.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/install.func), and installs the application. +5) [adguard.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/adguard.sh) (again): To display the completion message. + +The installation process uses reusable scripts: [build.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/build.func), [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/create_lxc.sh), and [install.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/install.func), which are not specific to any particular application. + +To gain a better understanding, focus on reviewing [adguard-install.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/install/adguard-install.sh). This script contains the commands and configurations for installing and configuring AdGuard Home within the LXC container. diff --git a/.github/CONTRIBUTOR_AND_GUIDES/CODE_OF_CONDUCT.md b/.github/CONTRIBUTOR_AND_GUIDES/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..4cf8cff --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available +at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/.github/CONTRIBUTOR_AND_GUIDES/CONTRIBUTING.md b/.github/CONTRIBUTOR_AND_GUIDES/CONTRIBUTING.md new file mode 100644 index 0000000..1c5f20b --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/CONTRIBUTING.md @@ -0,0 +1,106 @@ + +# Community Scripts Contribution Guide + +## **Welcome to the communty-scripts Repository!** + +📜 These documents outline the essential coding standards for all our scripts and JSON files. Adhering to these standards ensures that our codebase remains consistent, readable, and maintainable. By following these guidelines, we can improve collaboration, reduce errors, and enhance the overall quality of our project. + +### Why Coding Standards Matter + +Coding standards are crucial for several reasons: + +1. **Consistency**: Consistent code is easier to read, understand, and maintain. It helps new team members quickly get up to speed and reduces the learning curve. +2. **Readability**: Clear and well-structured code is easier to debug and extend. It allows developers to quickly identify and fix issues. +3. **Maintainability**: Code that follows a standard structure is easier to refactor and update. It ensures that changes can be made with minimal risk of introducing new bugs. +4. **Collaboration**: When everyone follows the same standards, it becomes easier to collaborate on code. It reduces friction and misunderstandings during code reviews and merges. + +### Scope of These Documents + +These documents cover the coding standards for the following types of files in our project: + +- **`install/$AppName-install.sh` Scripts**: These scripts are responsible for the installation of applications. +- **`ct/$AppName.sh` Scripts**: These scripts handle the creation and updating of containers. +- **`json/$AppName.json`**: These files store structured data and are used for the website. + +Each section provides detailed guidelines on various aspects of coding, including shebang usage, comments, variable naming, function naming, indentation, error handling, command substitution, quoting, script structure, and logging. Additionally, examples are provided to illustrate the application of these standards. + +By following the coding standards outlined in this document, we ensure that our scripts and JSON files are of high quality, making our project more robust and easier to manage. Please refer to this guide whenever you create or update scripts and JSON files to maintain a high standard of code quality across the project. 📚🔍 + +Let's work together to keep our codebase clean, efficient, and maintainable! 💪🚀 + + +## Getting Started + +Before contributing, please ensure that you have the following setup: + +1. **Visual Studio Code** (recommended for script development) +2. **Recommended VS Code Extensions:** + - [Shell Syntax](https://marketplace.visualstudio.com/items?itemName=bmalehorn.shell-syntax) + - [ShellCheck](https://marketplace.visualstudio.com/items?itemName=timonwong.shellcheck) + - [Shell Format](https://marketplace.visualstudio.com/items?itemName=foxundermoon.shell-format) + +### Important Notes +- Use [AppName.sh](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh) and [AppName-install.sh](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh) as templates when creating new scripts. + +--- + +# 🚀 The Application Script (ct/AppName.sh) + +- You can find all coding standards, as well as the structure for this file [here](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md). +- These scripts are responsible for container creation, setting the necessary variables and handling the update of the application once installed. + +--- + +# 🛠 The Installation Script (install/AppName-install.sh) + +- You can find all coding standards, as well as the structure for this file [here](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md). +- These scripts are responsible for the installation of the application. + +--- + +## 🚀 Building Your Own Scripts + +Start with the [template script](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh) + +--- + +## 🤝 Contribution Process + +### 1. Fork the repository +Fork to your GitHub account + +### 2. Clone your fork on your local environment +```bash +git clone https://github.com/yourUserName/ForkName +``` + +### 3. Create a new branch +```bash +git switch -c your-feature-branch +``` + +### 4. Change paths in build.func install.func and AppName.sh +To be able to develop from your own branch you need to change `https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main` to `https://raw.githubusercontent.com/[USER]/[REPOSITORY]/refs/heads/[BRANCH]`. You need to make this change atleast in misc/build.func misc/install.func and in your ct/AppName.sh. This change is only for testing. Before opening a Pull Request you should change this line change all this back to point to `https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main`. + +### 4. Commit changes (without build.func and install.func!) +```bash +git commit -m "Your commit message" +``` + +### 5. Push to your fork +```bash +git push origin your-feature-branch +``` + +### 6. Create a Pull Request +Open a Pull Request from your feature branch to the main repository branch. You must only include your **$AppName.sh**, **$AppName-install.sh** and **$AppName.json** files in the pull request. + +--- + +## 📚 Pages + +- [CT Template: AppName.sh](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh) +- [Install Template: AppName-install.sh](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh) +- [JSON Template: AppName.json](https://github.com/community-scripts/ProxmoxVED/blob/main/.github/CONTRIBUTOR_AND_GUIDES/json/AppName.json) + + diff --git a/.github/CONTRIBUTOR_AND_GUIDES/USER_SUBMITTED_GUIDES.md b/.github/CONTRIBUTOR_AND_GUIDES/USER_SUBMITTED_GUIDES.md new file mode 100644 index 0000000..6d9941c --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/USER_SUBMITTED_GUIDES.md @@ -0,0 +1,44 @@ +
+ + + +
+

User Submitted Guides

+ + In order to contribute a guide on installing with Proxmox VE Helper Scripts, you should open a pull request that adds the guide to the `USER_SUBMITTED_GUIDES.md` file. + +[Proxmox Automation with Proxmox Helper Scripts!](https://www.youtube.com/watch?v=kcpu4z5eSEU) + +[Installing Home Assistant OS using Proxmox 8](https://community.home-assistant.io/t/installing-home-assistant-os-using-proxmox-8/201835) + +[How To Separate Zigbee2MQTT From Home Assistant In Proxmox](https://smarthomescene.com/guides/how-to-separate-zigbee2mqtt-from-home-assistant-in-proxmox/) + +[How To Install Home Assistant On Proxmox: The Easy Way](https://smarthomescene.com/guides/how-to-install-home-assistant-on-proxmox-the-easy-way/) + +[Home Assistant: Installing InfluxDB (LXC)](https://www.derekseaman.com/2023/04/home-assistant-installing-influxdb-lxc.html) + +[Home Assistant: Proxmox Quick Start Guide](https://www.derekseaman.com/2023/10/home-assistant-proxmox-ve-8-0-quick-start-guide-2.html) + +[Home Assistant: Installing Grafana (LXC) with Let’s Encrypt SSL](https://www.derekseaman.com/2023/04/home-assistant-installing-grafana-lxc.html) + +[Proxmox: Plex LXC with Alder Lake Transcoding](https://www.derekseaman.com/2023/04/proxmox-plex-lxc-with-alder-lake-transcoding.html) + +[How To Backup Home Assistant In Proxmox](https://smarthomescene.com/guides/how-to-backup-home-assistant-in-proxmox/) + +[Running Frigate on Proxmox](https://www.homeautomationguy.io/blog/running-frigate-on-proxmox) + +[Frigate VM on Proxmox with PCIe Coral TPU](https://www.derekseaman.com/2023/06/home-assistant-frigate-vm-on-proxmox-with-pcie-coral-tpu.html) + +[Moving Home Assistant’s Database To MariaDB On Proxmox](https://smarthomescene.com/guides/moving-home-assistants-database-to-mariadb-on-proxmox/) + +[How-to: Proxmox VE 7.4 to 8.0 Upgrade](https://www.derekseaman.com/2023/06/how-to-proxmox-7-4-to-8-0-upgrade.html) + +[iGPU Transcoding In Proxmox with Jellyfin](https://www.youtube.com/watch?v=XAa_qpNmzZs) + +[Proxmox + NetData]() + +[Proxmox Homelab Series]() + +[The fastest installation of Docker and Portainer on Proxmox VE](https://lavr.site/en-fastest-install-docker-portainer-proxmox/) + +[How To Setup Proxmox Backuper Server Using Helper Scripts]() diff --git a/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md new file mode 100644 index 0000000..f6f9420 --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md @@ -0,0 +1,286 @@ +# **AppName.sh Scripts** + + `AppName.sh` scripts found in the `/ct` directory. These scripts are responsible for the installation of the desired application. For this guide we take `/ct/snipeit.sh` as example. + +## Table of Contents + +- [**AppName.sh Scripts**](#appnamesh-scripts) + - [Table of Contents](#table-of-contents) + - [1. **File Header**](#1-file-header) + - [1.1 **Shebang**](#11-shebang) + - [1.2 **Import Functions**](#12-import-functions) + - [1.3 **Metadata**](#13-metadata) + - [2 **Variables and function import**](#2-variables-and-function-import) + - [2.1 **Default Values**](#21-default-values) + - [2.2 **📋 App output \& base settings**](#22--app-output--base-settings) + - [2.3 **🛠 Core functions**](#23--core-functions) + - [3 **Update function**](#3-update-function) + - [3.1 **Function Header**](#31-function-header) + - [3.2 **Check APP**](#32-check-app) + - [3.3 **Check version**](#33-check-version) + - [3.4 **Verbosity**](#34-verbosity) + - [3.5 **Backups**](#35-backups) + - [3.6 **Cleanup**](#36-cleanup) + - [3.7 **No update function**](#37-no-update-function) + - [4 **End of the script**](#4-end-of-the-script) + - [5. **Contribution checklist**](#5-contribution-checklist) + +## 1. **File Header** + +### 1.1 **Shebang** + +- Use `#!/usr/bin/env bash` as the shebang. + +```bash +#!/usr/bin/env bash +``` + +### 1.2 **Import Functions** + +- Import the build.func file. +- When developing your own script, change the URL to your own repository. + +> [!IMPORTANT] +> You also need to change all apperances of this URL in `misc/build.func` and `misc/install.func` + +Example for development: + +```bash +source <(curl -s https://raw.githubusercontent.com/[USER]/[REPO]/refs/heads/[BRANCH]/misc/build.func) +``` + +Final script: + +```bash +source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +``` + +> [!CAUTION] +> Before opening a Pull Request, change the URLs to point to the community-scripts repo. + +### 1.3 **Metadata** + +- Add clear comments for script metadata, including author, copyright, and license information. + +Example: + +```bash +# Copyright (c) 2021-2025 community-scripts ORG +# Author: [YourUserName] +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: [SOURCE_URL] +``` + +> [!NOTE]: +> +> - Add your username and source URL +> - For existing scripts, add "| Co-Author [YourUserName]" after the current author + +--- + +## 2 **Variables and function import** +> +> [!NOTE] +> You need to have all this set in your script, otherwise it will not work! + +### 2.1 **Default Values** + +- This section sets the default values for the container. +- `APP` needs to be set to the application name and must be equal to the filenames of your scripts. +- `var_tags`: You can set Tags for the CT wich show up in the Proxmox UI. Don´t overdo it! + +>[!NOTE] +>Description for all Default Values +> +>| Variable | Description | Notes | +>|----------|-------------|-------| +>| `APP` | Application name | Must match ct\AppName.sh | +>| `var_tags` | Proxmox display tags without Spaces, only ; | Limit the number | +>| `var_cpu` | CPU cores | Number of cores | +>| `var_ram` | RAM | In MB | +>| `var_disk` | Disk capacity | In GB | +>| `var_os` | Operating system | alpine, debian, ubuntu | +>| `var_version` | OS version | e.g., 3.20, 11, 12, 20.04 | +>| `var_unprivileged` | Container type | 1 = Unprivileged, 0 = Privileged | + +Example: + +```bash +APP="SnipeIT" +var_tags="asset-management;foss" +var_cpu="2" +var_ram="2048" +var_disk="4" +var_os="debian" +var_version="12" +var_unprivileged="1" +``` + +## 2.2 **📋 App output & base settings** + +```bash +header_info "$APP" +``` +- `header_info`: Generates ASCII header for APP + +## 2.3 **🛠 Core functions** + +```bash +variables +color +catch_errors +``` + +- `variables`: Processes input and prepares variables +- `color`: Sets icons, colors, and formatting +- `catch_errors`: Enables error handling + +--- + +## 3 **Update function** + +### 3.1 **Function Header** + +- If applicable write a function that updates the application and the OS in the container. +- Each update function starts with the same code: + +```bash +function update_script() { + header_info + check_container_storage + check_container_resources +``` + +### 3.2 **Check APP** + +- Before doing anything update-wise, check if the app is installed in the container. + +Example: + +```bash +if [[ ! -d /opt/snipe-it ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi +``` + +### 3.3 **Check version** + +- Before updating, check if a new version exists. + - We use the `${APPLICATION}_version.txt` file created in `/opt` during the install to compare new versions against the currently installed version. + +Example with a Github Release: + +```bash + RELEASE=$(curl -fsSL https://api.github.com/repos/snipe/snipe-it/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') + if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then + msg_info "Updating ${APP} to v${RELEASE}" + #DO UPDATE + else + msg_ok "No update required. ${APP} is already at v${RELEASE}." + fi + exit +} +``` + +### 3.4 **Verbosity** + +- Use the appropriate flag (**-q** in the examples) for a command to suppress its output. +Example: + +```bash +wget -q +unzip -q +``` + +- If a command does not come with this functionality use `$STD` to suppress it's output. + +Example: + +```bash +$STD php artisan migrate --force +$STD php artisan config:clear +``` + +### 3.5 **Backups** + +- Backup user data if necessary. +- Move all user data back in the directory when the update is finished. + +>[!NOTE] +>This is not meant to be a permanent backup + +Example backup: + +```bash + mv /opt/snipe-it /opt/snipe-it-backup +``` + +Example config restore: + +```bash + cp /opt/snipe-it-backup/.env /opt/snipe-it/.env + cp -r /opt/snipe-it-backup/public/uploads/ /opt/snipe-it/public/uploads/ + cp -r /opt/snipe-it-backup/storage/private_uploads /opt/snipe-it/storage/private_uploads +``` + +### 3.6 **Cleanup** + +- Do not forget to remove any temporary files/folders such as zip-files or temporary backups. +Example: + +```bash + rm -rf /opt/v${RELEASE}.zip + rm -rf /opt/snipe-it-backup +``` + +### 3.7 **No update function** + +- In case you can not provide an update function use the following code to provide user feedback. + +```bash +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/snipeit ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + msg_error "Currently we don't provide an update function for this ${APP}." + exit +} +``` + +--- + +## 4 **End of the script** + +- `start`: Launches Whiptail dialogue +- `build_container`: Collects and integrates user settings +- `description`: Sets LXC container description +- With `echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"` you can point the user to the IP:PORT/folder needed to access the app. + +```bash +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}" +``` + +--- + +## 5. **Contribution checklist** + +- [ ] Shebang is correctly set (`#!/usr/bin/env bash`). +- [ ] Correct link to *build.func* +- [ ] Metadata (author, license) is included at the top. +- [ ] Variables follow naming conventions. +- [ ] Update function exists. +- [ ] Update functions checks if app is installed and for new version. +- [ ] Update function cleans up temporary files. +- [ ] Script ends with a helpful message for the user to reach the application. diff --git a/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh new file mode 100644 index 0000000..075fc69 --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: [YourUserName] +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: [SOURCE_URL] + +# App Default Values +APP="[APP_NAME]" +# Name of the app (e.g. Google, Adventurelog, Apache-Guacamole" +var_tags="[TAGS]" +# Tags for Proxmox VE, maximum 2 pcs., no spaces allowed, separated by a semicolon ; (e.g. database | adblock;dhcp) +var_cpu="[CPU]" +# Number of cores (1-X) (e.g. 4) - default are 2 +var_ram="[RAM]" +# Amount of used RAM in MB (e.g. 2048 or 4096) +var_disk="[DISK]" +# Amount of used disk space in GB (e.g. 4 or 10) +var_os="[OS]" +# Default OS (e.g. debian, ubuntu, alpine) +var_version="[VERSION]" +# Default OS version (e.g. 12 for debian, 24.04 for ubuntu, 3.20 for alpine) +var_unprivileged="[UNPRIVILEGED]" +# 1 = unprivileged container, 0 = privileged container + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + # Check if installation is present | -f for file, -d for folder + if [[ ! -f [INSTALLATION_CHECK_PATH] ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + # Crawling the new version and checking whether an update is required + RELEASE=$(curl -fsSL [RELEASE_URL] | [PARSE_RELEASE_COMMAND]) + if [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]] || [[ ! -f /opt/${APP}_version.txt ]]; then + # Stopping Services + msg_info "Stopping $APP" + systemctl stop [SERVICE_NAME] + msg_ok "Stopped $APP" + + # Creating Backup + msg_info "Creating Backup" + tar -czf "/opt/${APP}_backup_$(date +%F).tar.gz" [IMPORTANT_PATHS] + msg_ok "Backup Created" + + # Execute Update + msg_info "Updating $APP to v${RELEASE}" + [UPDATE_COMMANDS] + msg_ok "Updated $APP to v${RELEASE}" + + # Starting Services + msg_info "Starting $APP" + systemctl start [SERVICE_NAME] + msg_ok "Started $APP" + + # Cleaning up + msg_info "Cleaning Up" + rm -rf [TEMP_FILES] + msg_ok "Cleanup Completed" + + # Last Action + echo "${RELEASE}" >/opt/${APP}_version.txt + msg_ok "Update Successful" + else + msg_ok "No update required. ${APP} is already at v${RELEASE}" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:[PORT]${CL}" diff --git a/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md new file mode 100644 index 0000000..42107fd --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md @@ -0,0 +1,353 @@ + +# **AppName-install.sh Scripts** + + `AppName-install.sh` scripts found in the `/install` directory. These scripts are responsible for the installation of the application. For this guide we take `/install/snipeit-install.sh` as example. + +## Table of Contents + +- [**AppName-install.sh Scripts**](#appname-installsh-scripts) + - [Table of Contents](#table-of-contents) + - [1. **File header**](#1-file-header) + - [1.1 **Shebang**](#11-shebang) + - [1.2 **Comments**](#12-comments) + - [1.3 **Variables and function import**](#13-variables-and-function-import) + - [2. **Variable naming and management**](#2-variable-naming-and-management) + - [2.1 **Naming conventions**](#21-naming-conventions) + - [3. **Dependencies**](#3-dependencies) + - [3.1 **Install all at once**](#31-install-all-at-once) + - [3.2 **Collapse dependencies**](#32-collapse-dependencies) + - [4. **Paths to application files**](#4-paths-to-application-files) + - [5. **Version management**](#5-version-management) + - [5.1 **Install the latest release**](#51-install-the-latest-release) + - [5.2 **Save the version for update checks**](#52-save-the-version-for-update-checks) + - [6. **Input and output management**](#6-input-and-output-management) + - [6.1 **User feedback**](#61-user-feedback) + - [6.2 **Verbosity**](#62-verbosity) + - [7. **String/File Manipulation**](#7-stringfile-manipulation) + - [7.1 **File Manipulation**](#71-file-manipulation) + - [8. **Security practices**](#8-security-practices) + - [8.1 **Password generation**](#81-password-generation) + - [8.2 **File permissions**](#82-file-permissions) + - [9. **Service Configuration**](#9-service-configuration) + - [9.1 **Configuration files**](#91-configuration-files) + - [9.2 **Credential management**](#92-credential-management) + - [9.3 **Enviroment files**](#93-enviroment-files) + - [9.4 **Services**](#94-services) + - [10. **Cleanup**](#10-cleanup) + - [10.1 **Remove temporary files**](#101-remove-temporary-files) + - [10.2 **Autoremove and autoclean**](#102-autoremove-and-autoclean) + - [11. **Best Practices Checklist**](#11-best-practices-checklist) + - [Example: High-Level Script Flow](#example-high-level-script-flow) + +## 1. **File header** + +### 1.1 **Shebang** + +- Use `#!/usr/bin/env bash` as the shebang. + +```bash +#!/usr/bin/env bash +``` + +### 1.2 **Comments** + +- Add clear comments for script metadata, including author, copyright, and license information. +- Use meaningful inline comments to explain complex commands or logic. + +Example: + +```bash +# Copyright (c) 2021-2025 community-scripts ORG +# Author: [YourUserName] +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: [SOURCE_URL] +``` + +> [!NOTE]: +> +> - Add your username +> - When updating/reworking scripts, add "| Co-Author [YourUserName]" + +### 1.3 **Variables and function import** + +- This sections adds the support for all needed functions and variables. + +```bash +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os +``` + +--- + +## 2. **Variable naming and management** + +### 2.1 **Naming conventions** + +- Use uppercase names for constants and environment variables. +- Use lowercase names for local script variables. + +Example: + +```bash +DB_NAME=snipeit_db # Environment-like variable (constant) +db_user="snipeit" # Local variable +``` + +--- + +## 3. **Dependencies** + +### 3.1 **Install all at once** + +- Install all dependencies with a single command if possible + +Example: + +```bash +$STD apt-get install -y \ + curl \ + composer \ + git \ + sudo \ + mc \ + nginx +``` + +### 3.2 **Collapse dependencies** + +Collapse dependencies to keep the code readable. + +Example: +Use + +```bash +php8.2-{bcmath,common,ctype} +``` + +instead of + +```bash +php8.2-bcmath php8.2-common php8.2-ctype +``` + +--- + +## 4. **Paths to application files** + +If possible install the app and all necessary files in `/opt/` + +--- + +## 5. **Version management** + +### 5.1 **Install the latest release** + +- Always try and install the latest release +- Do not hardcode any version if not absolutely necessary + +Example for a git release: + +```bash +RELEASE=$(curl -fsSL https://api.github.com/repos/snipe/snipe-it/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') +wget -q "https://github.com/snipe/snipe-it/archive/refs/tags/v${RELEASE}.zip" +``` + +### 5.2 **Save the version for update checks** + +- Write the installed version into a file. +- This is used for the update function in **AppName.sh** to check for if a Update is needed. + +Example: + +```bash +echo "${RELEASE}" >"/opt/AppName_version.txt" +``` + +--- + +## 6. **Input and output management** + +### 6.1 **User feedback** + +- Use standard functions like `msg_info`, `msg_ok` or `msg_error` to print status messages. +- Each `msg_info` must be followed with a `msg_ok` before any other output is made. +- Display meaningful progress messages at key stages. + +Example: + +```bash +msg_info "Installing Dependencies" +$STD apt-get install -y ... +msg_ok "Installed Dependencies" +``` + +### 6.2 **Verbosity** + +- Use the appropiate flag (**-q** in the examples) for a command to suppres its output +Example: + +```bash +wget -q +unzip -q +``` + +- If a command dose not come with such a functionality use `$STD` (a custom standard redirection variable) for managing output verbosity. + +Example: + +```bash +$STD apt-get install -y nginx +``` + +--- + +## 7. **String/File Manipulation** + +### 7.1 **File Manipulation** + +- Use `sed` to replace placeholder values in configuration files. + +Example: + +```bash +sed -i -e "s|^DB_DATABASE=.*|DB_DATABASE=$DB_NAME|" \ + -e "s|^DB_USERNAME=.*|DB_USERNAME=$DB_USER|" \ + -e "s|^DB_PASSWORD=.*|DB_PASSWORD=$DB_PASS|" .env +``` + +--- + +## 8. **Security practices** + +### 8.1 **Password generation** + +- Use `openssl` to generate random passwords. +- Use only alphanumeric values to not introduce unknown behaviour. + +Example: + +```bash +DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +``` + +### 8.2 **File permissions** + +Explicitly set secure ownership and permissions for sensitive files. + +Example: + +```bash +chown -R www-data: /opt/snipe-it +chmod -R 755 /opt/snipe-it +``` + +--- + +## 9. **Service Configuration** + +### 9.1 **Configuration files** + +Use `cat </etc/nginx/conf.d/snipeit.conf +server { + listen 80; + root /opt/snipe-it/public; + index index.php; +} +EOF +``` + +### 9.2 **Credential management** + +Store the generated credentials in a file. + +Example: + +```bash +USERNAME=username +PASSWORD=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +{ + echo "Application-Credentials" + echo "Username: $USERNAME" + echo "Password: $PASSWORD" +} >> ~/application.creds +``` + +### 9.3 **Enviroment files** + +Use `cat </path/to/.env +VARIABLE="value" +PORT=3000 +DB_NAME="${DB_NAME}" +EOF +``` + +### 9.4 **Services** + +Enable affected services after configuration changes and start them right away. + +Example: + +```bash +systemctl enable -q --now nginx +``` + +--- + +## 10. **Cleanup** + +### 10.1 **Remove temporary files** + +Remove temporary files and downloads after use. + +Example: + +```bash +rm -rf /opt/v${RELEASE}.zip +``` + +### 10.2 **Autoremove and autoclean** + +Remove unused dependencies to reduce disk space usage. + +Example: + +```bash +apt-get -y autoremove +apt-get -y autoclean +``` + +--- + +## 11. **Best Practices Checklist** + +- [ ] Shebang is correctly set (`#!/usr/bin/env bash`). +- [ ] Metadata (author, license) is included at the top. +- [ ] Variables follow naming conventions. +- [ ] Sensitive values are dynamically generated. +- [ ] Files and services have proper permissions. +- [ ] Script cleans up temporary files. + +--- + +### Example: High-Level Script Flow + +1. Dependencies installation +2. Database setup +3. Download and configure application +4. Service configuration +5. Final cleanup diff --git a/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh new file mode 100644 index 0000000..43ea76a --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 community-scripts ORG +# Author: [YourUserName] +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: [SOURCE_URL] + +# Import Functions und Setup +source /dev/stdin <<< "$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +# Installing Dependencies with the 3 core dependencies (curl;sudo;mc) +msg_info "Installing Dependencies" +$STD apt-get install -y \ + curl \ + sudo \ + mc \ + [PACKAGE_1] \ + [PACKAGE_2] \ + [PACKAGE_3] +msg_ok "Installed Dependencies" + +# Template: MySQL Database +msg_info "Setting up Database" +DB_NAME=[DB_NAME] +DB_USER=[DB_USER] +DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +$STD mysql -u root -e "CREATE DATABASE $DB_NAME;" +$STD mysql -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');" +$STD mysql -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;" +{ + echo "${APPLICATION} Credentials" + echo "Database User: $DB_USER" + echo "Database Password: $DB_PASS" + echo "Database Name: $DB_NAME" +} >> ~/$APP_NAME.creds +msg_ok "Set up Database" + +# Temp + +# Setup App +msg_info "Setup ${APPLICATION}" +RELEASE=$(curl -s https://api.github.com/repos/[REPO]/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') +wget -q "https://github.com/[REPO]/archive/refs/tags/${RELEASE}.zip" +unzip -q ${RELEASE}.zip +mv ${APPLICATION}-${RELEASE}/ /opt/${APPLICATION} +# +# +# +echo "${RELEASE}" >/opt/${APPLICATION}_version.txt +msg_ok "Setup ${APPLICATION}" + +# Creating Service (if needed) +msg_info "Creating Service" +cat </etc/systemd/system/${APPLICATION}.service +[Unit] +Description=${APPLICATION} Service +After=network.target + +[Service] +ExecStart=[START_COMMAND] +Restart=always + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now ${APPLICATION}.service +msg_ok "Created Service" + +motd_ssh +customize + +# Cleanup +msg_info "Cleaning up" +rm -f ${RELEASE}.zip +$STD apt-get -y autoremove +$STD apt-get -y autoclean +msg_ok "Cleaned" \ No newline at end of file diff --git a/.github/CONTRIBUTOR_AND_GUIDES/json/AppName.json b/.github/CONTRIBUTOR_AND_GUIDES/json/AppName.json new file mode 100644 index 0000000..746ebd9 --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/json/AppName.json @@ -0,0 +1,34 @@ +{ + "name": "AppName", + "slug": "appname", + "categories": [ + 0 + ], + "date_created": "DATE CREATED", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": DEFAULT-PORT, + "documentation": null, + "website": "LINK TO WEBSITE", + "logo": "LINK TO LOGO", + "description": "Description of the app", + "install_methods": [ + { + "type": "default", + "script": "ct/AppName.sh", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 4, + "os": "debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/.github/CONTRIBUTOR_AND_GUIDES/json/AppName.md b/.github/CONTRIBUTOR_AND_GUIDES/json/AppName.md new file mode 100644 index 0000000..0082e38 --- /dev/null +++ b/.github/CONTRIBUTOR_AND_GUIDES/json/AppName.md @@ -0,0 +1,13 @@ +# **AppName.json Files** + + `AppName.json` files found in the `/json` directory. These files are used to provide informations for the website. For this guide we take `/json/snipeit.json` as example. + +## Table of Contents + +- [**AppName.json Files**](#appnamejson-files) + - [Table of Contents](#table-of-contents) + - [1. JSON Generator](#1-json-generator) + +## 1. JSON Generator + +Use the [JSON Generator](https://community-scripts.github.io/ProxmoxVED/json-editor) to create this file for your application. diff --git a/.github/DISCUSSION_TEMPLATE/request-script.yml b/.github/DISCUSSION_TEMPLATE/request-script.yml new file mode 100644 index 0000000..a5278b7 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/request-script.yml @@ -0,0 +1,35 @@ +title: "[Script request] " +labels: ["enhancement"] +body: +- type: input + attributes: + label: Application Name + description: Enter the application name. + placeholder: "e.g., Home Assistant" + validations: + required: true +- type: input + attributes: + label: Website + description: Official website or github page. + placeholder: "e.g., https://www.home-assistant.io/" + validations: + required: true +- type: textarea + attributes: + label: Description + description: Explain what the application does and why it should be added to Proxmox VE Helper-Scripts. + placeholder: "e.g., Home Assistant is a popular open-source platform that brings all your smart home devices together in one place. Adding it to Proxmox VE Helper-Scripts would make setup and management on Proxmox easy, letting users quickly get a powerful, self-hosted smart home system up and running." + validations: + required: true +- type: checkboxes + attributes: + label: Due Diligence + options: + - label: "I have searched existing [scripts](https://community-scripts.github.io/Proxmox/scripts) and found no duplicates." + required: true + - label: "I have searched existing [discussions](https://github.com/community-scripts/ProxmoxVED/discussions?discussions_q=) and found no duplicate requests." + required: true +- type: markdown + attributes: + value: "Thanks for submitting your request! The team will review it and reach out if we need more information." diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..2f1c07d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +ko_fi: community_scripts +github: community_scripts diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..a850e64 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,100 @@ +name: "🐞 Script Issue Report" +description: Report a specific issue with a script. For other inquiries, please use the Discussions section. +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + # 🐞 **Script Issue Report** + Thank you for taking the time to report an issue! Please provide as much detail as possible to help us address the problem efficiently. + + ## ⚠️ **IMPORTANT - READ FIRST** + - 🔍 **Search first:** Before submitting, check if the issue has already been reported or resolved in [closed issues](https://github.com/community-scripts/ProxmoxVED/issues?q=is%3Aissue+is%3Aclosed). If found, comment on that issue instead of creating a new one. + Alternatively, check the **[Discussions](https://github.com/community-scripts/ProxmoxVED/discussions)** under the *"Announcement"* or *"Guide"* categories for relevant information. + - 🛠️ **Supported environments only:** Ensure you are using a default Linux distribution. Custom setups may not be supported. + - 🔎 If you encounter `[ERROR] in line 23: exit code *: while executing command "$@" > /dev/null 2>&1`, rerun the script with verbose mode before submitting the issue. + - 💡 For general questions, feature requests, or suggestions, use the [Discussions section](https://github.com/community-scripts/ProxmoxVED/discussions). + + - type: input + id: guidelines + attributes: + label: ✅ Have you read and understood the above guidelines? + placeholder: "yes" + validations: + required: true + + - type: input + id: script_name + attributes: + label: 📜 What is the name of the script you are using? + placeholder: "e.g., NextcloudPi, Zigbee2MQTT" + validations: + required: true + + - type: input + id: script_command + attributes: + label: 📂 What was the exact command used to execute the script? + placeholder: "e.g., bash -c \"$(wget -qLO - https://github.com/community-scripts/ProxmoxVED/raw/main/ct/zigbee2mqtt.sh)\" or \"update\"" + validations: + required: true + + - type: textarea + id: issue_description + attributes: + label: 📝 Provide a clear and concise description of the issue. + validations: + required: true + + - type: checkboxes + validations: + required: true + attributes: + label: ⚙️ What settings are you using? + options: + - label: Default Settings + - label: Advanced Settings + + - type: markdown + attributes: + value: "💡 **Tip:** If you are using Advanced Settings, please test with Default Settings before submitting an issue." + + - type: dropdown + id: linux_distribution + attributes: + label: 🖥️ Which Linux distribution are you using? + options: + - + - Alpine + - Debian 11 + - Debian 12 + - Ubuntu 20.04 + - Ubuntu 22.04 + - Ubuntu 24.04 + - Ubuntu 24.10 + validations: + required: true + + - type: textarea + id: steps_to_reproduce + attributes: + label: 🔄 Steps to reproduce the issue. + placeholder: "e.g., Step 1: ..., Step 2: ..." + validations: + required: true + + - type: textarea + id: error_output + attributes: + label: ❌ Paste the full error output (if available). + placeholder: "Include any relevant logs or error messages." + validations: + required: true + + - type: textarea + id: additional_context + attributes: + label: 🖼️ Additional context (optional). + placeholder: "Include screenshots, code blocks (use triple backticks ```), or any other relevant information." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..fac1dfc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: 🤔 Questions and Help + url: https://github.com/community-scripts/ProxmoxVED/discussions + about: For suggestions or questions, please use the Discussions section. + - name: 🌟 new Script request + url: https://github.com/community-scripts/ProxmoxVED/discussions/new?category=request-script + about: For feature/script requests, please use the Discussions section. + - name: 💻 Discord + url: https://discord.gg/UHrpNWGwkH + about: Join our Discord server to chat with other users in the Proxmox Helper Scripts community. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..7f06527 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,33 @@ +name: "✨ Feature Request" +description: "Suggest a new feature or enhancement." +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + # ✨ **Feature Request** + Have an idea for a new feature? Share your thoughts below! + + - type: input + id: feature_summary + attributes: + label: "🌟 Briefly describe the feature" + placeholder: "e.g., Add support for XYZ" + validations: + required: true + + - type: textarea + id: feature_description + attributes: + label: "📝 Detailed description" + placeholder: "Explain the feature in detail" + validations: + required: true + + - type: textarea + id: use_case + attributes: + label: "💡 Why is this useful?" + placeholder: "Describe the benefit of this feature" + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/frontend_report.yml b/.github/ISSUE_TEMPLATE/frontend_report.yml new file mode 100644 index 0000000..2871c97 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/frontend_report.yml @@ -0,0 +1,75 @@ +name: "🌐 Website Issue Report" +description: Report an issue, an optimization request or an documentation issue specifically related to the website. +labels: "website" + +body: + - type: markdown + attributes: + value: | + **IMPORTANT:** Failure to comply with the following guidelines may result in immediate closure. + - Prior to submitting, kindly search the closed issues to check if the problem you are reporting has already been addressed and resolved. If you come across a closed issue that pertains to your problem, please leave a comment on that issue instead of creating a new one. + - If the problem is related to a bug in the website, kindly check for browser compatibility and ensure the issue occurs in multiple browsers before submitting. + - For suggestions, questions, or feature requests, please use the [Discussions section.](https://github.com/community-scripts/ProxmoxVED/discussions) + + - type: input + id: guidelines + attributes: + label: Please verify that you have read and understood the guidelines. + placeholder: 'yes' + validations: + required: true + + - type: dropdown + id: issue_type + validations: + required: true + attributes: + label: What type of issue is this? + options: + - + - Bug + - Optimization + - Documentation + - Other + + - type: textarea + id: bug_description + attributes: + label: A clear and concise description of the issue. + validations: + required: true + + - type: dropdown + id: browser + validations: + required: true + attributes: + label: Which browser are you using? + options: + - + - Chrome + - Firefox + - Safari + - Edge + - Other + + - type: markdown + attributes: + value: | + **If the issue is browser-related**, please provide information on the version and platform (Windows, MacOS, Linux, etc.). + + - type: textarea + id: screenshot + attributes: + label: If relevant, including screenshots or a code block can be helpful in clarifying the issue. + placeholder: "Code blocks begin and conclude by enclosing the code with three backticks (```) above and below it." + validations: + required: false + + - type: textarea + id: reproduce + attributes: + label: Please provide detailed steps to reproduce the issue. + placeholder: "First do this, then this ..." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/task.yml b/.github/ISSUE_TEMPLATE/task.yml new file mode 100644 index 0000000..bf55692 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/task.yml @@ -0,0 +1,25 @@ +name: "🛠️ Task / General Request" +description: "Request a general task, improvement, or refactor." +labels: ["task"] +body: + - type: markdown + attributes: + value: | + # 🛠️ **Task / General Request** + Request a task that isn't a bug or feature request. + + - type: input + id: task_summary + attributes: + label: "📌 Task summary" + placeholder: "e.g., Refactor XYZ" + validations: + required: true + + - type: textarea + id: task_details + attributes: + label: "📋 Task details" + placeholder: "Explain what needs to be done" + validations: + required: true diff --git a/.github/autolabeler-config.json b/.github/autolabeler-config.json new file mode 100644 index 0000000..5406bda --- /dev/null +++ b/.github/autolabeler-config.json @@ -0,0 +1,76 @@ + +{ + "new script": [ + { + "fileStatus": "added", + "includeGlobs": ["ct/**", "install/**", "misc/**", "turnkey/**", "vm/**"], + "excludeGlobs": [] + } + ], + "update script": [ + { + "fileStatus": "modified", + "includeGlobs": ["ct/**", "install/**", "misc/**", "turnkey/**", "vm/**"], + "excludeGlobs": ["misc/build.func", "misc/install.func", "misc/api.func"] + } + ], + "delete script": [ + { + "fileStatus": "removed", + "includeGlobs": ["ct/**", "install/**", "misc/**", "turnkey/**", "vm/**"], + "excludeGlobs": [] + } + ], + "maintenance": [ + { + "fileStatus": null, + "includeGlobs": ["*.md", ".github/**", "misc/*.func", "ct/create_lxc.sh", "api/**"], + "excludeGlobs": [] + } + ], + "core": [ + { + "fileStatus": null, + "includeGlobs": ["misc/*.func", "ct/create_lxc.sh"], + "excludeGlobs": [] + } + ], + "website": [ + { + "fileStatus": null, + "includeGlobs": ["frontend/**", "json/**"], + "excludeGlobs": [] + } + ], + "api": [ + { + "fileStatus": null, + "includeGlobs": ["api/**", "misc/api.func"], + "excludeGlobs": [] + } + ], + "github": [ + { + "fileStatus": null, + "includeGlobs": [".github/**"], + "excludeGlobs": [] + } + ], + "json": [ + { + "fileStatus": "modified", + "includeGlobs": ["json/**"], + "excludeGlobs": [] + } + ], + + "high risk": [ + { + "fileStatus": null, + "includeGlobs": ["misc/build.func", "misc/install.func", "ct/create_lxc.sh"], + "excludeGlobs": [] + } + ] + + +} \ No newline at end of file diff --git a/.github/changelog-pr-config.json b/.github/changelog-pr-config.json new file mode 100644 index 0000000..2c62aa3 --- /dev/null +++ b/.github/changelog-pr-config.json @@ -0,0 +1,97 @@ +[ + { + "title": "🆕 New Scripts", + "labels": ["new script"] + }, + { + "title": "🚀 Updated Scripts", + "labels": ["update script"], + "subCategories": [ + { + "title": "🐞 Bug Fixes", + "labels": ["bugfix"], + "notes" : [] + }, + { + "title": "✨ New Features", + "labels": ["feature"], + "notes" : [] + }, + { + "title": "💥 Breaking Changes", + "labels": ["breaking change"], + "notes" : [] + } + ] + }, + { + "title": "🧰 Maintenance", + "labels": ["maintenance"], + "subCategories": [ + { + "title": "🐞 Bug Fixes", + "labels": ["bugfix"], + "notes" : [] + }, + { + "title": "✨ New Features", + "labels": ["feature"], + "notes" : [] + }, + { + "title": "💥 Breaking Changes", + "labels": ["breaking change"], + "notes" : [] + }, + { + "title": "📡 API", + "labels": ["api"], + "notes" : [] + }, + { + "title": "💾 Core", + "labels": ["core"], + "notes" : [] + }, + { + "title": "📂 Github", + "labels": ["github"], + "notes" : [] + } + ] + }, + { + "title": "🌐 Website", + "labels": ["website"], + "subCategories": [ + { + "title": "🐞 Bug Fixes", + "labels": ["bugfix"], + "notes" : [] + }, + { + "title": "✨ New Features", + "labels": ["feature"], + "notes" : [] + }, + { + "title": "💥 Breaking Changes", + "labels": ["breaking change"], + "notes" : [] + }, + { + "title": "📝 Script Information", + "labels": ["json"], + "notes" : [] + } + ] + }, + { + "title": "❔ Unlabelled", + "labels": [] + }, + { + "title": "💥 Breaking Changes", + "labels": ["breaking change"] + } +] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..d669ec7 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,25 @@ +## ✍️ Description + + +## 🔗 Related PR / Discussion / Issue + +Link: # + +## ✅ Prerequisites + +Before this PR can be reviewed, the following must be completed: + +- [] **Self-review performed** – Code follows established patterns and conventions. +- [] **Testing performed** – Changes have been thoroughly tested and verified. + +## 🛠️ Type of Change + +Select all that apply: + +- [] 🆕 **New script** – A fully functional and tested script or script set. +- [] 🐞 **Bug fix** – Resolves an issue without breaking functionality. +- [] ✨ **New feature** – Adds new, non-breaking functionality. +- [] 💥 **Breaking change** – Alters existing functionality in a way that may require updates. + +## 📋 Additional Information (optional) + diff --git a/.github/runner/docker/gh-runner-self.dockerfile b/.github/runner/docker/gh-runner-self.dockerfile new file mode 100644 index 0000000..e5ae072 --- /dev/null +++ b/.github/runner/docker/gh-runner-self.dockerfile @@ -0,0 +1,68 @@ +FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy as build + +ARG TARGETOS +ARG TARGETARCH +ARG DOCKER_VERSION=27.5.1 +ARG BUILDX_VERSION=0.20.1 +ARG RUNNER_ARCH="x64" + +RUN apt update -y && apt install sudo curl unzip -y + +WORKDIR /actions-runner + +RUN RUNNER_VERSION=$(curl -s https://api.github.com/repos/actions/runner/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \ + && curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz \ + && tar xzf ./runner.tar.gz \ + && rm runner.tar.gz + +RUN RUNNER_CONTAINER_HOOKS_VERSION=$(curl -s https://api.github.com/repos/actions/runner-container-hooks/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \ + && curl -f -L -o runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \ + && unzip ./runner-container-hooks.zip -d ./k8s \ + && rm runner-container-hooks.zip + +RUN export RUNNER_ARCH=${TARGETARCH} \ + && if [ "$RUNNER_ARCH" = "amd64" ]; then export DOCKER_ARCH=x86_64 ; fi \ + && if [ "$RUNNER_ARCH" = "arm64" ]; then export DOCKER_ARCH=aarch64 ; fi \ + && curl -fLo docker.tgz https://download.docker.com/${TARGETOS}/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz \ + && tar zxvf docker.tgz \ + && rm -rf docker.tgz \ + && mkdir -p /usr/local/lib/docker/cli-plugins \ + && curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \ + "https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-${TARGETARCH}" \ + && chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx + +FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy + +ENV DEBIAN_FRONTEND=noninteractive +ENV RUNNER_MANUALLY_TRAP_SIG=1 +ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1 +ENV ImageOS=ubuntu22 + +RUN apt update -y \ + && apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip \ + && rm -rf /var/lib/apt/lists/* + +RUN add-apt-repository ppa:git-core/ppa \ + && apt update -y \ + && apt install -y git \ + && rm -rf /var/lib/apt/lists/* + +RUN adduser --disabled-password --gecos "" --uid 1001 runner \ + && groupadd docker --gid 123 \ + && usermod -aG sudo runner \ + && usermod -aG docker runner \ + && echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \ + && echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers + +# Install own dependencies in final image +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ + && apt-get install -y gh jq git + +WORKDIR /home/runner + +COPY --chown=runner:docker --from=build /actions-runner . +COPY --from=build /usr/local/lib/docker/cli-plugins/docker-buildx /usr/local/lib/docker/cli-plugins/docker-buildx +RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker + +USER runner diff --git a/.github/workflows/auto-update-app-headers.yml b/.github/workflows/auto-update-app-headers.yml new file mode 100644 index 0000000..b6c4f2b --- /dev/null +++ b/.github/workflows/auto-update-app-headers.yml @@ -0,0 +1,106 @@ +name: Auto Update .app-files + +on: + push: + branches: + - main + paths: + - 'ct/**.sh' + workflow_dispatch: + +jobs: + update-app-files: + runs-on: runner-cluster-htl-set + + permissions: + contents: write + pull-requests: write + + steps: + - name: Generate a token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + # Step 1: Checkout repository + - name: Checkout repository + uses: actions/checkout@v2 + + # Step 2: Disable file mode changes detection + - name: Disable file mode changes + run: git config core.fileMode false + + # Step 3: Set up Git user for committing changes + - name: Set up Git + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + # Step 4: Install figlet + - name: Install figlet + run: sudo apt-get install -y figlet + + # Step 5: Run the updated generate-app-files.sh script + - name: Run generate-app-files.sh + run: | + chmod +x .github/workflows/scripts/generate-app-headers.sh + .github/workflows/scripts/generate-app-headers.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Step 6: Check if there are any changes + - name: Check if there are any changes + run: | + echo "Checking for changes..." + git add -A # Untracked Dateien aufnehmen + git status + if git diff --cached --quiet; then + echo "No changes detected." + echo "changed=false" >> "$GITHUB_ENV" + else + echo "Changes detected:" + git diff --stat --cached + echo "changed=true" >> "$GITHUB_ENV" + fi + + # Step 7: Commit and create PR if changes exist + - name: Commit and create PR if changes exist + if: env.changed == 'true' + run: | + git commit -m "Update .app files" + git checkout -b pr-update-app-files + git push origin pr-update-app-files --force + gh pr create --title "[core] update .app files" \ + --body "This PR is auto-generated by a GitHub Action to update the .app files." \ + --head pr-update-app-files \ + --base main \ + --label "automated pr" + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + + - name: Approve pull request + if: env.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head "pr-update-app-files" --json number --jq '.[].number') + if [ -n "$PR_NUMBER" ]; then + gh pr review $PR_NUMBER --approve + fi + + - name: Re-approve pull request after update + if: env.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head "pr-update-app-files" --json number --jq '.[].number') + if [ -n "$PR_NUMBER" ]; then + gh pr review $PR_NUMBER --approve + fi + + # Step 8: Output success message when no changes + - name: No changes detected + if: env.changed == 'false' + run: echo "No changes to commit. Workflow completed successfully." diff --git a/.github/workflows/autolabeler.yml b/.github/workflows/autolabeler.yml new file mode 100644 index 0000000..54647ea --- /dev/null +++ b/.github/workflows/autolabeler.yml @@ -0,0 +1,90 @@ +name: Auto Label Pull Requests + +on: + pull_request_target: + branches: ["main"] + types: [opened, synchronize, reopened, edited] + +jobs: + autolabeler: + runs-on: runner-cluster-htl-set + permissions: + pull-requests: write + env: + CONFIG_PATH: .github/autolabeler-config.json + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install minimatch + run: npm install minimatch + + - name: Label PR based on file changes and PR template + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs').promises; + const path = require('path'); + const { minimatch } = require('minimatch'); + + const configPath = path.resolve(process.env.CONFIG_PATH); + const fileContent = await fs.readFile(configPath, 'utf-8'); + const autolabelerConfig = JSON.parse(fileContent); + + const prNumber = context.payload.pull_request.number; + const prBody = context.payload.pull_request.body.toLowerCase(); + + let labelsToAdd = new Set(); + + const prListFilesResponse = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + const prFiles = prListFilesResponse.data; + + + + // Apply labels based on file changes + for (const [label, rules] of Object.entries(autolabelerConfig)) { + const shouldAddLabel = prFiles.some((prFile) => { + return rules.some((rule) => { + const isFileStatusMatch = rule.fileStatus ? rule.fileStatus === prFile.status : true; + const isIncludeGlobMatch = rule.includeGlobs.some((glob) => minimatch(prFile.filename, glob)); + const isExcludeGlobMatch = rule.excludeGlobs.some((glob) => minimatch(prFile.filename, glob)); + + return isFileStatusMatch && isIncludeGlobMatch && !isExcludeGlobMatch; + }); + }); + + if (shouldAddLabel) { + labelsToAdd.add(label); + } + } + const templateLabelMappings = { + "🐞 **Bug fix**": "bugfix", + "✨ **New feature**": "feature", + "💥 **Breaking change**": "breaking change", + }; + + for (const [checkbox, label] of Object.entries(templateLabelMappings)) { + const escapedCheckbox = checkbox.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); + const regex = new RegExp(`- \\[(x|X)\\]\\s*.*${escapedCheckbox}`, "i"); + const match = prBody.match(regex); + if (match) { + console.log(`Match: ${match}`); + labelsToAdd.add(label); + } + } + + console.log(`Labels to add: ${Array.from(labelsToAdd).join(", ")}`); + + if (labelsToAdd.size > 0) { + console.log(`Adding labels ${Array.from(labelsToAdd).join(", ")} to PR ${prNumber}`); + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: Array.from(labelsToAdd), + }); + } diff --git a/.github/workflows/backup/check_and_update_json_date.yml b/.github/workflows/backup/check_and_update_json_date.yml new file mode 100644 index 0000000..cde3cbb --- /dev/null +++ b/.github/workflows/backup/check_and_update_json_date.yml @@ -0,0 +1,60 @@ +name: Update date_created in JSON files + +on: + # Dieser Trigger wird für das Öffnen von PRs sowie für das Aktualisieren von offenen PRs verwendet + pull_request: + types: [opened, synchronize] + schedule: + # Dieser Trigger wird 4x am Tag ausgelöst, um sicherzustellen, dass das Datum aktualisiert wird + - cron: "0 0,6,12,18 * * *" # Führt alle 6 Stunden aus + workflow_dispatch: # Manuelle Ausführung des Workflows möglich + +jobs: + update-date: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install yq + run: | + sudo apt-get update + sudo apt-get install -y yq + + - name: Set the current date + id: set_date + run: echo "TODAY=$(date -u +%Y-%m-%d)" >> $GITHUB_ENV + + - name: Check for changes in PR + run: | + # Hole den PR-Branch + PR_BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge" + git fetch origin $PR_BRANCH + + # Liste alle JSON-Dateien im PR auf, die geändert wurden + CHANGED_JSON_FILES=$(git diff --name-only origin/main...$PR_BRANCH | grep '.json') + + if [ -z "$CHANGED_JSON_FILES" ]; then + echo "No JSON files changed in this PR." + exit 0 + fi + + # Gehe alle geänderten JSON-Dateien durch und aktualisiere das Datum + for file in $CHANGED_JSON_FILES; do + echo "Updating date_created in $file" + # Setze das aktuelle Datum + yq eval ".date_created = \"${{ env.TODAY }}\"" -i "$file" + git add "$file" + done + + - name: Commit and push changes + run: | + # Prüfe, ob es Änderungen gibt und committe sie + git config user.name "json-updater-bot" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git commit -m "Update date_created to ${{ env.TODAY }}" || echo "No changes to commit" + + # Push zurück in den PR-Branch + git push origin $PR_BRANCH diff --git a/.github/workflows/backup/shellcheck.yml b/.github/workflows/backup/shellcheck.yml new file mode 100644 index 0000000..4385fc8 --- /dev/null +++ b/.github/workflows/backup/shellcheck.yml @@ -0,0 +1,60 @@ +name: Shellcheck + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + schedule: + - cron: "5 1 * * *" + +jobs: + shellcheck: + name: Shellcheck + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + **.sh + + - name: Download ShellCheck + shell: bash + env: + INPUT_VERSION: "v0.10.0" + run: | + set -euo pipefail + if [[ "${{ runner.os }}" == "macOS" ]]; then + osvariant="darwin" + else + osvariant="linux" + fi + + baseurl="https://github.com/koalaman/shellcheck/releases/download" + curl -Lso "${{ github.workspace }}/sc.tar.xz" \ + "${baseurl}/${INPUT_VERSION}/shellcheck-${INPUT_VERSION}.${osvariant}.x86_64.tar.xz" + + tar -xf "${{ github.workspace }}/sc.tar.xz" -C "${{ github.workspace }}" + mv "${{ github.workspace }}/shellcheck-${INPUT_VERSION}/shellcheck" \ + "${{ github.workspace }}/shellcheck" + + - name: Verify ShellCheck binary + run: | + ls -l "${{ github.workspace }}/shellcheck" + + - name: Display ShellCheck version + run: | + "${{ github.workspace }}/shellcheck" --version + + - name: Run ShellCheck + if: steps.changed-files.outputs.any_changed == 'true' + env: + ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} + run: | + echo "${ALL_CHANGED_FILES}" | xargs "${{ github.workspace }}/shellcheck" diff --git a/.github/workflows/backup/update_json_date.yml.bak b/.github/workflows/backup/update_json_date.yml.bak new file mode 100644 index 0000000..cb9bc85 --- /dev/null +++ b/.github/workflows/backup/update_json_date.yml.bak @@ -0,0 +1,88 @@ +name: Auto Update JSON-Date + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + update-json-dates: + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - name: Generate a token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history for proper detection + + - name: Set up Git + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Find JSON files with incorrect date_created + id: find_wrong_json + run: | + TODAY=$(date -u +"%Y-%m-%d") + > incorrect_json_files.txt + + for FILE in json/*.json; do + if [[ -f "$FILE" ]]; then + DATE_IN_JSON=$(jq -r '.date_created' "$FILE" 2>/dev/null || echo "") + + if [[ "$DATE_IN_JSON" != "$TODAY" ]]; then + echo "$FILE" >> incorrect_json_files.txt + fi + fi + done + + if [[ -s incorrect_json_files.txt ]]; then + echo "CHANGED=true" >> $GITHUB_ENV + else + echo "CHANGED=false" >> $GITHUB_ENV + fi + + - name: Run update script + if: env.CHANGED == 'true' + run: | + chmod +x .github/workflows/scripts/update-json.sh + while read -r FILE; do + .github/workflows/scripts/update-json.sh "$FILE" + done < incorrect_json_files.txt + + - name: Commit and create PR if changes exist + if: env.CHANGED == 'true' + run: | + git add json/*.json + git commit -m "Auto-update date_created in incorrect JSON files" + git checkout -b pr-fix-json-dates + git push origin pr-fix-json-dates --force + gh pr create --title "[core] Fix incorrect JSON date_created fields" \ + --body "This PR is auto-generated to fix incorrect `date_created` fields in JSON files." \ + --head pr-fix-json-dates \ + --base main \ + --label "automated pr" + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + + - name: Approve pull request + if: env.CHANGED == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head "pr-fix-json-dates" --json number --jq '.[].number') + if [ -n "$PR_NUMBER" ]; then + gh pr review $PR_NUMBER --approve + fi diff --git a/.github/workflows/backup/validate-formatting.yaml.bak b/.github/workflows/backup/validate-formatting.yaml.bak new file mode 100644 index 0000000..8eadd0a --- /dev/null +++ b/.github/workflows/backup/validate-formatting.yaml.bak @@ -0,0 +1,133 @@ +name: Validate script formatting + +on: + push: + branches: + - main + pull_request_target: + paths: + - "**/*.sh" + - "**/*.func" + +jobs: + shfmt: + name: Check changed files + runs-on: ubuntu-latest + permissions: + + pull-requests: write + + steps: + - name: Get pull request information + if: github.event_name == 'pull_request_target' + uses: actions/github-script@v7 + id: pr + with: + script: | + const { data: pullRequest } = await github.rest.pulls.get({ + ...context.repo, + pull_number: context.payload.pull_request.number, + }); + return pullRequest; + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Ensure the full history is fetched for accurate diffing + ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }} + + - name: Get changed files + id: changed-files + run: | + if ${{ github.event_name == 'pull_request_target' }}; then + echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT + else + echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT + fi + + - name: Set up Go + if: steps.changed-files.outputs.files != '' + uses: actions/setup-go@v5 + + - name: Install shfmt + if: steps.changed-files.outputs.files != '' + run: | + go install mvdan.cc/sh/v3/cmd/shfmt@latest + echo "$GOPATH/bin" >> $GITHUB_PATH + + - name: Run shfmt + if: steps.changed-files.outputs.files != '' + id: shfmt + run: | + set +e + + + shfmt_output=$(shfmt -d ${{ steps.changed-files.outputs.files }}) + if [[ $? -eq 0 ]]; then + exit 0 + else + echo "diff=\"$(echo -n "$shfmt_output" | base64 -w 0)\"" >> $GITHUB_OUTPUT + printf "%s" "$shfmt_output" + exit 1 + fi + + - name: Post comment with results + if: always() && steps.changed-files.outputs.files != '' && github.event_name == 'pull_request_target' + uses: actions/github-script@v7 + with: + script: | + const result = "${{ job.status }}" === "success" ? "success" : "failure"; + const diff = Buffer.from( + ${{ steps.shfmt.outputs.diff }}, + "base64", + ).toString(); + const issueNumber = context.payload.pull_request + ? context.payload.pull_request.number + : null; + const commentIdentifier = "validate-formatting"; + let newCommentBody = `\n### Script formatting\n\n`; + + if (result === "failure") { + newCommentBody += + `:x: We found issues in the formatting of the following changed files:\n\n\`\`\`diff\n${diff}\n\`\`\`\n`; + } else { + newCommentBody += `:rocket: All changed shell scripts are formatted correctly!\n`; + } + + newCommentBody += `\n\n`; + + if (issueNumber) { + const { data: comments } = await github.rest.issues.listComments({ + ...context.repo, + issue_number: issueNumber, + }); + + const existingComment = comments.find( + (comment) => comment.user.login === "github-actions[bot]", + + ); + + if (existingComment) { + if (existingComment.body.includes(commentIdentifier)) { + const re = new RegExp( + String.raw`[\s\S]*?`, + "", + ); + newCommentBody = existingComment.body.replace(re, newCommentBody); + } else { + newCommentBody = existingComment.body + "\n\n---\n\n" + newCommentBody; + } + + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existingComment.id, + body: newCommentBody, + }); + } else { + await github.rest.issues.createComment({ + ...context.repo, + issue_number: issueNumber, + body: newCommentBody, + }); + } + } diff --git a/.github/workflows/backup/validate-scripts.yml.bak b/.github/workflows/backup/validate-scripts.yml.bak new file mode 100644 index 0000000..acb8613 --- /dev/null +++ b/.github/workflows/backup/validate-scripts.yml.bak @@ -0,0 +1,234 @@ +name: Validate scripts +on: + push: + branches: + - main + pull_request_target: + paths: + - "ct/*.sh" + - "install/*.sh" + +jobs: + check-scripts: + name: Check changed files + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - name: Debug event payload + run: | + echo "Event name: ${{ github.event_name }}" + echo "Payload: $(cat $GITHUB_EVENT_PATH)" + + - name: Get pull request information + if: github.event_name == 'pull_request_target' + uses: actions/github-script@v7 + id: pr + with: + script: | + const { data: pullRequest } = await github.rest.pulls.get({ + ...context.repo, + pull_number: context.payload.pull_request.number, + }); + return pullRequest; + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }} + + - name: Get changed files + id: changed-files + run: | + if [ "${{ github.event_name }}" == "pull_request_target" ]; then + echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT + else + echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT + fi + + - name: Check build.func line + if: always() && steps.changed-files.outputs.files != '' + id: build-func + run: | + NON_COMPLIANT_FILES="" + for FILE in ${{ steps.changed-files.outputs.files }}; do + if [[ "$FILE" == ct/* ]] && [[ $(sed -n '2p' "$FILE") != "source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)" ]]; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "Build.func line missing or incorrect in files:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: Check executable permissions + if: always() && steps.changed-files.outputs.files != '' + id: check-executable + run: | + NON_COMPLIANT_FILES="" + for FILE in ${{ steps.changed-files.outputs.files }}; do + if [[ ! -x "$FILE" ]]; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "Files not executable:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: Check copyright + if: always() && steps.changed-files.outputs.files != '' + id: check-copyright + run: | + NON_COMPLIANT_FILES="" + for FILE in ${{ steps.changed-files.outputs.files }}; do + if ! sed -n '3p' "$FILE" | grep -qE "^# Copyright \(c\) [0-9]{4}(-[0-9]{4})? (tteck \| community-scripts ORG|community-scripts ORG|tteck)$"; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "Copyright header missing or not on line 3 in files:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: Check author + if: always() && steps.changed-files.outputs.files != '' + id: check-author + run: | + NON_COMPLIANT_FILES="" + for FILE in ${{ steps.changed-files.outputs.files }}; do + if ! sed -n '4p' "$FILE" | grep -qE "^# Author: .+"; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "Author header missing or invalid on line 4 in files:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: Check license + if: always() && steps.changed-files.outputs.files != '' + id: check-license + run: | + NON_COMPLIANT_FILES="" + for FILE in ${{ steps.changed-files.outputs.files }}; do + if [[ "$(sed -n '5p' "$FILE")" != "# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE" ]]; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "License header missing or not on line 5 in files:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: Check source + if: always() && steps.changed-files.outputs.files != '' + id: check-source + run: | + NON_COMPLIANT_FILES="" + for FILE in ${{ steps.changed-files.outputs.files }}; do + if ! sed -n '6p' "$FILE" | grep -qE "^# Source: .+"; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "Source header missing or not on line 6 in files:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: Post results and comment + if: always() && steps.changed-files.outputs.files != '' && github.event_name == 'pull_request_target' + uses: actions/github-script@v7 + with: + script: | + const result = '${{ job.status }}' === 'success' ? 'success' : 'failure'; + const nonCompliantFiles = { + 'Invalid build.func source': "${{ steps.build-func.outputs.files || '' }}", + 'Not executable': "${{ steps.check-executable.outputs.files || '' }}", + 'Copyright header line missing or invalid': "${{ steps.check-copyright.outputs.files || '' }}", + 'Author header line missing or invalid': "${{ steps.check-author.outputs.files || '' }}", + 'License header line missing or invalid': "${{ steps.check-license.outputs.files || '' }}", + 'Source header line missing or invalid': "${{ steps.check-source.outputs.files || '' }}" + }; + + const issueNumber = context.payload.pull_request ? context.payload.pull_request.number : null; + const commentIdentifier = 'validate-scripts'; + let newCommentBody = `\n### Script validation\n\n`; + + if (result === 'failure') { + newCommentBody += ':x: We found issues in the following changed files:\n\n'; + for (const [check, files] of Object.entries(nonCompliantFiles)) { + if (files) { + newCommentBody += `**${check}:**\n`; + files.trim().split(' ').forEach(file => { + newCommentBody += `- ${file}: ${check}\n`; + }); + newCommentBody += `\n`; + } + } + } else { + newCommentBody += `:rocket: All changed shell scripts passed validation!\n`; + } + + newCommentBody += `\n\n`; + + if (issueNumber) { + const { data: comments } = await github.rest.issues.listComments({ + ...context.repo, + issue_number: issueNumber + }); + + const existingComment = comments.find(comment => + comment.body.includes(``) && + comment.user.login === 'github-actions[bot]' + ); + + if (existingComment) { + const re = new RegExp(String.raw`[\\s\\S]*?`, "m"); + newCommentBody = existingComment.body.replace(re, newCommentBody); + + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existingComment.id, + body: newCommentBody + }); + } else { + await github.rest.issues.createComment({ + ...context.repo, + issue_number: issueNumber, + body: newCommentBody + }); + } + } diff --git a/.github/workflows/changelog-pr.yml b/.github/workflows/changelog-pr.yml new file mode 100644 index 0000000..036ef7a --- /dev/null +++ b/.github/workflows/changelog-pr.yml @@ -0,0 +1,226 @@ +name: Create Changelog Pull Request + +on: + push: + branches: ["main"] + workflow_dispatch: + +jobs: + update-changelog-pull-request: + runs-on: runner-cluster-htl-set + env: + CONFIG_PATH: .github/changelog-pr-config.json + BRANCH_NAME: github-action-update-changelog + AUTOMATED_PR_LABEL: "automated pr" + permissions: + contents: write + pull-requests: write + steps: + - name: Generate a token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get latest dates in changelog + run: | + DATES=$(grep -E '^## [0-9]{4}-[0-9]{2}-[0-9]{2}' CHANGELOG.md | head -n 2 | awk '{print $2}') + + LATEST_DATE=$(echo "$DATES" | sed -n '1p') + SECOND_LATEST_DATE=$(echo "$DATES" | sed -n '2p') + TODAY=$(date -u +%Y-%m-%d) + + echo "TODAY=$TODAY" >> $GITHUB_ENV + if [[ "$LATEST_DATE" == "$TODAY" ]]; then + echo "LATEST_DATE=$SECOND_LATEST_DATE" >> $GITHUB_ENV + else + echo "LATEST_DATE=$LATEST_DATE" >> $GITHUB_ENV + fi + + - name: Get categorized pull requests + id: get-categorized-prs + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs').promises; + const path = require('path'); + + const configPath = path.resolve(process.env.CONFIG_PATH); + const fileContent = await fs.readFile(configPath, 'utf-8'); + const changelogConfig = JSON.parse(fileContent); + + const categorizedPRs = changelogConfig.map(obj => ({ + ...obj, + notes: [], + subCategories: obj.subCategories ?? ( + obj.labels.includes("update script") ? [ + { title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] }, + { title: "✨ New Features", labels: ["feature"], notes: [] }, + { title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] } + ] : + obj.labels.includes("maintenance") ? [ + { title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] }, + { title: "✨ New Features", labels: ["feature"], notes: [] }, + { title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] }, + { title: "📡 API", labels: ["api"], notes: [] }, + { title: "Github", labels: ["github"], notes: [] } + ] : + obj.labels.includes("website") ? [ + { title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] }, + { title: "✨ New Features", labels: ["feature"], notes: [] }, + { title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] }, + { title: "Script Information", labels: ["json"], notes: [] } + ] : [] + ) + })); + + const latestDateInChangelog = new Date(process.env.LATEST_DATE); + latestDateInChangelog.setUTCHours(23, 59, 59, 999); + + const { data: pulls } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + base: "main", + state: "closed", + sort: "updated", + direction: "desc", + per_page: 100, + }); + + pulls.filter(pr => + pr.merged_at && + new Date(pr.merged_at) > latestDateInChangelog && + !pr.labels.some(label => + ["invalid", "wontdo", process.env.AUTOMATED_PR_LABEL].includes(label.name.toLowerCase()) + ) + ).forEach(pr => { + + const prLabels = pr.labels.map(label => label.name.toLowerCase()); + const prNote = `- ${pr.title} [@${pr.user.login}](https://github.com/${pr.user.login}) ([#${pr.number}](${pr.html_url}))`; + + const updateScriptsCategory = categorizedPRs.find(category => + category.labels.some(label => prLabels.includes(label)) + ); + + if (updateScriptsCategory) { + + const subCategory = updateScriptsCategory.subCategories.find(sub => + sub.labels.some(label => prLabels.includes(label)) + ); + + if (subCategory) { + subCategory.notes.push(prNote); + } else { + updateScriptsCategory.notes.push(prNote); + } + } + }); + + console.log(JSON.stringify(categorizedPRs, null, 2)); + + return categorizedPRs; + + + - name: Update CHANGELOG.md + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs').promises; + const path = require('path'); + + const today = process.env.TODAY; + const latestDateInChangelog = process.env.LATEST_DATE; + const changelogPath = path.resolve('CHANGELOG.md'); + const categorizedPRs = ${{ steps.get-categorized-prs.outputs.result }}; + + console.log(JSON.stringify(categorizedPRs, null, 2)); + + + let newReleaseNotes = `## ${today}\n\n`; + for (const { title, notes, subCategories } of categorizedPRs) { + const hasSubcategories = subCategories && subCategories.length > 0; + const hasMainNotes = notes.length > 0; + const hasSubNotes = hasSubcategories && subCategories.some(sub => sub.notes && sub.notes.length > 0); + + + if (hasMainNotes || hasSubNotes) { + newReleaseNotes += `### ${title}\n\n`; + } + + if (hasMainNotes) { + newReleaseNotes += ` ${notes.join("\n")}\n\n`; + } + if (hasSubcategories) { + for (const { title: subTitle, notes: subNotes } of subCategories) { + if (subNotes && subNotes.length > 0) { + newReleaseNotes += ` - #### ${subTitle}\n\n`; + newReleaseNotes += ` ${subNotes.join("\n ")}\n\n`; + } + } + } + } + + const changelogContent = await fs.readFile(changelogPath, 'utf-8'); + const changelogIncludesTodaysReleaseNotes = changelogContent.includes(`\n## ${today}`); + + const regex = changelogIncludesTodaysReleaseNotes + ? new RegExp(`## ${today}.*(?=## ${latestDateInChangelog})`, "gs") + : new RegExp(`(?=## ${latestDateInChangelog})`, "gs"); + + const newChangelogContent = changelogContent.replace(regex, newReleaseNotes); + await fs.writeFile(changelogPath, newChangelogContent); + + - name: Check for changes + id: verify-diff + run: | + git diff --quiet . || echo "changed=true" >> $GITHUB_ENV + + - name: Commit and push changes + if: env.changed == 'true' + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add CHANGELOG.md + git commit -m "Update CHANGELOG.md" + git checkout -b $BRANCH_NAME || git checkout $BRANCH_NAME + git push origin $BRANCH_NAME --force + + - name: Create pull request if not exists + if: env.changed == 'true' + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + PR_EXISTS=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number') + if [ -z "$PR_EXISTS" ]; then + gh pr create --title "[Github Action] Update CHANGELOG.md" \ + --body "This PR is auto-generated by a Github Action to update the CHANGELOG.md file." \ + --head $BRANCH_NAME \ + --base main \ + --label "$AUTOMATED_PR_LABEL" + fi + + - name: Approve pull request + if: env.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number') + if [ -n "$PR_NUMBER" ]; then + gh pr review $PR_NUMBER --approve + fi + + - name: Re-approve pull request after update + if: env.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number') + if [ -n "$PR_NUMBER" ]; then + gh pr review $PR_NUMBER --approve + fi \ No newline at end of file diff --git a/.github/workflows/close-discussion.yml b/.github/workflows/close-discussion.yml new file mode 100644 index 0000000..dd9a80b --- /dev/null +++ b/.github/workflows/close-discussion.yml @@ -0,0 +1,122 @@ +name: Close Discussion on PR Merge + +on: + pull_request: + types: [closed] + +jobs: + close-discussion: + runs-on: runner-cluster-htl-set + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set Up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + - name: Install Dependencies + run: npm install zx @octokit/graphql + + - name: Close Discussion + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_BODY: ${{ github.event.pull_request.body }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO_OWNER: ${{ github.repository_owner }} + REPO_NAME: ${{ github.event.repository.name }} + run: | + npx zx << 'EOF' + import { graphql } from "@octokit/graphql"; + (async function() { + try { + const token = process.env.GITHUB_TOKEN; + const prBody = process.env.PR_BODY; + const prNumber = process.env.PR_NUMBER; + const owner = process.env.REPO_OWNER; + const repo = process.env.REPO_NAME; + + if (!token || !prBody || !prNumber || !owner || !repo) { + console.log("Missing required environment variables."); + process.exit(1); + } + + const match = prBody.match(/#(\d+)/); + if (!match) { + console.log("No discussion ID found in PR body."); + return; + } + const discussionNumber = match[1]; + + console.log(`Extracted Discussion Number: ${discussionNumber}`); + console.log(`PR Number: ${prNumber}`); + console.log(`Repository: ${owner}/${repo}`); + + const graphqlWithAuth = graphql.defaults({ + headers: { authorization: `Bearer ${token}` }, + }); + + const discussionQuery = ` + query($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { + discussion(number: $number) { + id + } + } + } + `; + + const discussionResponse = await graphqlWithAuth(discussionQuery, { + owner, + repo, + number: parseInt(discussionNumber, 10), + }); + + const discussionQLId = discussionResponse.repository.discussion.id; + if (!discussionQLId) { + console.log("Failed to fetch discussion GraphQL ID."); + return; + } + + console.log(`GraphQL Discussion ID: ${discussionQLId}`); + + const commentMutation = ` + mutation($discussionId: ID!, $body: String!) { + addDiscussionComment(input: { discussionId: $discussionId, body: $body }) { + comment { id body } + } + } + `; + + const commentResponse = await graphqlWithAuth(commentMutation, { + discussionId: discussionQLId, + body: `Merged with PR #${prNumber}`, + }); + + const commentId = commentResponse.addDiscussionComment.comment.id; + if (!commentId) { + console.log("Failed to post the comment."); + return; + } + + console.log(`Comment Posted Successfully! Comment ID: ${commentId}`); + + const markAnswerMutation = ` + mutation($id: ID!) { + markDiscussionCommentAsAnswer(input: { id: $id }) { + discussion { id title } + } + } + `; + + await graphqlWithAuth(markAnswerMutation, { id: commentId }); + + console.log("Comment marked as answer successfully!"); + + } catch (error) { + console.error("Error:", error); + return; + } + })(); + EOF \ No newline at end of file diff --git a/.github/workflows/create-docker-for-runner.yml b/.github/workflows/create-docker-for-runner.yml new file mode 100644 index 0000000..c9fef0a --- /dev/null +++ b/.github/workflows/create-docker-for-runner.yml @@ -0,0 +1,37 @@ +name: Build and Publish Docker Image + +on: + push: + branches: + - main + paths: + - '.github/runner/docker/**' + schedule: + - cron: '0 0 * * *' + +jobs: + build: + runs-on: ubuntu-latest #To ensure it always builds we use the github runner with all the right tooling + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Log in to GHCR + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Docker image + run: | + repo_name=${{ github.repository }} # Get repository name + repo_name_lower=$(echo $repo_name | tr '[:upper:]' '[:lower:]') # Convert to lowercase + docker build -t ghcr.io/$repo_name_lower/gh-runner-self:latest -f .github/runner/docker/gh-runner-self.dockerfile . + + - name: Push Docker image to GHCR + run: | + repo_name=${{ github.repository }} # Get repository name + repo_name_lower=$(echo $repo_name | tr '[:upper:]' '[:lower:]') # Convert to lowercase + docker push ghcr.io/$repo_name_lower/gh-runner-self:latest diff --git a/.github/workflows/delete-json-branch.yml b/.github/workflows/delete-json-branch.yml new file mode 100644 index 0000000..b728684 --- /dev/null +++ b/.github/workflows/delete-json-branch.yml @@ -0,0 +1,28 @@ + +name: Delete JSON date PR Branch + +on: + pull_request: + types: [closed] + branches: + - main + +jobs: + delete_branch: + runs-on: runner-cluster-htl-set + steps: + - name: Checkout the code + uses: actions/checkout@v3 + + - name: Delete PR Update Branch + if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'pr-update-json-') + run: | + PR_BRANCH="${{ github.event.pull_request.head.ref }}" + echo "Deleting branch $PR_BRANCH..." + + # Avoid deleting the default branch (e.g., main) + if [[ "$PR_BRANCH" != "main" ]]; then + git push origin --delete "$PR_BRANCH" + else + echo "Skipping deletion of the main branch" + fi \ No newline at end of file diff --git a/.github/workflows/frontend-cicd.yml b/.github/workflows/frontend-cicd.yml new file mode 100644 index 0000000..c4f1a64 --- /dev/null +++ b/.github/workflows/frontend-cicd.yml @@ -0,0 +1,78 @@ +# Based on https://github.com/actions/starter-workflows/blob/main/pages/nextjs.yml + +name: Frontend CI/CD + +on: + push: + branches: ["main"] + paths: + - frontend/** + - json/** + + pull_request: + branches: ["main"] + types: [opened, synchronize, reopened, edited] + paths: + - frontend/** + - json/** + + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: pages-${{ github.ref }} + cancel-in-progress: false + +jobs: + build: + runs-on: runner-cluster-htl-set + defaults: + run: + working-directory: frontend # Set default working directory for all run steps + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Install dependencies + run: npm ci --prefer-offline --legacy-peer-deps + + - name: Run tests + run: npm run test + + - name: Configure Next.js for pages + uses: actions/configure-pages@v5 + with: + static_site_generator: next + + - name: Build with Next.js + run: npm run build + + - name: Upload artifact + if: github.ref == 'refs/heads/main' + uses: actions/upload-pages-artifact@v3 + with: + path: frontend/out + + deploy: + runs-on: ubuntu-latest + needs: build + if: github.ref == 'refs/heads/main' + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml new file mode 100644 index 0000000..605cefe --- /dev/null +++ b/.github/workflows/github-release.yml @@ -0,0 +1,57 @@ +name: Create Daily Release + +on: + schedule: + - cron: '1 0 * * *' # Runs daily at 00:01 UTC + workflow_dispatch: + +jobs: + create-daily-release: + runs-on: runner-cluster-htl-set + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Extract first 5000 characters from CHANGELOG.md + run: head -c 5000 CHANGELOG.md > changelog_cropped.md + + - name: Debugging - Show extracted changelog + run: | + echo "=== CHANGELOG EXCERPT ===" + cat changelog_cropped.md + echo "=========================" + + - name: Parse CHANGELOG.md and create release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + YESTERDAY=$(date -u --date="yesterday" +%Y-%m-%d) + echo "Checking for changes on: $YESTERDAY" + + # Ensure yesterday's date exists in the changelog + if ! grep -q "## $YESTERDAY" changelog_cropped.md; then + echo "No entry found for $YESTERDAY, skipping release." + exit 0 + fi + + # Extract section for yesterday's date + awk -v date="## $YESTERDAY" ' + $0 ~ date {found=1; next} + found && /^## [0-9]{4}-[0-9]{2}-[0-9]{2}/ {exit} + found + ' changelog_cropped.md > changelog_tmp.md + + echo "=== Extracted Changelog ===" + cat changelog_tmp.md + echo "===========================" + + # Skip if no content was found + if [ ! -s changelog_tmp.md ]; then + echo "No changes found for $YESTERDAY, skipping release." + exit 0 + fi + + # Create GitHub release + gh release create "$YESTERDAY" -t "$YESTERDAY" -F changelog_tmp.md diff --git a/.github/workflows/script-test.yml b/.github/workflows/script-test.yml new file mode 100644 index 0000000..272a127 --- /dev/null +++ b/.github/workflows/script-test.yml @@ -0,0 +1,177 @@ +name: Run Scripts on PVE Node for testing +permissions: + pull-requests: write +on: + pull_request_target: + branches: + - main + paths: + - 'install/**.sh' + - 'ct/**.sh' + +jobs: + run-install-script: + runs-on: pvenode + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + fetch-depth: 0 + + - name: Add Git safe directory + run: | + git config --global --add safe.directory /__w/ProxmoxVED/ProxmoxVE + + - name: Set up GH_TOKEN + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV + + - name: Get Changed Files + run: | + CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only) + CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ') + echo "Changed files: $CHANGED_FILES" + echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + + - name: Get scripts + id: check-install-script + run: | + ALL_FILES=() + ADDED_FILES=() + for FILE in ${{ env.SCRIPT }}; do + if [[ $FILE =~ ^install/.*-install\.sh$ ]] || [[ $FILE =~ ^ct/.*\.sh$ ]]; then + STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') + if [[ ! " ${ADDED_FILES[@]} " =~ " $STRIPPED_NAME " ]]; then + ALL_FILES+=("$FILE") + ADDED_FILES+=("$STRIPPED_NAME") # Mark this base file as added (without the path) + fi + fi + done + ALL_FILES=$(echo "${ALL_FILES[@]}" | xargs) + echo "$ALL_FILES" + echo "ALL_FILES=$ALL_FILES" >> $GITHUB_ENV + + - name: Run scripts + id: run-install + continue-on-error: true + run: | + set +e + #run for each files in /ct + for FILE in ${{ env.ALL_FILES }}; do + STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') + echo "Running Test for: $STRIPPED_NAME" + if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "$FILE"; then + echo "The script contains an interactive prompt. Skipping execution." + continue + fi + if [[ $FILE =~ ^install/.*-install\.sh$ ]]; then + CT_SCRIPT="ct/$STRIPPED_NAME.sh" + if [[ ! -f $CT_SCRIPT ]]; then + echo "No CT script found for $STRIPPED_NAME" + ERROR_MSG="No CT script found for $FILE" + echo "$ERROR_MSG" > result_$STRIPPED_NAME.log + continue + fi + if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "install/$STRIPPED_NAME-install.sh"; then + echo "The script contains an interactive prompt. Skipping execution." + continue + fi + echo "Found CT script for $STRIPPED_NAME" + chmod +x "$CT_SCRIPT" + RUNNING_FILE=$CT_SCRIPT + elif [[ $FILE =~ ^ct/.*\.sh$ ]]; then + INSTALL_SCRIPT="install/$STRIPPED_NAME-install.sh" + if [[ ! -f $INSTALL_SCRIPT ]]; then + echo "No install script found for $STRIPPED_NAME" + ERROR_MSG="No install script found for $FILE" + echo "$ERROR_MSG" > result_$STRIPPED_NAME.log + continue + fi + echo "Found install script for $STRIPPED_NAME" + chmod +x "$INSTALL_SCRIPT" + RUNNING_FILE=$FILE + if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "ct/$STRIPPED_NAME.sh"; then + echo "The script contains an interactive prompt. Skipping execution." + continue + fi + fi + git remote add community-scripts https://github.com/community-scripts/ProxmoxVE.git + git fetch community-scripts + rm -f .github/workflows/scripts/app-test/pr-build.func || true + rm -f .github/workflows/scripts/app-test/pr-install.func || true + rm -f .github/workflows/scripts/app-test/pr-alpine-install.func || true + rm -f .github/workflows/scripts/app-test/pr-create-lxc.sh || true + git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-build.func + git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-install.func + git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-alpine-install.func + git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-create-lxc.sh + chmod +x $RUNNING_FILE + chmod +x .github/workflows/scripts/app-test/pr-create-lxc.sh + chmod +x .github/workflows/scripts/app-test/pr-install.func + chmod +x .github/workflows/scripts/app-test/pr-alpine-install.func + chmod +x .github/workflows/scripts/app-test/pr-build.func + sed -i 's|source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)|source .github/workflows/scripts/app-test/pr-build.func|g' "$RUNNING_FILE" + echo "Executing $RUNNING_FILE" + ERROR_MSG=$(./$RUNNING_FILE 2>&1 > /dev/null) + echo "Finished running $FILE" + if [ -n "$ERROR_MSG" ]; then + echo "ERROR in $STRIPPED_NAME: $ERROR_MSG" + echo "$ERROR_MSG" > result_$STRIPPED_NAME.log + fi + done + set -e # Restore exit-on-error + + - name: Cleanup PVE Node + run: | + containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}' | awk '{print $1}') + + for container_id in $containers; do + status=$(pct status $container_id | awk '{print $2}') + if [[ $status == "running" ]]; then + pct stop $container_id + pct destroy $container_id + fi + done + + - name: Post error comments + run: | + ERROR="false" + SEARCH_LINE=".github/workflows/scripts/app-test/pr-build.func: line 255:" + + # Get all existing comments on the PR + EXISTING_COMMENTS=$(gh pr view ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --json comments --jq '.comments[].body') + + for FILE in ${{ env.ALL_FILES }}; do + STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') + if [[ ! -f result_$STRIPPED_NAME.log ]]; then + continue + fi + ERROR_MSG=$(cat result_$STRIPPED_NAME.log) + + if [ -n "$ERROR_MSG" ]; then + CLEANED_ERROR_MSG=$(echo "$ERROR_MSG" | sed "s|$SEARCH_LINE.*||") + COMMENT_BODY=":warning: The script _**$FILE**_ failed with the following message:
${CLEANED_ERROR_MSG}
" + + # Check if the comment already exists + if echo "$EXISTING_COMMENTS" | grep -qF "$COMMENT_BODY"; then + echo "Skipping duplicate comment for $FILE" + else + echo "Posting error message for $FILE" + gh pr comment ${{ github.event.pull_request.number }} \ + --repo ${{ github.repository }} \ + --body "$COMMENT_BODY" + ERROR="true" + fi + fi + done + + echo "ERROR=$ERROR" >> $GITHUB_ENV + + diff --git a/.github/workflows/script_format.yml b/.github/workflows/script_format.yml new file mode 100644 index 0000000..c8ea7a4 --- /dev/null +++ b/.github/workflows/script_format.yml @@ -0,0 +1,243 @@ +name: Script Format Check +permissions: + pull-requests: write +on: + pull_request_target: + branches: + - main + paths: + - 'install/*.sh' + - 'ct/*.sh' + +jobs: + run-install-script: + runs-on: pvenode + steps: + - name: Checkout PR branch (supports forks) + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + fetch-depth: 0 + + - name: Add Git safe directory + run: | + git config --global --add safe.directory /__w/ProxmoxVED/ProxmoxVE + + - name: Set up GH_TOKEN + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV + + - name: Get Changed Files + run: | + CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only) + CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ') + echo "Changed files: $CHANGED_FILES" + echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check scripts + id: run-install + continue-on-error: true + run: | + for FILE in ${{ env.SCRIPT }}; do + STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') + echo "Running Test for: $STRIPPED_NAME" + FILE_STRIPPED="${FILE##*/}" + LOG_FILE="result_$FILE_STRIPPED.log" + + if [[ $FILE =~ ^ct/.*\.sh$ ]]; then + + FIRST_LINE=$(sed -n '1p' "$FILE") + [[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE" + SECOND_LINE=$(sed -n '2p' "$FILE") + [[ "$SECOND_LINE" != "source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)" ]] && + echo "Line 2 was $SECOND_LINE | Should be: source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)" >> "$LOG_FILE" + THIRD_LINE=$(sed -n '3p' "$FILE") + if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then + echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2025 community-scripts ORG" >> "$LOG_FILE" + fi + + EXPECTED_AUTHOR="# Author:" + EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE" + EXPECTED_SOURCE="# Source:" + EXPECTED_EMPTY="" + + for i in {4..7}; do + LINE=$(sed -n "${i}p" "$FILE") + + case $i in + 4) + [[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE + ;; + 5) + [[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE + ;; + 6) + [[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE + ;; + 7) + [[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE + ;; + esac + done + + + EXPECTED_PREFIXES=( + "APP=" + "var_tags=" + "var_cpu=" # Must be a number + "var_ram=" # Must be a number + "var_disk=" # Must be a number + "var_os=" # Must be debian, alpine, or ubuntu + "var_version=" + "var_unprivileged=" # Must be 0 or 1 + ) + + + for i in {8..15}; do + LINE=$(sed -n "${i}p" "$FILE") + INDEX=$((i - 8)) + + case $INDEX in + 2|3|4) # var_cpu, var_ram, var_disk (must be numbers) + if [[ "$LINE" =~ ^${EXPECTED_PREFIXES[$INDEX]}([0-9]+)$ ]]; then + continue # Valid + else + echo "Line $i was '$LINE' | Should be: '${EXPECTED_PREFIXES[$INDEX]}'" >> "$LOG_FILE" + fi + ;; + 5) # var_os (must be debian, alpine, or ubuntu) + if [[ "$LINE" =~ ^var_os=(debian|alpine|ubuntu)$ ]]; then + continue # Valid + else + echo "Line $i was '$LINE' | Should be: 'var_os=[debian|alpine|ubuntu]'" >> "$LOG_FILE" + fi + ;; + 7) # var_unprivileged (must be 0 or 1) + if [[ "$LINE" =~ ^var_unprivileged=[01]$ ]]; then + continue # Valid + else + echo "Line $i was '$LINE' | Should be: 'var_unprivileged=[0|1]'" >> "$LOG_FILE" + fi + ;; + *) # Other lines (must start with expected prefix) + if [[ "$LINE" == ${EXPECTED_PREFIXES[$INDEX]}* ]]; then + continue # Valid + else + echo "Line $i was '$LINE' | Should start with '${EXPECTED_PREFIXES[$INDEX]}'" >> "$LOG_FILE" + fi + ;; + esac + done + + for i in {16..20}; do + LINE=$(sed -n "${i}p" "$FILE") + EXPECTED=( + "header_info \"$APP\"" + "variables" + "color" + "catch_errors" + "function update_script() {" + ) + [[ "$LINE" != "${EXPECTED[$((i-16))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-16))]}" >> "$LOG_FILE" + done + cat "$LOG_FILE" + elif [[ $FILE =~ ^install/.*-install\.sh$ ]]; then + + FIRST_LINE=$(sed -n '1p' "$FILE") + [[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE" + + SECOND_LINE=$(sed -n '2p' "$FILE") + [[ -n "$SECOND_LINE" ]] && echo "Line 2 should be empty" >> "$LOG_FILE" + + THIRD_LINE=$(sed -n '3p' "$FILE") + if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then + echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2025 community-scripts ORG" >> "$LOG_FILE" + fi + + EXPECTED_AUTHOR="# Author:" + EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE" + EXPECTED_SOURCE="# Source:" + EXPECTED_EMPTY="" + + for i in {4..7}; do + LINE=$(sed -n "${i}p" "$FILE") + + case $i in + 4) + [[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE + ;; + 5) + [[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE + ;; + 6) + [[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE + ;; + 7) + [[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE + ;; + esac + done + + [[ "$(sed -n '8p' "$FILE")" != 'source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' ]] && echo 'Line 8 should be: source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' >> "$LOG_FILE" + + for i in {9..14}; do + LINE=$(sed -n "${i}p" "$FILE") + EXPECTED=( + "color" + "verb_ip6" + "catch_errors" + "setting_up_container" + "network_check" + "update_os" + ) + [[ "$LINE" != "${EXPECTED[$((i-9))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-9))]}" >> "$LOG_FILE" + done + + [[ -n "$(sed -n '15p' "$FILE")" ]] && echo "Line 15 should be empty" >> "$LOG_FILE" + [[ "$(sed -n '16p' "$FILE")" != 'msg_info "Installing Dependencies"' ]] && echo 'Line 16 should be: msg_info "Installing Dependencies"' >> "$LOG_FILE" + + LAST_3_LINES=$(tail -n 3 "$FILE") + [[ "$LAST_3_LINES" != *"$STD apt-get -y autoremove"* ]] && echo 'Third to last line should be: $STD apt-get -y autoremove' >> "$LOG_FILE" + [[ "$LAST_3_LINES" != *"$STD apt-get -y autoclean"* ]] && echo 'Second to last line should be: $STD apt-get -y clean' >> "$LOG_FILE" + [[ "$LAST_3_LINES" != *'msg_ok "Cleaned"'* ]] && echo 'Last line should be: msg_ok "Cleaned"' >> "$LOG_FILE" + cat "$LOG_FILE" + fi + + done + + + - name: Post error comments + run: | + ERROR="false" + for FILE in ${{ env.SCRIPT }}; do + FILE_STRIPPED="${FILE##*/}" + LOG_FILE="result_$FILE_STRIPPED.log" + echo $LOG_FILE + if [[ ! -f $LOG_FILE ]]; then + continue + fi + ERROR_MSG=$(cat $LOG_FILE) + + if [ -n "$ERROR_MSG" ]; then + echo "Posting error message for $FILE" + echo ${ERROR_MSG} + gh pr comment ${{ github.event.pull_request.number }} \ + --repo ${{ github.repository }} \ + --body ":warning: The script _**$FILE**_ has the following formatting errors:
${ERROR_MSG}
" + + + ERROR="true" + fi + done + echo "ERROR=$ERROR" >> $GITHUB_ENV + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Fail if error + if: ${{ env.ERROR == 'true' }} + run: exit 1 diff --git a/.github/workflows/scripts/app-test/pr-alpine-install.func b/.github/workflows/scripts/app-test/pr-alpine-install.func new file mode 100644 index 0000000..9c13a6b --- /dev/null +++ b/.github/workflows/scripts/app-test/pr-alpine-install.func @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Michel Roegl-Brunner (michelroegl-brunner) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE + +color() { + return +} +catch_errors() { + set -Eeuo pipefail + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR +} + +# This function handles errors +error_handler() { + local line_number="$1" + local command="$2" + SCRIPT_NAME=$(basename "$0") + local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command" + echo -e "\n$error_message" + exit 0 +} +verb_ip6() { + STD="" + return +} + +msg_info() { + local msg="$1" + echo -ne "${msg}\n" +} + +msg_ok() { + local msg="$1" + echo -e "${msg}\n" +} + +msg_error() { + + local msg="$1" + echo -e "${msg}\n" +} + +RETRY_NUM=10 +RETRY_EVERY=3 +i=$RETRY_NUM + +setting_up_container() { + while [ $i -gt 0 ]; do + if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then + break + fi + echo 1>&2 -en "No Network! " + sleep $RETRY_EVERY + i=$((i - 1)) + done + + if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then + echo 1>&2 -e "\n No Network After $RETRY_NUM Tries" + echo -e "Check Network Settings" + exit 1 + fi + msg_ok "Set up Container OS" + msg_ok "Network Connected: $(hostname -i)" +} + +network_check() { + RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }') + if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi + set -e +} + +update_os() { + msg_info "Updating Container OS" + apk update + apk upgrade + msg_ok "Updated Container OS" +} + +motd_ssh() { + return +} + +customize() { + return +} \ No newline at end of file diff --git a/.github/workflows/scripts/app-test/pr-build.func b/.github/workflows/scripts/app-test/pr-build.func new file mode 100644 index 0000000..67a9767 --- /dev/null +++ b/.github/workflows/scripts/app-test/pr-build.func @@ -0,0 +1,260 @@ +#!/usr/bin/env bash +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Michel Roegl-Brunner (michelroegl-brunner) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE + +variables() { + NSAPP=$(echo ${APP,,} | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces. + var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP. + +} + +NEXTID=$(pvesh get /cluster/nextid) +timezone=$(cat /etc/timezone) +header_info() { + return +} + +base_settings() { + # Default Settings + CT_TYPE="1" + DISK_SIZE="4" + CORE_COUNT="1" + RAM_SIZE="1024" + VERBOSE="no" + PW="" + CT_ID=$NEXTID + HN=$NSAPP + BRG="vmbr0" + NET="dhcp" + GATE="" + APT_CACHER="" + APT_CACHER_IP="" + DISABLEIP6="no" + MTU="" + SD="" + NS="" + MAC="" + VLAN="" + SSH="no" + SSH_AUTHORIZED_KEY="" + TAGS="community-script;" + + # Override default settings with variables from ct script + CT_TYPE=${var_unprivileged:-$CT_TYPE} + DISK_SIZE=${var_disk:-$DISK_SIZE} + CORE_COUNT=${var_cpu:-$CORE_COUNT} + RAM_SIZE=${var_ram:-$RAM_SIZE} + VERB=${var_verbose:-$VERBOSE} + TAGS="${TAGS}${var_tags:-}" + + # Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts + if [ -z "$var_os" ]; then + var_os="debian" + fi + if [ -z "$var_version" ]; then + var_version="12" + fi +} + +color() { + # Colors + YW=$(echo "\033[33m") + YWB=$(echo "\033[93m") + BL=$(echo "\033[36m") + RD=$(echo "\033[01;31m") + BGN=$(echo "\033[4;92m") + GN=$(echo "\033[1;92m") + DGN=$(echo "\033[32m") + + # Formatting + CL=$(echo "\033[m") + UL=$(echo "\033[4m") + BOLD=$(echo "\033[1m") + BFR="\\r\\033[K" + HOLD=" " + TAB=" " + + # Icons + CM="${TAB}✔️${TAB}${CL}" + CROSS="${TAB}✖️${TAB}${CL}" + INFO="${TAB}💡${TAB}${CL}" + OS="${TAB}🖥️${TAB}${CL}" + OSVERSION="${TAB}🌟${TAB}${CL}" + CONTAINERTYPE="${TAB}📦${TAB}${CL}" + DISKSIZE="${TAB}💾${TAB}${CL}" + CPUCORE="${TAB}🧠${TAB}${CL}" + RAMSIZE="${TAB}🛠️${TAB}${CL}" + SEARCH="${TAB}🔍${TAB}${CL}" + VERIFYPW="${TAB}🔐${TAB}${CL}" + CONTAINERID="${TAB}🆔${TAB}${CL}" + HOSTNAME="${TAB}🏠${TAB}${CL}" + BRIDGE="${TAB}🌉${TAB}${CL}" + NETWORK="${TAB}📡${TAB}${CL}" + GATEWAY="${TAB}🌐${TAB}${CL}" + DISABLEIPV6="${TAB}🚫${TAB}${CL}" + DEFAULT="${TAB}⚙️${TAB}${CL}" + MACADDRESS="${TAB}🔗${TAB}${CL}" + VLANTAG="${TAB}🏷️${TAB}${CL}" + ROOTSSH="${TAB}🔑${TAB}${CL}" + CREATING="${TAB}🚀${TAB}${CL}" + ADVANCED="${TAB}🧩${TAB}${CL}" +} + +catch_errors() { + set -Eeuo pipefail + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR +} + +# This function handles errors +error_handler() { + local line_number="$1" + local command="$2" + SCRIPT_NAME=$(basename "$0") + local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command" + echo -e "\n$error_message" + exit 100 +} + +msg_info() { + local msg="$1" + echo -ne "${msg}\n" +} + +msg_ok() { + local msg="$1" + echo -e "${msg}\n" +} + +msg_error() { + + local msg="$1" + echo -e "${msg}\n" +} +start() { + base_settings + return +} + +build_container() { + # if [ "$VERB" == "yes" ]; then set -x; fi + + if [ "$CT_TYPE" == "1" ]; then + FEATURES="keyctl=1,nesting=1" + else + FEATURES="nesting=1" + fi + TEMP_DIR=$(mktemp -d) + pushd $TEMP_DIR >/dev/null + if [ "$var_os" == "alpine" ]; then + export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/.github/workflows/scripts/app-test/pr-alpine-install.func)" + else + export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/.github/workflows/scripts/app-test/pr-install.func)" + fi + + export CACHER="$APT_CACHER" + export CACHER_IP="$APT_CACHER_IP" + export tz="" + export DISABLEIPV6="$DISABLEIP6" + export APPLICATION="$APP" + export app="$NSAPP" + export PASSWORD="$PW" + export VERBOSE="$VERB" + export SSH_ROOT="${SSH}" + export SSH_AUTHORIZED_KEY + export CTID="$CT_ID" + export CTTYPE="$CT_TYPE" + export PCT_OSTYPE="$var_os" + export PCT_OSVERSION="$var_version" + export PCT_DISK_SIZE="$DISK_SIZE" + export tz="$timezone" + export PCT_OPTIONS=" + -features $FEATURES + -hostname $HN + -tags $TAGS + $SD + $NS + -net0 name=eth0,bridge=$BRG$MAC,ip=$NET$GATE$VLAN$MTU + -onboot 1 + -cores $CORE_COUNT + -memory $RAM_SIZE + -unprivileged $CT_TYPE + $PW + " + echo "Container ID: $CTID" + + # This executes create_lxc.sh and creates the container and .conf file + bash -c "$(wget -qLO - https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/.github/workflows/scripts/app-test/pr-create-lxc.sh)" + + LXC_CONFIG=/etc/pve/lxc/${CTID}.conf + if [ "$CT_TYPE" == "0" ]; then + cat <>$LXC_CONFIG +# USB passthrough +lxc.cgroup2.devices.allow: a +lxc.cap.drop: +lxc.cgroup2.devices.allow: c 188:* rwm +lxc.cgroup2.devices.allow: c 189:* rwm +lxc.mount.entry: /dev/serial/by-id dev/serial/by-id none bind,optional,create=dir +lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file +lxc.mount.entry: /dev/ttyUSB1 dev/ttyUSB1 none bind,optional,create=file +lxc.mount.entry: /dev/ttyACM0 dev/ttyACM0 none bind,optional,create=file +lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create=file +EOF + fi + + if [ "$CT_TYPE" == "0" ]; then + if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then + cat <>$LXC_CONFIG +# VAAPI hardware transcoding +lxc.cgroup2.devices.allow: c 226:0 rwm +lxc.cgroup2.devices.allow: c 226:128 rwm +lxc.cgroup2.devices.allow: c 29:0 rwm +lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file +lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir +lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file +EOF + fi + else + if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then + if [[ -e "/dev/dri/renderD128" ]]; then + if [[ -e "/dev/dri/card0" ]]; then + cat <>$LXC_CONFIG +# VAAPI hardware transcoding +dev0: /dev/dri/card0,gid=44 +dev1: /dev/dri/renderD128,gid=104 +EOF + else + cat <>$LXC_CONFIG +# VAAPI hardware transcoding +dev0: /dev/dri/card1,gid=44 +dev1: /dev/dri/renderD128,gid=104 +EOF + fi + fi + fi + fi + + # This starts the container and executes -install.sh + msg_info "Starting LXC Container" + pct start "$CTID" + msg_ok "Started LXC Container" + + if [[ ! -f "/root/actions-runner/_work/ProxmoxVED/ProxmoxVED/install/$var_install.sh" ]]; then + msg_error "No install script found for $APP" + exit 1 + fi + if [ "$var_os" == "alpine" ]; then + sleep 3 + pct exec "$CTID" -- /bin/sh -c 'cat </etc/apk/repositories +http://dl-cdn.alpinelinux.org/alpine/latest-stable/main +http://dl-cdn.alpinelinux.org/alpine/latest-stable/community +EOF' + pct exec "$CTID" -- ash -c "apk add bash >/dev/null" + fi + lxc-attach -n "$CTID" -- bash -c "$(cat /root/actions-runner/_work/ProxmoxVED/ProxmoxVED/install/$var_install.sh)" + +} + +description() { + IP=$(pct exec "$CTID" ip a s dev eth0 | awk '/inet / {print $2}' | cut -d/ -f1) +} \ No newline at end of file diff --git a/.github/workflows/scripts/app-test/pr-create-lxc.sh b/.github/workflows/scripts/app-test/pr-create-lxc.sh new file mode 100644 index 0000000..69b45a2 --- /dev/null +++ b/.github/workflows/scripts/app-test/pr-create-lxc.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Michel Roegl-Brunner (michelroegl-brunner) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE + +color() { + return +} +catch_errors() { + set -Eeuo pipefail + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR +} + +# This function handles errors +error_handler() { + local exit_code="$?" + local line_number="$1" + local command="$2" + local error_message="Failure in line $line_number: exit code $exit_code: while executing command $command" + echo -e "\n$error_message" + exit 100 +} +verb_ip6() { + return +} + +msg_info() { + local msg="$1" + echo -ne "${msg}\n" +} + +msg_ok() { + local msg="$1" + echo -e "${msg}\n" +} + +msg_error() { + + local msg="$1" + echo -e "${msg}\n" +} + +VALIDCT=$(pvesm status -content rootdir | awk 'NR>1') +if [ -z "$VALIDCT" ]; then + msg_error "Unable to detect a valid Container Storage location." + exit 1 +fi +VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1') +if [ -z "$VALIDTMP" ]; then + msg_error "Unable to detect a valid Template Storage location." + exit 1 +fi + +function select_storage() { + local CLASS=$1 + local CONTENT + local CONTENT_LABEL + case $CLASS in + container) + CONTENT='rootdir' + CONTENT_LABEL='Container' + ;; + template) + CONTENT='vztmpl' + CONTENT_LABEL='Container template' + ;; + *) false || { + msg_error "Invalid storage class." + exit 201 + } ;; + esac + + # This Queries all storage locations + local -a MENU + while read -r line; do + local TAG=$(echo $line | awk '{print $1}') + local TYPE=$(echo $line | awk '{printf "%-10s", $2}') + local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}') + local ITEM="Type: $TYPE Free: $FREE " + local OFFSET=2 + if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then + local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET)) + fi + MENU+=("$TAG" "$ITEM" "OFF") + done < <(pvesm status -content $CONTENT | awk 'NR>1') + + # Select storage location + if [ $((${#MENU[@]} / 3)) -eq 1 ]; then + printf ${MENU[0]} + else + msg_error "STORAGE ISSUES!" + exit 202 + fi +} + +[[ "${CTID:-}" ]] || { + msg_error "You need to set 'CTID' variable." + exit 203 +} +[[ "${PCT_OSTYPE:-}" ]] || { + msg_error "You need to set 'PCT_OSTYPE' variable." + exit 204 +} + +# Test if ID is valid +[ "$CTID" -ge "100" ] || { + msg_error "ID cannot be less than 100." + exit 205 +} + +# Test if ID is in use +if pct status $CTID &>/dev/null; then + echo -e "ID '$CTID' is already in use." + unset CTID + msg_error "Cannot use ID that is already in use." + exit 206 +fi + +TEMPLATE_STORAGE=$(select_storage template) || exit + +CONTAINER_STORAGE=$(select_storage container) || exit + +pveam update >/dev/null + +TEMPLATE_SEARCH=${PCT_OSTYPE}-${PCT_OSVERSION:-} +mapfile -t TEMPLATES < <(pveam available -section system | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V) +[ ${#TEMPLATES[@]} -gt 0 ] || { + msg_error "Unable to find a template when searching for '$TEMPLATE_SEARCH'." + exit 207 +} +TEMPLATE="${TEMPLATES[-1]}" + +TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE" + +if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE"; then + [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH" + pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null || + { + msg_error "A problem occurred while downloading the LXC template." + exit 208 + } +fi + +grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid +grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid + +PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}}) +[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}") + +if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then + [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH" + + pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null || + { + msg_error "A problem occurred while re-downloading the LXC template." + exit 208 + } + + if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then + msg_error "A problem occurred while trying to create container after re-downloading template." + exit 200 + fi +fi diff --git a/.github/workflows/scripts/app-test/pr-install.func b/.github/workflows/scripts/app-test/pr-install.func new file mode 100644 index 0000000..2ff48df --- /dev/null +++ b/.github/workflows/scripts/app-test/pr-install.func @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Michel Roegl-Brunner (michelroegl-brunner) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE + +color() { + return +} + +catch_errors() { + set -Euo pipefail + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR +} + +error_handler() { + local line_number="$1" + local command="$2" + local error_message="Failure in line $line_number while executing command '$command'" + echo -e "\n$error_message\n" >&2 + exit 1 +} + +verb_ip6() { + STD="silent" + silent() { + "$@" >/dev/null 2>&1 || error_handler "${BASH_LINENO[0]}" "$*" + } + return +} + +msg_info() { + local msg="$1" + echo -ne "${msg}\n" +} + +msg_ok() { + local msg="$1" + echo -e "${msg}\n" +} + +msg_error() { + + local msg="$1" + echo -e "${msg}\n" +} + +RETRY_NUM=10 +RETRY_EVERY=3 +setting_up_container() { + + sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen + locale_line=$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print $1}' | head -n 1) + echo "LANG=${locale_line}" >/etc/default/locale + locale-gen >/dev/null + export LANG=${locale_line} + echo $tz >/etc/timezone + ln -sf /usr/share/zoneinfo/$tz /etc/localtime + + for ((i = RETRY_NUM; i > 0; i--)); do + if [ "$(hostname -I)" != "" ]; then + break + fi + sleep $RETRY_EVERY + done + if [ "$(hostname -I)" = "" ]; then + echo 1>&2 -e "\nNo Network After $RETRY_NUM Tries" + echo -e "Check Network Settings" + exit 101 + fi + rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED + systemctl disable -q --now systemd-networkd-wait-online.service +} + +network_check() { + RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }') + if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi + set -e +} + +update_os() { + export DEBIAN_FRONTEND=noninteractive + apt-get update >/dev/null 2>&1 + apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade >/dev/null + rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED +} + +motd_ssh() { + return +} + +customize() { + return +} \ No newline at end of file diff --git a/.github/workflows/scripts/generate-app-headers.sh b/.github/workflows/scripts/generate-app-headers.sh new file mode 100644 index 0000000..854a0f1 --- /dev/null +++ b/.github/workflows/scripts/generate-app-headers.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# Base directory for headers +headers_dir="./ct/headers" + +# Ensure the headers directory exists and clear it +mkdir -p "$headers_dir" +rm -f "$headers_dir"/* + +# Find all .sh files in ./ct directory, sorted alphabetically +find ./ct -type f -name "*.sh" | sort | while read -r script; do + # Extract the APP name from the APP line + app_name=$(grep -oP '^APP="\K[^"]+' "$script" 2>/dev/null) + + if [[ -n "$app_name" ]]; then + # Define the output file name in the headers directory + output_file="${headers_dir}/$(basename "${script%.*}")" + + # Generate figlet output + figlet_output=$(figlet -w 500 -f slant "$app_name") + + # Check if figlet output is not empty + if [[ -n "$figlet_output" ]]; then + echo "$figlet_output" > "$output_file" + echo "Generated: $output_file" + else + echo "Figlet failed for $app_name in $script" + fi + else + echo "No APP name found in $script, skipping." + fi +done + +echo "Completed processing .sh files." diff --git a/.github/workflows/scripts/update-json.sh b/.github/workflows/scripts/update-json.sh new file mode 100644 index 0000000..b51df64 --- /dev/null +++ b/.github/workflows/scripts/update-json.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +FILE=$1 +TODAY=$(date -u +"%Y-%m-%d") + +if [[ -z "$FILE" ]]; then + echo "No file specified. Exiting." + exit 1 +fi + +if [[ ! -f "$FILE" ]]; then + echo "File $FILE not found. Exiting." + exit 1 +fi + +DATE_IN_JSON=$(jq -r '.date_created' "$FILE" 2>/dev/null || echo "") + +if [[ "$DATE_IN_JSON" != "$TODAY" ]]; then + jq --arg date "$TODAY" '.date_created = $date' "$FILE" > tmp.json && mv tmp.json "$FILE" +fi diff --git a/.github/workflows/scripts/update_json_date.sh b/.github/workflows/scripts/update_json_date.sh new file mode 100644 index 0000000..d07eab7 --- /dev/null +++ b/.github/workflows/scripts/update_json_date.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Verzeichnis, das die JSON-Dateien enthält +json_dir="./json/*.json" + +current_date=$(date +"%Y-%m-%d") + +for json_file in $json_dir; do + if [[ -f "$json_file" ]]; then + current_json_date=$(jq -r '.date_created' "$json_file") + + if [[ "$current_json_date" != "$current_date" ]]; then + echo "Updating $json_file with date $current_date" + jq --arg date "$current_date" '.date_created = $date' "$json_file" > temp.json && mv temp.json "$json_file" + + git add "$json_file" + git commit -m "Update date_created to $current_date in $json_file" + else + echo "Date in $json_file is already up to date." + fi + fi +done +git push origin HEAD diff --git a/.github/workflows/update-json-date.yml b/.github/workflows/update-json-date.yml new file mode 100644 index 0000000..26957e5 --- /dev/null +++ b/.github/workflows/update-json-date.yml @@ -0,0 +1,131 @@ +name: Update JSON Date + +on: + push: + branches: + - main + paths: + - 'json/**.json' + workflow_dispatch: + +jobs: + update-app-files: + runs-on: runner-cluster-htl-set + + permissions: + contents: write + pull-requests: write + + steps: + - name: Generate a token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Generate dynamic branch name + id: timestamp + run: echo "BRANCH_NAME=pr-update-json-$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV + + - name: Set up GH_TOKEN + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV + + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Ensure we have the last two commits + + - name: Get Previous Commit + id: prev_commit + run: | + PREV_COMMIT=$(git rev-parse HEAD^) + echo "Previous commit: $PREV_COMMIT" + echo "prev_commit=$PREV_COMMIT" >> $GITHUB_ENV + + - name: Get Newly Added JSON Files + id: new_json_files + run: | + git diff --name-only --diff-filter=A ${{ env.prev_commit }} HEAD | grep '^json/.*\.json$' > new_files.txt || true + echo "New files detected:" + cat new_files.txt || echo "No new files." + + - name: Disable file mode changes + run: git config core.fileMode false + + - name: Set up Git + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Change JSON Date + id: change-json-date + run: | + current_date=$(date +"%Y-%m-%d") + while IFS= read -r file; do + # Skip empty lines + [[ -z "$file" ]] && continue + + if [[ -f "$file" ]]; then + echo "Processing $file..." + current_json_date=$(jq -r '.date_created // empty' "$file") + if [[ -z "$current_json_date" || "$current_json_date" != "$current_date" ]]; then + echo "Updating $file with date $current_date" + jq --arg date "$current_date" '.date_created = $date' "$file" > temp.json && mv temp.json "$file" + else + echo "Date in $file is already up to date." + fi + else + echo "Warning: File $file not found!" + fi + done < new_files.txt + rm new_files.txt + + - name: Check if there are any changes + run: | + echo "Checking for changes..." + git add -A # Untracked Dateien aufnehmen + git status + if git diff --cached --quiet; then + echo "No changes detected." + echo "changed=false" >> "$GITHUB_ENV" + else + echo "Changes detected:" + git diff --stat --cached + echo "changed=true" >> "$GITHUB_ENV" + fi + + # Step 7: Commit and create PR if changes exist + - name: Commit and create PR if changes exist + if: env.changed == 'true' + run: | + + + git commit -m "Update date in json" + git checkout -b ${{ env.BRANCH_NAME }} + git push origin ${{ env.BRANCH_NAME }} + + gh pr create --title "[core] update date in json" \ + --body "This PR is auto-generated by a GitHub Action to update the date in json." \ + --head ${{ env.BRANCH_NAME }} \ + --base main \ + --label "automated pr" + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + + - name: Approve pull request + if: env.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head "${{ env.BRANCH_NAME }}" --json number --jq '.[].number') + if [ -n "$PR_NUMBER" ]; then + gh pr review $PR_NUMBER --approve + fi + + - name: No changes detected + if: env.changed == 'false' + run: echo "No changes to commit. Workflow completed successfully." diff --git a/.github/workflows/validate-filenames.yml b/.github/workflows/validate-filenames.yml new file mode 100644 index 0000000..dac8062 --- /dev/null +++ b/.github/workflows/validate-filenames.yml @@ -0,0 +1,161 @@ +name: Validate filenames + +on: + pull_request_target: + paths: + - "ct/*.sh" + - "install/*.sh" + - "json/*.json" + +jobs: + check-files: + name: Check changed files + runs-on: runner-cluster-htl-set + permissions: + pull-requests: write + + steps: + - name: Get pull request information + if: github.event_name == 'pull_request_target' + uses: actions/github-script@v7 + id: pr + with: + script: | + const { data: pullRequest } = await github.rest.pulls.get({ + ...context.repo, + pull_number: context.payload.pull_request.number, + }); + return pullRequest; + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Ensure the full history is fetched for accurate diffing + ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }} + + - name: Get changed files + id: changed-files + run: | + if ${{ github.event_name == 'pull_request_target' }}; then + echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | xargs)" >> $GITHUB_OUTPUT + else + echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_OUTPUT + fi + + - name: "Validate filenames in ct and install directory" + if: always() && steps.changed-files.outputs.files != '' + id: check-scripts + run: | + CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^(ct|install)/.*\.sh$' || true; }) + + NON_COMPLIANT_FILES="" + for FILE in $CHANGED_FILES; do + # Datei "ct/create_lxc.sh" explizit überspringen + if [[ "$FILE" == "ct/create_lxc.sh" ]]; then + continue + fi + BASENAME=$(echo "$(basename "${FILE%.*}")") + if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "Non-compliant filenames found, change to lowercase:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: "Validate filenames in json directory." + if: always() && steps.changed-files.outputs.files != '' + id: check-json + run: | + CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^json/.*\.json$' || true; }) + + NON_COMPLIANT_FILES="" + for FILE in $CHANGED_FILES; do + BASENAME=$(echo "$(basename "${FILE%.*}")") + if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then + NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" + fi + done + + if [ -n "$NON_COMPLIANT_FILES" ]; then + echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT + echo "Non-compliant filenames found, change to lowercase:" + for FILE in $NON_COMPLIANT_FILES; do + echo "$FILE" + done + exit 1 + fi + + - name: Post results and comment + if: always() && steps.check-scripts.outputs.files != '' && steps.check-json.outputs.files != '' && github.event_name == 'pull_request_target' + uses: actions/github-script@v7 + with: + script: | + const result = "${{ job.status }}" === "success" ? "success" : "failure"; + const nonCompliantFiles = { + script: "${{ steps.check-scripts.outputs.files }}", + JSON: "${{ steps.check-json.outputs.files }}", + }; + + const issueNumber = context.payload.pull_request + ? context.payload.pull_request.number + : null; + const commentIdentifier = "validate-filenames"; + let newCommentBody = `\n### Filename validation\n\n`; + + if (result === "failure") { + newCommentBody += ":x: We found issues in the following changed files:\n\n"; + for (const [check, files] of Object.entries(nonCompliantFiles)) { + if (files) { + newCommentBody += `**${check.charAt(0).toUpperCase() + check.slice(1)} filename invalid:**\n${files + .trim() + .split(" ") + .map((file) => `- ${file}`) + .join("\n")}\n\n`; + } + } + newCommentBody += + "Please change the filenames to lowercase and use only alphanumeric characters and dashes.\n"; + } else { + newCommentBody += `:rocket: All files passed filename validation!\n`; + } + + newCommentBody += `\n\n`; + + if (issueNumber) { + const { data: comments } = await github.rest.issues.listComments({ + ...context.repo, + issue_number: issueNumber, + }); + + const existingComment = comments.find( + (comment) => comment.user.login === "github-actions[bot]", + ); + + if (existingComment) { + if (existingComment.body.includes(commentIdentifier)) { + const re = new RegExp(String.raw`[\s\S]*?`, ""); + newCommentBody = existingComment.body.replace(re, newCommentBody); + } else { + newCommentBody = existingComment.body + '\n\n---\n\n' + newCommentBody; + } + + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existingComment.id, + body: newCommentBody, + }); + } else { + await github.rest.issues.createComment({ + ...context.repo, + issue_number: issueNumber, + body: newCommentBody, + }); + } + } diff --git a/.vscode/.editorconfig b/.vscode/.editorconfig new file mode 100644 index 0000000..f79a823 --- /dev/null +++ b/.vscode/.editorconfig @@ -0,0 +1,16 @@ +; editorconfig.org +root = true + +[*] +charset = utf-8 +continuation_indent_size = 2 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +max_line_length = 120 +tab_width = 2 +; trim_trailing_whitespace = true ; disabled until files are cleaned up + +[*.md] +trim_trailing_whitespace = false diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..1949e6f --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "bmalehorn.shell-syntax", + "timonwong.shellcheck", + "foxundermoon.shell-format" + ], + "unwantedRecommendations": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..be834d9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.func": "shellscript" + } +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..63ae4f5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ + +

Changelog - Develop

+ +

All notable changes to this project will be documented in this file.

+ + +## 2025-03-03 + +### 🚀 Initial Release \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7d4a430..3dfc60d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Proxmox Helper Scripts (CE) +Copyright (c) 2021-2025 tteck | community-scripts ORG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e29ccc --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# 🚧 ProxmoxVED Helper-Scripts (Development Repository) + +**Warning: This repository is under active development and is not intended for production use. Changes may occur at any time!** + +--- + +## 🔧 What is this? +This repository contains a collection of scripts for managing and automating Proxmox Virtual Environment (Proxmox VE). Originally created by [tteck](https://github.com/tteck), the project is now community-driven and continues to evolve. + +--- + +## 🚀 Development Status +- **⚠️ Unstable**: Features may be incomplete or subject to change. +- **📢 Community-driven**: Contributions and feedback are welcome. +- **🔄 Frequent updates**: Active development means rapid iterations and fixes. + +--- + +## 💬 Get Involved +Join the discussion, contribute code, or report issues: +- **Discord**: [Join the Proxmox Helper Scripts Discord server](https://discord.gg/UHrpNWGwkH) +- **GitHub Issues**: [Report bugs or request features](https://github.com/community-scripts/ProxmoxVED/issues) + +--- + +## ❤️ Community and Contributions + +We appreciate any contributions to the project—whether it's bug reports, feature requests, documentation improvements, or spreading the word. Your involvement helps keep the project alive and sustainable. + +## 💖 Donate to Support the Project +- **Ko-Fi for Community Edition**: [Donate to support this project](https://ko-fi.com/community_scripts) – Donations go towards maintaining the project, testing infrastructure, and charity (cancer research, hospice care). 30% of the funds will be donated to charity. + + +## 📜 License + +This project is licensed under the [MIT License](LICENSE). + +
+
+

+ Proxmox® is a registered trademark of Proxmox Server Solutions GmbH. +

+ + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..c8530d5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +## Supported Versions +This project currently supports the following versions of Proxmox VE: + +| Version | Supported | +| ------- | ------------------ | +| 8.3.x | :white_check_mark: | +| 8.2.x | :white_check_mark: | +| 8.1.x | :white_check_mark: | +| 8.0.x | Limited support* ❕| +| < 8.0 | :x: | + +*Version 8.0.x has limited support. Security updates may not be provided for all issues in this version. + +## Reporting a Vulnerability + +Security vulnerabilities shouldn’t be reported publicly to prevent potential exploitation. Instead, please report any vulnerabilities privately by reaching out directly to us. You can either join our [Discord server](https://discord.gg/UHrpNWGwkH) and send a direct message to a maintainer or contact us via email at contact@community-scripts.org. Be sure to include a detailed description of the vulnerability and the steps to reproduce it. Thank you for helping us keep our project secure! + +Once a vulnerability has been reported, the project maintainers will review it and acknowledge the report within 7 business days. We will then work to address the vulnerability and provide a fix as soon as possible. Depending on the severity of the issue, a patch may be released immediately or included in the next scheduled update. + +Please note that not all reported vulnerabilities may be accepted. The project maintainers reserve the right to decline a vulnerability report if it is deemed to be a low-risk issue or if it conflicts with the project's design or architecture. In such cases, we will provide an explanation for the decision. + +If you have any questions or concerns about this security policy, please don't hesitate to contact the project maintainers. + diff --git a/api/.env.example b/api/.env.example new file mode 100644 index 0000000..fc7bdbb --- /dev/null +++ b/api/.env.example @@ -0,0 +1,5 @@ +MONGO_USER= +MONGO_PASSWORD= +MONGO_IP= +MONGO_PORT= +MONGO_DATABASE= \ No newline at end of file diff --git a/api/go.mod b/api/go.mod new file mode 100644 index 0000000..0297b1a --- /dev/null +++ b/api/go.mod @@ -0,0 +1,32 @@ +module proxmox-api + +go 1.23.2 + +require go.mongodb.org/mongo-driver v1.17.2 + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.2 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/text v0.21.0 // indirect + gorm.io/driver/mysql v1.5.7 // indirect + gorm.io/driver/postgres v1.5.11 // indirect + gorm.io/gorm v1.25.12 // indirect +) diff --git a/api/go.sum b/api/go.sum new file mode 100644 index 0000000..ea649ff --- /dev/null +++ b/api/go.sum @@ -0,0 +1,83 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM= +go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/api/main.go b/api/main.go new file mode 100644 index 0000000..55b2f24 --- /dev/null +++ b/api/main.go @@ -0,0 +1,450 @@ +// Copyright (c) 2021-2025 community-scripts ORG +// Author: Michel Roegl-Brunner (michelroegl-brunner) +// License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE + +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "net/http" + "os" + "strconv" + "time" + + "github.com/gorilla/mux" + "github.com/joho/godotenv" + "github.com/rs/cors" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +var client *mongo.Client +var collection *mongo.Collection + +func loadEnv() { + if err := godotenv.Load(); err != nil { + log.Fatal("Error loading .env file") + } +} + +// DataModel represents a single document in MongoDB +type DataModel struct { + ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` + CT_TYPE uint `json:"ct_type" bson:"ct_type"` + DISK_SIZE float32 `json:"disk_size" bson:"disk_size"` + CORE_COUNT uint `json:"core_count" bson:"core_count"` + RAM_SIZE uint `json:"ram_size" bson:"ram_size"` + OS_TYPE string `json:"os_type" bson:"os_type"` + OS_VERSION string `json:"os_version" bson:"os_version"` + DISABLEIP6 string `json:"disableip6" bson:"disableip6"` + NSAPP string `json:"nsapp" bson:"nsapp"` + METHOD string `json:"method" bson:"method"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + PVEVERSION string `json:"pve_version" bson:"pve_version"` + STATUS string `json:"status" bson:"status"` + RANDOM_ID string `json:"random_id" bson:"random_id"` + TYPE string `json:"type" bson:"type"` + ERROR string `json:"error" bson:"error"` +} + +type StatusModel struct { + RANDOM_ID string `json:"random_id" bson:"random_id"` + ERROR string `json:"error" bson:"error"` + STATUS string `json:"status" bson:"status"` +} + +type CountResponse struct { + TotalEntries int64 `json:"total_entries"` + StatusCount map[string]int64 `json:"status_count"` + NSAPPCount map[string]int64 `json:"nsapp_count"` +} + +// ConnectDatabase initializes the MongoDB connection +func ConnectDatabase() { + loadEnv() + + mongoURI := fmt.Sprintf("mongodb://%s:%s@%s:%s", + os.Getenv("MONGO_USER"), + os.Getenv("MONGO_PASSWORD"), + os.Getenv("MONGO_IP"), + os.Getenv("MONGO_PORT")) + + database := os.Getenv("MONGO_DATABASE") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + var err error + client, err = mongo.Connect(ctx, options.Client().ApplyURI(mongoURI)) + if err != nil { + log.Fatal("Failed to connect to MongoDB!", err) + } + collection = client.Database(database).Collection("data_models") + fmt.Println("Connected to MongoDB on 10.10.10.18") +} + +// UploadJSON handles API requests and stores data as a document in MongoDB +func UploadJSON(w http.ResponseWriter, r *http.Request) { + var input DataModel + + if err := json.NewDecoder(r.Body).Decode(&input); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + input.CreatedAt = time.Now() + + _, err := collection.InsertOne(context.Background(), input) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + log.Println("Received data:", input) + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(map[string]string{"message": "Data saved successfully"}) +} + +// UpdateStatus updates the status of a record based on RANDOM_ID +func UpdateStatus(w http.ResponseWriter, r *http.Request) { + var input StatusModel + + if err := json.NewDecoder(r.Body).Decode(&input); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + filter := bson.M{"random_id": input.RANDOM_ID} + update := bson.M{"$set": bson.M{"status": input.STATUS, "error": input.ERROR}} + + _, err := collection.UpdateOne(context.Background(), filter, update) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + log.Println("Updated data:", input) + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]string{"message": "Record updated successfully"}) +} + +// GetDataJSON fetches all data from MongoDB +func GetDataJSON(w http.ResponseWriter, r *http.Request) { + var records []DataModel + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + cursor, err := collection.Find(ctx, bson.M{}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer cursor.Close(ctx) + + for cursor.Next(ctx) { + var record DataModel + if err := cursor.Decode(&record); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + records = append(records, record) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(records) +} +func GetPaginatedData(w http.ResponseWriter, r *http.Request) { + page, _ := strconv.Atoi(r.URL.Query().Get("page")) + limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) + if page < 1 { + page = 1 + } + if limit < 1 { + limit = 10 + } + skip := (page - 1) * limit + var records []DataModel + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + options := options.Find().SetSkip(int64(skip)).SetLimit(int64(limit)) + cursor, err := collection.Find(ctx, bson.M{}, options) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer cursor.Close(ctx) + + for cursor.Next(ctx) { + var record DataModel + if err := cursor.Decode(&record); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + records = append(records, record) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(records) +} + +func GetSummary(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + totalCount, err := collection.CountDocuments(ctx, bson.M{}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + statusCount := make(map[string]int64) + nsappCount := make(map[string]int64) + + pipeline := []bson.M{ + {"$group": bson.M{"_id": "$status", "count": bson.M{"$sum": 1}}}, + } + cursor, err := collection.Aggregate(ctx, pipeline) + if err == nil { + for cursor.Next(ctx) { + var result struct { + ID string `bson:"_id"` + Count int64 `bson:"count"` + } + if err := cursor.Decode(&result); err == nil { + statusCount[result.ID] = result.Count + } + } + } + + pipeline = []bson.M{ + {"$group": bson.M{"_id": "$nsapp", "count": bson.M{"$sum": 1}}}, + } + cursor, err = collection.Aggregate(ctx, pipeline) + if err == nil { + for cursor.Next(ctx) { + var result struct { + ID string `bson:"_id"` + Count int64 `bson:"count"` + } + if err := cursor.Decode(&result); err == nil { + nsappCount[result.ID] = result.Count + } + } + } + + response := CountResponse{ + TotalEntries: totalCount, + StatusCount: statusCount, + NSAPPCount: nsappCount, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +func GetByNsapp(w http.ResponseWriter, r *http.Request) { + nsapp := r.URL.Query().Get("nsapp") + var records []DataModel + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + cursor, err := collection.Find(ctx, bson.M{"nsapp": nsapp}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer cursor.Close(ctx) + + for cursor.Next(ctx) { + var record DataModel + if err := cursor.Decode(&record); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + records = append(records, record) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(records) +} + +func GetByDateRange(w http.ResponseWriter, r *http.Request) { + + startDate := r.URL.Query().Get("start_date") + endDate := r.URL.Query().Get("end_date") + + if startDate == "" || endDate == "" { + http.Error(w, "Both start_date and end_date are required", http.StatusBadRequest) + return + } + + start, err := time.Parse("2006-01-02T15:04:05.999999+00:00", startDate+"T00:00:00+00:00") + if err != nil { + http.Error(w, "Invalid start_date format", http.StatusBadRequest) + return + } + + end, err := time.Parse("2006-01-02T15:04:05.999999+00:00", endDate+"T23:59:59+00:00") + if err != nil { + http.Error(w, "Invalid end_date format", http.StatusBadRequest) + return + } + + var records []DataModel + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + cursor, err := collection.Find(ctx, bson.M{ + "created_at": bson.M{ + "$gte": start, + "$lte": end, + }, + }) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer cursor.Close(ctx) + + for cursor.Next(ctx) { + var record DataModel + if err := cursor.Decode(&record); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + records = append(records, record) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(records) +} +func GetByStatus(w http.ResponseWriter, r *http.Request) { + status := r.URL.Query().Get("status") + var records []DataModel + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + cursor, err := collection.Find(ctx, bson.M{"status": status}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer cursor.Close(ctx) + + for cursor.Next(ctx) { + var record DataModel + if err := cursor.Decode(&record); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + records = append(records, record) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(records) +} + +func GetByOS(w http.ResponseWriter, r *http.Request) { + osType := r.URL.Query().Get("os_type") + osVersion := r.URL.Query().Get("os_version") + var records []DataModel + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + cursor, err := collection.Find(ctx, bson.M{"os_type": osType, "os_version": osVersion}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer cursor.Close(ctx) + + for cursor.Next(ctx) { + var record DataModel + if err := cursor.Decode(&record); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + records = append(records, record) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(records) +} + +func GetErrors(w http.ResponseWriter, r *http.Request) { + errorCount := make(map[string]int) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + cursor, err := collection.Find(ctx, bson.M{"error": bson.M{"$ne": ""}}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer cursor.Close(ctx) + + for cursor.Next(ctx) { + var record DataModel + if err := cursor.Decode(&record); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if record.ERROR != "" { + errorCount[record.ERROR]++ + } + } + + type ErrorCountResponse struct { + Error string `json:"error"` + Count int `json:"count"` + } + + var errorCounts []ErrorCountResponse + for err, count := range errorCount { + errorCounts = append(errorCounts, ErrorCountResponse{ + Error: err, + Count: count, + }) + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(struct { + ErrorCounts []ErrorCountResponse `json:"error_counts"` + }{ + ErrorCounts: errorCounts, + }) +} + +func main() { + ConnectDatabase() + + router := mux.NewRouter() + router.HandleFunc("/upload", UploadJSON).Methods("POST") + router.HandleFunc("/upload/updatestatus", UpdateStatus).Methods("POST") + router.HandleFunc("/data/json", GetDataJSON).Methods("GET") + router.HandleFunc("/data/paginated", GetPaginatedData).Methods("GET") + router.HandleFunc("/data/summary", GetSummary).Methods("GET") + router.HandleFunc("/data/nsapp", GetByNsapp).Methods("GET") + router.HandleFunc("/data/date", GetByDateRange).Methods("GET") + router.HandleFunc("/data/status", GetByStatus).Methods("GET") + router.HandleFunc("/data/os", GetByOS).Methods("GET") + router.HandleFunc("/data/errors", GetErrors).Methods("GET") + + c := cors.New(cors.Options{ + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{"GET", "POST"}, + AllowedHeaders: []string{"Content-Type", "Authorization"}, + AllowCredentials: true, + }) + + handler := c.Handler(router) + + fmt.Println("Server running on port 8080") + log.Fatal(http.ListenAndServe(":8080", handler)) +} diff --git a/ct/alpine.sh b/ct/alpine.sh new file mode 100644 index 0000000..dc93ecc --- /dev/null +++ b/ct/alpine.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://alpinelinux.org/ + +APP="Alpine" +var_tags="os;alpine" +var_cpu="1" +var_ram="512" +var_disk="0.1" +var_os="alpine" +var_version="3.21" +var_unprivileged="1" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + UPD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SUPPORT" --radiolist --cancel-button Exit-Script "Spacebar = Select" 11 58 1 \ + "1" "Check for Alpine Updates" ON \ + 3>&1 1>&2 2>&3) + + header_info + if [ "$UPD" == "1" ]; then + apk update && apk upgrade + exit + fi +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" diff --git a/ct/debian.sh b/ct/debian.sh new file mode 100644 index 0000000..d61d26b --- /dev/null +++ b/ct/debian.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://www.debian.org/ + +APP="Debian" +var_tags="os" +var_cpu="1" +var_ram="512" +var_disk="2" +var_os="debian" +var_version="12" +var_unprivileged="1" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /var ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + msg_info "Updating $APP LXC" + $STD apt-get update + $STD apt-get -y upgrade + msg_ok "Updated $APP LXC" + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" \ No newline at end of file diff --git a/ct/ubuntu.sh b/ct/ubuntu.sh new file mode 100644 index 0000000..dcbb94a --- /dev/null +++ b/ct/ubuntu.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://ubuntu.com/ + +echo -e "Loading..." +APP="Ubuntu" +var_tags="os" +var_cpu="1" +var_ram="512" +var_disk="2" +var_os="ubuntu" +var_version="24.04" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /var ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + msg_info "Updating ${APP} LXC" + $STD apt-get update + $STD apt-get -y upgrade + msg_ok "Updated ${APP} LXC" + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" \ No newline at end of file diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json new file mode 100644 index 0000000..32ef36a --- /dev/null +++ b/frontend/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": ["next/core-web-vitals"], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"] +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..4a2000d --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,39 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# wrangler +.worker-next +.wrangler + +# testing +/coverage + +# next.js +/.next/ +out +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# # local env files +# .env*.local +# .env +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 0000000..3aea320 --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,5 @@ +dist +node_modules +.next +build +.contentlayer \ No newline at end of file diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 0000000..490e839 --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,3 @@ +{ + "plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-organize-imports"] +} diff --git a/frontend/LICENSE b/frontend/LICENSE new file mode 100644 index 0000000..83fb1d4 --- /dev/null +++ b/frontend/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Bram Suurd + +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/frontend/components.json b/frontend/components.json new file mode 100644 index 0000000..380285b --- /dev/null +++ b/frontend/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "@/styles/globals.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} diff --git a/frontend/next.config.mjs b/frontend/next.config.mjs new file mode 100644 index 0000000..108da03 --- /dev/null +++ b/frontend/next.config.mjs @@ -0,0 +1,25 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + webpack: (config) => { + config.resolve.alias.canvas = false; + + return config; + }, + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "**", + }, + ], + }, + + env: { + BASE_PATH: "ProxmoxVE", + }, + + output: "export", + basePath: `/ProxmoxVE`, +}; + +export default nextConfig; diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..3ac30e9 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,10147 @@ +{ + "name": "proxmox-helper-scripts-website", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "proxmox-helper-scripts-website", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-icons": "^1.3.1", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-navigation-menu": "^1.1.4", + "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-select": "^2.1.2", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.1", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.2", + "@vercel/analytics": "^1.2.2", + "chart.js": "^4.4.1", + "chartjs-plugin-datalabels": "^2.2.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.0", + "date-fns": "^4.1.0", + "framer-motion": "^11.11.11", + "fuse.js": "^7.0.0", + "lucide-react": "^0.453.0", + "mini-svg-data-uri": "^1.4.4", + "next": "15.1.3", + "next-themes": "^0.3.0", + "nuqs": "^2.1.1", + "pocketbase": "^0.21.4", + "prettier-plugin-organize-imports": "^4.1.0", + "react": "19.0.0-rc-02c0e824-20241028", + "react-chartjs-2": "^5.3.0", + "react-code-blocks": "^0.1.6", + "react-datepicker": "^7.6.0", + "react-day-picker": "8.10.1", + "react-dom": "19.0.0-rc-02c0e824-20241028", + "react-icons": "^5.1.0", + "react-simple-typewriter": "^5.0.1", + "sharp": "^0.33.5", + "simple-icons": "^13.5.0", + "sonner": "^1.5.0", + "tailwind-merge": "^2.3.0", + "zod": "^3.23.8" + }, + "devDependencies": { + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.0.1", + "@types/node": "^22", + "@types/react": "npm:types-react@19.0.0-rc.1", + "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", + "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/parser": "^8.8.1", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.13.0", + "eslint-config-next": "15.0.2", + "jsdom": "^25.0.1", + "postcss": "^8", + "prettier": "^3.2.5", + "prettier-plugin-tailwindcss": "^0.6.5", + "tailwindcss": "^3.4.9", + "tailwindcss-animate": "^1.0.7", + "tailwindcss-animated": "^1.1.2", + "typescript": "^5", + "vite-tsconfig-paths": "^5.1.3", + "vitest": "^2.1.9" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", + "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, + "node_modules/@next/env": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.3.tgz", + "integrity": "sha512-Q1tXwQCGWyA3ehMph3VO+E6xFPHDKdHFYosadt0F78EObYxPio0S09H9UGYznDe6Wc8eLKLG89GqcFJJDiK5xw==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.0.2.tgz", + "integrity": "sha512-R9Jc7T6Ge0txjmqpPwqD8vx6onQjynO9JT73ArCYiYPvSrwYXepH/UY/WdKDY8JPWJl72sAE4iGMHPeQ5xdEWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.3.tgz", + "integrity": "sha512-aZtmIh8jU89DZahXQt1La0f2EMPt/i7W+rG1sLtYJERsP7GRnNFghsciFpQcKHcGh4dUiyTB5C1X3Dde/Gw8gg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.3.tgz", + "integrity": "sha512-aw8901rjkVBK5mbq5oV32IqkJg+CQa6aULNlN8zyCWSsePzEG3kpDkAFkkTOh3eJ0p95KbkLyWBzslQKamXsLA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.3.tgz", + "integrity": "sha512-YbdaYjyHa4fPK4GR4k2XgXV0p8vbU1SZh7vv6El4bl9N+ZSiMfbmqCuCuNU1Z4ebJMumafaz6UCC2zaJCsdzjw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.3.tgz", + "integrity": "sha512-qgH/aRj2xcr4BouwKG3XdqNu33SDadqbkqB6KaZZkozar857upxKakbRllpqZgWl/NDeSCBYPmUAZPBHZpbA0w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.3.tgz", + "integrity": "sha512-uzafnTFwZCPN499fNVnS2xFME8WLC9y7PLRs/yqz5lz1X/ySoxfaK2Hbz74zYUdEg+iDZPd8KlsWaw9HKkLEVw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.3.tgz", + "integrity": "sha512-el6GUFi4SiDYnMTTlJJFMU+GHvw0UIFnffP1qhurrN1qJV3BqaSRUjkDUgVV44T6zpw1Lc6u+yn0puDKHs+Sbw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.3.tgz", + "integrity": "sha512-6RxKjvnvVMM89giYGI1qye9ODsBQpHSHVo8vqA8xGhmRPZHDQUE4jcDbhBwK0GnFMqBnu+XMg3nYukNkmLOLWw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.3.tgz", + "integrity": "sha512-VId/f5blObG7IodwC5Grf+aYP0O8Saz1/aeU3YcWqNdIUAmFQY3VEPKPaIzfv32F/clvanOb2K2BR5DtDs6XyQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.1.tgz", + "integrity": "sha512-bg/l7l5QzUjgsh8kjwDFommzAshnUsuVMV5NM56QVCm+7ZckYdd9P/ExR8xG/Oup0OajVxNLaHJ1tb8mXk+nzQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collapsible": "1.1.1", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.1.tgz", + "integrity": "sha512-1///SnrfQHJEofLokyczERxQbWfCGQlQ2XsCZMucVs6it+lq9iw4vXy+uDn1edlb58cOZOWSldnfPAYcT4O/Yg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz", + "integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz", + "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz", + "integrity": "sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-menu": "2.1.2", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-icons": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.1.tgz", + "integrity": "sha512-QvYompk0X+8Yjlo/Fv4McrzxohDdM5GgLHyQcPpcsPvlOSXCGFjdbuyGL5dzRbg0GpknAjQJJZzdiRK7iWVuFQ==", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x || ^19.x" + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.2.tgz", + "integrity": "sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.1.tgz", + "integrity": "sha512-egDo0yJD2IK8L17gC82vptkvW1jLeni1VuqCyzY727dSJdk5cDjINomouLoNk8RVF7g2aNIfENKWL4UzeU9c8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.2.tgz", + "integrity": "sha512-u2HRUyWW+lOiA2g0Le0tMmT55FGOEWHwPFt1EPfbLly7uXQExFo5duNKqG2DzmFXIdqOeNd+TpE8baHWJCyP9w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz", + "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", + "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", + "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.2.tgz", + "integrity": "sha512-rZJtWmorC7dFRi0owDmoijm6nSJH1tVw64QGiNIZ9PNLyBDtG+iAq+XGsya052At4BfarzY/Dhv9wrrUr6IMZA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.0.tgz", + "integrity": "sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.1.tgz", + "integrity": "sha512-diPqDDoBcZPSicYoMWdWx+bCPuTRH4QSp9J+65IvtdS0Kuzt67bI6n32vCj8q6NZmYW/ah+2orOtMwcX5eQwIg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.1.tgz", + "integrity": "sha512-3GBUDmP2DvzmtYLMsHmpA1GtR46ZDZ+OreXM/N+kkQJOPIgytFWWTfDQmBQKBvaFS0Vno0FktdbVzN28KGrMdw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.3.tgz", + "integrity": "sha512-Z4w1FIS0BqVFI2c1jZvb/uDVJijJjJ2ZMuPV81oVgTZ7g3BZxobplnMVvXtFWgtozdvYJ+MFWtwkM5S2HnAong==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", + "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz", + "integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/react": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.8.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.6.tgz", + "integrity": "sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@types/react": { + "name": "types-react", + "version": "19.0.0-rc.1", + "resolved": "https://registry.npmjs.org/types-react/-/types-react-19.0.0-rc.1.tgz", + "integrity": "sha512-RshndUfqTW6K3STLPis8BtAYCGOkMbtvYsi90gmVNDZBXUyUc5juf2PE9LfS/JmOlUIRO8cWTS/1MTnmhjDqyQ==", + "devOptional": true, + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "name": "types-react-dom", + "version": "19.0.0-rc.1", + "resolved": "https://registry.npmjs.org/types-react-dom/-/types-react-dom-19.0.0-rc.1.tgz", + "integrity": "sha512-VSLZJl8VXCD0fAWp7DUTFUDCcZ8DVXOQmjhJMD03odgeFmu14ZQJHCXeETm3BEAhJqfgJaFkLnGkQv88sRx0fQ==", + "devOptional": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", + "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/type-utils": "8.12.2", + "@typescript-eslint/utils": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", + "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", + "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", + "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/utils": "8.12.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", + "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", + "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", + "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", + "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.12.2", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vercel/analytics": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.3.2.tgz", + "integrity": "sha512-n/Ws7skBbW+fUBMeg+jrT30+GP00jTHvCcL4fuVrShuML0uveEV/4vVUdvqEVnDgXIGfLm0GXW5EID2mCcRXhg==", + "license": "MPL-2.0", + "dependencies": { + "server-only": "^0.0.1" + }, + "peerDependencies": { + "next": ">= 13", + "react": "^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", + "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001676", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz", + "integrity": "sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chart.js": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.7.tgz", + "integrity": "sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "2.0.0" + }, + "funding": { + "url": "https://joebell.co.uk" + } + }, + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.3.tgz", + "integrity": "sha512-2c3uTjwT4YeHj60q2k8S1B0WHSoGR6t5CPnec6PMFD2QF4gwid0t1VSPNeEmL02EwBwNky/A3gwPCOViKTtoPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.0", + "use-sync-external-store": "^1.2.2" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rrweb-cssom": "^0.7.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.65", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.65.tgz", + "integrity": "sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.4", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.3", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", + "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.13.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.0.2.tgz", + "integrity": "sha512-N8o6cyUXzlMmQbdc2Kc83g1qomFi3ITqrAZfubipVKET2uR2mCStyGRcx/r8WiAIVMul2KfwRiCHBkTpBvGBmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "15.0.2", + "@rushstack/eslint-patch": "^1.10.3", + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.35.0", + "eslint-plugin-react-hooks": "^5.0.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", + "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.1.0", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", + "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", + "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/framer-motion": { + "version": "11.11.11", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.11.11.tgz", + "integrity": "sha512-tuDH23ptJAKUHGydJQII9PhABNJBpB+z0P1bmgKK9QFIssHGlfPd6kxMq00LSKwE27WFsb2z0ovY0bpUyMvfRw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-vue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", + "license": "CC0-1.0" + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "dev": true, + "license": "MIT" + }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "license": "MIT", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/lucide-react": { + "version": "0.453.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.453.0.tgz", + "integrity": "sha512-kL+RGZCcJi9BvJtzg2kshO192Ddy9hv3ij+cPrVPWSRzgCWCVazoQJxOjAwgK53NomL07HB7GPHW120FimjNhQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "license": "MIT", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/next/-/next-15.1.3.tgz", + "integrity": "sha512-5igmb8N8AEhWDYzogcJvtcRDU6n4cMGtBklxKD4biYv4LXN8+awc/bbQ2IM2NQHdVPgJ6XumYXfo3hBtErg1DA==", + "dependencies": { + "@next/env": "15.1.3", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.15", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.1.3", + "@next/swc-darwin-x64": "15.1.3", + "@next/swc-linux-arm64-gnu": "15.1.3", + "@next/swc-linux-arm64-musl": "15.1.3", + "@next/swc-linux-x64-gnu": "15.1.3", + "@next/swc-linux-x64-musl": "15.1.3", + "@next/swc-win32-arm64-msvc": "15.1.3", + "@next/swc-win32-x64-msvc": "15.1.3", + "sharp": "^0.33.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nuqs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nuqs/-/nuqs-2.1.1.tgz", + "integrity": "sha512-iM2H8lMmhvk9bxupUs2oRle9usRNEAqppOkTMXOxD/uK85gOKAubU7T2zmPo8fnYQS4n5e/XswTiq+gLYGpy3w==", + "license": "MIT", + "dependencies": { + "mitt": "^3.0.1" + }, + "peerDependencies": { + "@remix-run/react": ">= 2", + "next": ">= 14.2.0", + "react": ">= 18.2.0", + "react-router-dom": ">= 6" + }, + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "next": { + "optional": true + }, + "react-router-dom": { + "optional": true + } + } + }, + "node_modules/nwsapi": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz", + "integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pocketbase": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.21.5.tgz", + "integrity": "sha512-bnI/uinnQps+ElSlzxkc4yvwuSFfKcoszDtXH/4QT2FhGq2mJVUvDlxn+rjRXVntUjPfmMG5LEPZ1eGqV6ssog==", + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-organize-imports": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", + "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "license": "MIT", + "peerDependencies": { + "prettier": ">=2.0", + "typescript": ">=2.9", + "vue-tsc": "^2.1.0" + }, + "peerDependenciesMeta": { + "vue-tsc": { + "optional": true + } + } + }, + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.8.tgz", + "integrity": "sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "@zackad/prettier-plugin-twig-melody": "*", + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-multiline-arrays": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "@zackad/prettier-plugin-twig-melody": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-multiline-arrays": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + } + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.0.0-rc-02c0e824-20241028", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-rc-02c0e824-20241028.tgz", + "integrity": "sha512-GbZ7hpPHQMiEu53BqEaPQVM/4GG4hARo+mqEEnx4rYporDvNvUjutiAFxYFSbu6sgHwcr7LeFv8htEOwALVA2A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-chartjs-2": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz", + "integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==", + "license": "MIT", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-code-blocks": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/react-code-blocks/-/react-code-blocks-0.1.6.tgz", + "integrity": "sha512-ENNuxG07yO+OuX1ChRje3ieefPRz6yrIpHmebQlaFQgzcAHbUfVeTINpOpoI9bSRSObeYo/OdHsporeToZ7fcg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.4", + "react-syntax-highlighter": "^15.5.0", + "styled-components": "^6.1.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/react-datepicker": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.6.0.tgz", + "integrity": "sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.27.0", + "clsx": "^2.1.1", + "date-fns": "^3.6.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/react-datepicker/node_modules/@floating-ui/react": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.3.tgz", + "integrity": "sha512-CLHnes3ixIFFKVQDdICjel8muhFLOBdQH7fgtHNPY8UbCNqbeKZ262G7K66lGQOUQWWnYocf7ZbUsLJgGfsLHg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.9", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/react-datepicker/node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/react-day-picker": { + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz", + "integrity": "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "date-fns": "^2.28.0 || ^3.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-dom": { + "version": "19.0.0-rc-02c0e824-20241028", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc-02c0e824-20241028.tgz", + "integrity": "sha512-LrZf3DfHL6Fs07wwlUCHrzFTCMM19yA99MvJpfLokN4I2nBAZvREGZjZAn8VPiSfN72+i9j1eL4wB8gC695F3Q==", + "license": "MIT", + "dependencies": { + "scheduler": "0.25.0-rc-02c0e824-20241028" + }, + "peerDependencies": { + "react": "19.0.0-rc-02c0e824-20241028" + } + }, + "node_modules/react-icons": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", + "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz", + "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.6", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", + "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-simple-typewriter": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-simple-typewriter/-/react-simple-typewriter-5.0.1.tgz", + "integrity": "sha512-vA5HkABwJKL/DJ4RshSlY/igdr+FiVY4MLsSQYJX6FZG/f1/VwN4y1i3mPXRyfaswrvI8xii1kOVe1dYtO2Row==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-syntax-highlighter": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz", + "integrity": "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "highlightjs-vue": "^1.0.0", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "license": "MIT", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.25.0-rc-02c0e824-20241028", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-02c0e824-20241028.tgz", + "integrity": "sha512-GysnKjmMSaWcwsKTLzeJO0IhU3EyIiC0ivJKE6yDNLqt3IMxDByx8b6lSNXRNdN+ULUY0WLLjSPaZ0LuU/GnTg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-icons": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-13.15.0.tgz", + "integrity": "sha512-8SzFj9CvPlDnjDLISsAWTvpCs7om2zbSJZ1hNLRo6quWKLqFwjCD9opS24Q/yD0bdsnVHPpF0N3hitpHrY5u9w==", + "license": "CC0-1.0", + "engines": { + "node": ">=0.12.18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/simple-icons" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sonner": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.5.0.tgz", + "integrity": "sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-components": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", + "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.38", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/styled-components/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "license": "MIT" + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, + "node_modules/tailwind-merge": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", + "integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tailwindcss-animated": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tailwindcss-animated/-/tailwindcss-animated-1.1.2.tgz", + "integrity": "sha512-SI4owS5ojserhgEYIZA/uFVdNjU2GMB2P3sjtjmFA52VxoUi+Hht6oR5+RdT+CxrX9cNNYEa+vbTWHvN9zbj3w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.1.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", + "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.64", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.64.tgz", + "integrity": "sha512-ph4AE5BXWIOsSy9stpoeo7bYe/Cy7VfpciIH4RhVZUPItCJmhqWCN0EVzxd8BOHiyNb42vuJc6NWTjJkg91Tuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.64" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.64", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.64.tgz", + "integrity": "sha512-uqnl8vGV16KsyflHOzqrYjjArjfXaU6rMPXYy2/ZWoRKCkXtghgB4VwTDXUG+t0OTGeSewNAG31/x1gCTfLt+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tsconfck": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.4.tgz", + "integrity": "sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", + "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.3.tgz", + "integrity": "sha512-0bz+PDlLpGfP2CigeSKL9NFTF1KtXkeHGZSSaGQSuPZH77GhoiQaA8IjYgOaynSuwlDTolSUEU0ErVvju3NURg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "dev": true, + "license": "MIT", + "dependencies": { + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "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.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..3457b6a --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,92 @@ +{ + "name": "proxmox-helper-scripts-website", + "version": "1.0.0", + "license": "MIT", + "private": true, + "author": { + "name": "Bram Suurd", + "url": "https://github.com/community-scripts" + }, + "type": "module", + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "next lint", + "test": "vitest", + "deploy": "next build && touch out/.nojekyll && git add out/ && git commit -m \"Deploy\" && git subtree push --prefix out origin gh-pages", + "format:write": "prettier --write \"**/*.{ts,tsx,mdx}\" --cache", + "format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-icons": "^1.3.1", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-navigation-menu": "^1.1.4", + "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-select": "^2.1.2", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.1", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.2", + "@vercel/analytics": "^1.2.2", + "chart.js": "^4.4.1", + "chartjs-plugin-datalabels": "^2.2.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.0", + "date-fns": "^4.1.0", + "framer-motion": "^11.11.11", + "fuse.js": "^7.0.0", + "lucide-react": "^0.453.0", + "mini-svg-data-uri": "^1.4.4", + "next": "15.1.3", + "next-themes": "^0.3.0", + "nuqs": "^2.1.1", + "pocketbase": "^0.21.4", + "prettier-plugin-organize-imports": "^4.1.0", + "react": "19.0.0-rc-02c0e824-20241028", + "react-chartjs-2": "^5.3.0", + "react-code-blocks": "^0.1.6", + "react-datepicker": "^7.6.0", + "react-day-picker": "8.10.1", + "react-dom": "19.0.0-rc-02c0e824-20241028", + "react-icons": "^5.1.0", + "react-simple-typewriter": "^5.0.1", + "sharp": "^0.33.5", + "simple-icons": "^13.5.0", + "sonner": "^1.5.0", + "tailwind-merge": "^2.3.0", + "zod": "^3.23.8" + }, + "devDependencies": { + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.0.1", + "@types/node": "^22", + "@types/react": "npm:types-react@19.0.0-rc.1", + "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", + "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/parser": "^8.8.1", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.13.0", + "eslint-config-next": "15.0.2", + "jsdom": "^25.0.1", + "postcss": "^8", + "prettier": "^3.2.5", + "prettier-plugin-tailwindcss": "^0.6.5", + "tailwindcss": "^3.4.9", + "tailwindcss-animate": "^1.0.7", + "tailwindcss-animated": "^1.1.2", + "typescript": "^5", + "vite-tsconfig-paths": "^5.1.3", + "vitest": "^2.1.9" + }, + "overrides": { + "@types/react": "npm:types-react@19.0.0-rc.1", + "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1" + } +} diff --git a/frontend/postcss.config.mjs b/frontend/postcss.config.mjs new file mode 100644 index 0000000..1a69fd2 --- /dev/null +++ b/frontend/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + tailwindcss: {}, + }, +}; + +export default config; diff --git a/frontend/public/defaultimg.png b/frontend/public/defaultimg.png new file mode 100644 index 0000000000000000000000000000000000000000..4aac77d5c835d4f5b0242329b9f8bb0e142faf07 GIT binary patch literal 77312 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�%8kbxKQLgho=Qq=*ZMXfrpL+N6 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 { + it("should show button to view scripts", () => { + render(); + expect(screen.getByRole("button", { name: "View Scripts" })).toBeDefined(); + }); +}); diff --git a/frontend/src/__tests__/public/validate-json.test.ts b/frontend/src/__tests__/public/validate-json.test.ts new file mode 100644 index 0000000..562ebe9 --- /dev/null +++ b/frontend/src/__tests__/public/validate-json.test.ts @@ -0,0 +1,53 @@ +import { describe, it, assert, beforeAll } from "vitest"; +import { promises as fs } from "fs"; +import path from "path"; +import { ScriptSchema, type Script } from "@/app/json-editor/_schemas/schemas"; +import { Metadata } from "@/lib/types"; + +const jsonDir = "public/json"; +const metadataFileName = "metadata.json"; +const encoding = "utf-8"; + +const fileNames = (await fs.readdir(jsonDir)) + .filter((fileName) => fileName !== metadataFileName) + +describe.each(fileNames)("%s", async (fileName) => { + let script: Script; + + beforeAll(async () => { + const filePath = path.resolve(jsonDir, fileName); + const fileContent = await fs.readFile(filePath, encoding) + script = JSON.parse(fileContent); + }) + + it("should have valid json according to script schema", () => { + ScriptSchema.parse(script); + }); + + it("should have a corresponding script file", () => { + script.install_methods.forEach((method) => { + const scriptPath = path.resolve("..", method.script) + assert(fs.stat(scriptPath), `Script file not found: ${scriptPath}`) + }) + }); +}) + +describe(`${metadataFileName}`, async () => { + let metadata: Metadata; + + beforeAll(async () => { + const filePath = path.resolve(jsonDir, metadataFileName); + const fileContent = await fs.readFile(filePath, encoding) + metadata = JSON.parse(fileContent); + }) + + it("should have valid json according to metadata schema", () => { + // TODO: create zod schema for metadata. Move zod schemas to /lib/types.ts + assert(metadata.categories.length > 0); + metadata.categories.forEach((category) => { + assert.isString(category.name) + assert.isNumber(category.id) + assert.isNumber(category.sort_order) + }); + }); +}) diff --git a/frontend/src/__tests__/setupTests.ts b/frontend/src/__tests__/setupTests.ts new file mode 100644 index 0000000..063af62 --- /dev/null +++ b/frontend/src/__tests__/setupTests.ts @@ -0,0 +1,4 @@ +import { vi } from "vitest"; + +// Mock canvas getContext +HTMLCanvasElement.prototype.getContext = vi.fn(); \ No newline at end of file diff --git a/frontend/src/app/api/categories/route.ts b/frontend/src/app/api/categories/route.ts new file mode 100644 index 0000000..2d33a3a --- /dev/null +++ b/frontend/src/app/api/categories/route.ts @@ -0,0 +1,56 @@ +import { Metadata, Script } from "@/lib/types"; +import { promises as fs } from "fs"; +import { NextResponse } from "next/server"; +import path from "path"; + +export const dynamic = "force-static"; + +const jsonDir = "public/json"; +const metadataFileName = "metadata.json"; +const encoding = "utf-8"; + +const getMetadata = async () => { + const filePath = path.resolve(jsonDir, metadataFileName); + const fileContent = await fs.readFile(filePath, encoding); + const metadata: Metadata = JSON.parse(fileContent); + return metadata; +}; + +const getScripts = async () => { + const filePaths = (await fs.readdir(jsonDir)) + .filter((fileName) => fileName !== metadataFileName) + .map((fileName) => path.resolve(jsonDir, fileName)); + + const scripts = await Promise.all( + filePaths.map(async (filePath) => { + const fileContent = await fs.readFile(filePath, encoding); + const script: Script = JSON.parse(fileContent); + return script; + }), + ); + return scripts; +}; + +export async function GET() { + try { + const metadata = await getMetadata(); + const scripts = await getScripts(); + + const categories = metadata.categories + .map((category) => { + category.scripts = scripts.filter((script) => + script.categories.includes(category.id), + ); + return category; + }) + .sort((a, b) => a.sort_order - b.sort_order); + + return NextResponse.json(categories); + } catch (error) { + console.error(error as Error); + return NextResponse.json( + { error: "Failed to fetch categories" }, + { status: 500 }, + ); + } +} diff --git a/frontend/src/app/category-view/page.tsx b/frontend/src/app/category-view/page.tsx new file mode 100644 index 0000000..1d5a9e9 --- /dev/null +++ b/frontend/src/app/category-view/page.tsx @@ -0,0 +1,276 @@ +"use client"; + +import React, { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import { Card, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { ChevronLeft, ChevronRight } from "lucide-react"; +import { Category } from "@/lib/types"; + +const defaultLogo = "/default-logo.png"; // Fallback logo path +const MAX_DESCRIPTION_LENGTH = 100; // Set max length for description +const MAX_LOGOS = 5; // Max logos to display at once + +const formattedBadge = (type: string) => { + switch (type) { + case "vm": + return VM; + case "ct": + return ( + LXC + ); + case "misc": + return MISC; + } + return null; +}; + +const CategoryView = () => { + const [categories, setCategories] = useState([]); + const [selectedCategoryIndex, setSelectedCategoryIndex] = useState(null); + const [currentScripts, setCurrentScripts] = useState([]); + const [logoIndices, setLogoIndices] = useState<{ [key: string]: number }>({}); + const router = useRouter(); + + useEffect(() => { + const fetchCategories = async () => { + try { + const basePath = process.env.NODE_ENV === "production" ? "/ProxmoxVE" : ""; + const response = await fetch(`${basePath}/api/categories`); + if (!response.ok) { + throw new Error("Failed to fetch categories"); + } + const data = await response.json(); + setCategories(data); + + // Initialize logo indices + const initialLogoIndices: { [key: string]: number } = {}; + data.forEach((category: any) => { + initialLogoIndices[category.name] = 0; + }); + setLogoIndices(initialLogoIndices); + } catch (error) { + console.error("Error fetching categories:", error); + } + }; + + fetchCategories(); + }, []); + + const handleCategoryClick = (index: number) => { + setSelectedCategoryIndex(index); + setCurrentScripts(categories[index]?.scripts || []); // Update scripts for the selected category + }; + + const handleBackClick = () => { + setSelectedCategoryIndex(null); + setCurrentScripts([]); // Clear scripts when going back + }; + + const handleScriptClick = (scriptSlug: string) => { + router.push(`/scripts?id=${scriptSlug}`); + }; + + const navigateCategory = (direction: "prev" | "next") => { + if (selectedCategoryIndex !== null) { + const newIndex = + direction === "prev" + ? (selectedCategoryIndex - 1 + categories.length) % categories.length + : (selectedCategoryIndex + 1) % categories.length; + setSelectedCategoryIndex(newIndex); + setCurrentScripts(categories[newIndex]?.scripts || []); // Update scripts for the new category + } + }; + + const switchLogos = (categoryName: string, direction: "prev" | "next") => { + setLogoIndices((prev) => { + const currentIndex = prev[categoryName] || 0; + const category = categories.find((cat) => cat.name === categoryName); + if (!category || !category.scripts) return prev; + + const totalLogos = category.scripts.length; + const newIndex = + direction === "prev" + ? (currentIndex - MAX_LOGOS + totalLogos) % totalLogos + : (currentIndex + MAX_LOGOS) % totalLogos; + + return { ...prev, [categoryName]: newIndex }; + }); + }; + + const truncateDescription = (text: string) => { + return text.length > MAX_DESCRIPTION_LENGTH + ? `${text.slice(0, MAX_DESCRIPTION_LENGTH)}...` + : text; + }; + + const renderResources = (script: any) => { + const cpu = script.install_methods[0]?.resources.cpu; + const ram = script.install_methods[0]?.resources.ram; + const hdd = script.install_methods[0]?.resources.hdd; + + const resourceParts = []; + if (cpu) resourceParts.push(CPU: {cpu}vCPU); + if (ram) resourceParts.push(RAM: {ram}MB); + if (hdd) resourceParts.push(HDD: {hdd}GB); + + return resourceParts.length > 0 ? ( +
+ {resourceParts.map((part, index) => ( + + {part} + {index < resourceParts.length - 1 && " | "} + + ))} +
+ ) : null; + }; + + return ( +
+ {categories.length === 0 && ( +

No categories available. Please check the API endpoint.

+ )} + {selectedCategoryIndex !== null ? ( +
+ {/* Header with Navigation */} +
+ +

+ {categories[selectedCategoryIndex].name} +

+ +
+ + {/* Scripts Grid */} +
+ {currentScripts + .sort((a, b) => a.name.localeCompare(b.name)) + .map((script) => ( + handleScriptClick(script.slug)} + > + +

+ {script.name} +

+ {script.name +

+ Created at: {script.date_created || "No date available"} +

+

+ {truncateDescription(script.description || "No description available.")} +

+ {renderResources(script)} +
+
+ ))} +
+ + {/* Back to Categories Button */} +
+ +
+
+ ) : ( +
+ {/* Categories Grid */} +
+

Categories

+

+ {categories.reduce((total, category) => total + (category.scripts?.length || 0), 0)} Total scripts +

+
+
+ {categories.map((category, index) => ( + handleCategoryClick(index)} + className="cursor-pointer hover:shadow-lg flex flex-col items-center justify-center py-6 transition-shadow duration-300" + > + +

+ {category.name} +

+
+ + {category.scripts && + category.scripts + .slice(logoIndices[category.name] || 0, (logoIndices[category.name] || 0) + MAX_LOGOS) + .map((script, i) => ( +
+ {script.name { + e.stopPropagation(); + handleScriptClick(script.slug); + }} + /> + {formattedBadge(script.type)} +
+ ))} + +
+

+ {(category as any).description || "No description available."} +

+
+
+ ))} +
+
+ )} +
+ ); +}; + +export default CategoryView; diff --git a/frontend/src/app/data/page.tsx b/frontend/src/app/data/page.tsx new file mode 100644 index 0000000..b752464 --- /dev/null +++ b/frontend/src/app/data/page.tsx @@ -0,0 +1,198 @@ +"use client"; + +import React, { JSX, useEffect, useState } from "react"; +import DatePicker from 'react-datepicker'; +import 'react-datepicker/dist/react-datepicker.css'; +import ApplicationChart from "../../components/ApplicationChart"; + +interface DataModel { + id: number; + ct_type: number; + disk_size: number; + core_count: number; + ram_size: number; + os_type: string; + os_version: string; + disableip6: string; + nsapp: string; + created_at: string; + method: string; + pve_version: string; + status: string; + error: string; + type: string; + [key: string]: any; +} + +interface SummaryData { + total_entries: number; + status_count: Record; + nsapp_count: Record; +} + +const DataFetcher: React.FC = () => { + const [data, setData] = useState([]); + const [summary, setSummary] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [currentPage, setCurrentPage] = useState(1); + const [itemsPerPage, setItemsPerPage] = useState(25); + const [sortConfig, setSortConfig] = useState<{ key: string; direction: 'ascending' | 'descending' } | null>(null); + + useEffect(() => { + const fetchSummary = async () => { + try { + const response = await fetch("https://api.htl-braunau.at/data/summary"); + if (!response.ok) throw new Error(`Failed to fetch summary: ${response.statusText}`); + const result: SummaryData = await response.json(); + setSummary(result); + } catch (err) { + setError((err as Error).message); + } + }; + + fetchSummary(); + }, []); + + useEffect(() => { + const fetchPaginatedData = async () => { + setLoading(true); + try { + const response = await fetch(`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? '' : itemsPerPage}`); + if (!response.ok) throw new Error(`Failed to fetch data: ${response.statusText}`); + const result: DataModel[] = await response.json(); + setData(result); + } catch (err) { + setError((err as Error).message); + } finally { + setLoading(false); + } + }; + + fetchPaginatedData(); + }, [currentPage, itemsPerPage]); + + const sortedData = React.useMemo(() => { + if (!sortConfig) return data; + const sorted = [...data].sort((a, b) => { + if (a[sortConfig.key] < b[sortConfig.key]) { + return sortConfig.direction === 'ascending' ? -1 : 1; + } + if (a[sortConfig.key] > b[sortConfig.key]) { + return sortConfig.direction === 'ascending' ? 1 : -1; + } + return 0; + }); + return sorted; + }, [data, sortConfig]); + + if (loading) return

Loading...

; + if (error) return

Error: {error}

; + + const requestSort = (key: string) => { + let direction: 'ascending' | 'descending' = 'ascending'; + if (sortConfig && sortConfig.key === key && sortConfig.direction === 'ascending') { + direction = 'descending'; + } + setSortConfig({ key, direction }); + }; + + const formatDate = (dateString: string): string => { + const date = new Date(dateString); + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const day = date.getDate(); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const timezoneOffset = dateString.slice(-6); + return `${day}.${month}.${year} ${hours}:${minutes} ${timezoneOffset} GMT`; + }; + + return ( +
+

Created LXCs

+ +

+
+

{summary?.total_entries} results found

+

Status Legend: 🔄 installing {summary?.status_count["installing"] ?? 0} | ✔️ completed {summary?.status_count["done"] ?? 0} | ❌ failed {summary?.status_count["failed"] ?? 0} | ❓ unknown

+
+
+
+ + + + + + + + + + + + + + + + + + + {sortedData.map((item, index) => ( + + + + + + + + + + + + + + + ))} + +
requestSort('status')}>Status requestSort('type')}>Type requestSort('nsapp')}>Application requestSort('os_type')}>OS requestSort('os_version')}>OS Version requestSort('disk_size')}>Disk Size requestSort('core_count')}>Core Count requestSort('ram_size')}>RAM Size requestSort('method')}>Method requestSort('pve_version')}>PVE Version requestSort('error')}>Error Message requestSort('created_at')}>Created At
+ {item.status === "done" ? ( + "✔️" + ) : item.status === "failed" ? ( + "❌" + ) : item.status === "installing" ? ( + "🔄" + ) : ( + item.status + )} + {item.type === "lxc" ? ( + "📦" + ) : item.type === "vm" ? ( + "🖥️" + ) : ( + item.type + )}{item.nsapp}{item.os_type}{item.os_version}{item.disk_size}{item.core_count}{item.ram_size}{item.method}{item.pve_version}{item.error}{formatDate(item.created_at)}
+
+
+
+ + Page {currentPage} + + +
+
+ ); +}; + +export default DataFetcher; diff --git a/frontend/src/app/favicon.ico b/frontend/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2ef326ee6a4806293b1d9f9eb1c3ecbf6bdce1c2 GIT binary patch literal 1841 zcmV-12hRA3P)Px*>q$gGR9HvFn0ZuGRUF5^_q~}nFpOiO0sQOO|3W5rvg6VN-;b5VyKpb_zz;RMcfmz$NLv& znBVvJdB5-P{_cH4(8cQtrG0u6a#@KiQ4-WvOg*K2z27aqfb<6y=_(3p4QAo7i$m9( zu002l;*P@PoT~{Nmviw)*c$;}bLU|8m(`7o-BEhFxmtG$W_Hf65nqw}X(sTv@500e|rVcH;JL*~@` zUr@43J%*XIy*P1qxoyV>L1(f0SQ)N0@F0DMqrtZ?q79nG2WCCAQV9r)@c@RBIXg-g zZ2H5t9yWrt!9PI75q$V{1uTseV;>qafBS2*H!2132xiu{Zx(K@u&)M0K-4&4C~cH^n#`)gE- zAhIT9OIn$xqbOG-MY6v!>i(;pqm$hYWHT*V2cprRUU4W*#6tb`B@4hZmx zjg7sf1gK4zkslm?|4g0mGDL?&m#BF>sqYcAAmopk<+WAIh)AVSgg`3@_dS=KT7SB{a3BytjgPkYer{gg>%W^!EoKX|Oz-P!NQsX(breVd30sl(b7`ag z9%-ktGmnRu*6~B{tE@e*n#`89@}$hNK?cJEanaEw?tsXE75N7%8vSDc*={5RSUSps z;{srobsUP5hF`Dh^Mrnck8k|#U@VtSd` z+3{6Z&3hP-WJa;3*6E&4nKtd?)_|H5X;&1}`i6Q?RuPxgog=vZre_s$0%c_-SDVdS zTC*(F5STC_dQ6KRl4MpJPu#FUrE`w_<|V>M5ODL2aE~g)EZbjjbYi*b!X7IAI~H6N z3CGcXfq^f@$Hc6cR8CGVEc=#PZR|jlE-$qT4NE)&VhTI==8Q2}Y7P+j*#SVW)4x48 zaq7~hOszhxU_3#s;93Bwh!yswqdlq+6Uoghc>4G1i+Rr17}*LA2uPb67q^Uk+@`RQ zUSzTILJvtSCC~^0;(n-9?cP0EI*{D#S!UVc!V`%ck1 zmS3)3CBJ4cw?hJhQYMWV^M%{p)Yen_zEeak4zK^No-RuT2kgd{le+NuapT$Ferw*k zO(Co}VFL#}8x;|;$?cqRS8nz{@3j1?dR`w07xUSloJI|QYpqYU@xLqQ&YbMGt7^>Y zAfm(?PQ@c6pwHC!n3!GiTpj8ed5|_e-+YVj)>FFeDd43877r&|_U&6|HeY!~K3CZ3 z-QQpsKQTHwr?rPx1jB@S8V}K{L=RA@Wo+)R3px)`HZ++v5yQepj|dMx)>icu!#FKl zoLgD1>DdpiCy!mky1u_abeX3rwF<)q41759@yEY&*9M(}VZ!?KgOzoB_kPVu91gs1 z_yvytE5j~mp~1nU#z#fn{tc%MqE5p&ElbU$SAF`!d1ZBhVb;u=o)p|mt98Cjw6{79 zGiS!U5(}*x{=HumO!~oq-R7(eCwSq3@bI8VhYYE14?@wLk&Aw|b=w)!<*M-W=Y9fb zv*B!DBr3ZN#)kf72o32!FeWmxqN5<}dx|Ub+1AaLzpb_&O}$Gg#kK3#v9-n@m)6YS z31I`qv!xhjO~&Wcb)d1AJhjFLFD5^uSW|J}nv4v|G0yHeLx+a+ju;VP_N*SazuhG; zY}dS&GFP!yryIDbGJ+uB#hEiZ4brIwW-wk}UKr%>uZxO`x~bF}*Eq#bwEFW5+7;Gx f2~1a1Lay--?WTauvxr8#00000NkvXXu0mjf$!vt0 literal 0 HcmV?d00001 diff --git a/frontend/src/app/json-editor/_components/Categories.tsx b/frontend/src/app/json-editor/_components/Categories.tsx new file mode 100644 index 0000000..d6b9906 --- /dev/null +++ b/frontend/src/app/json-editor/_components/Categories.tsx @@ -0,0 +1,117 @@ +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Category } from "@/lib/types"; +import { cn } from "@/lib/utils"; +import { z } from "zod"; +import { type Script } from "../_schemas/schemas"; +import { memo } from "react"; + +type CategoryProps = { + script: Script; + setScript: (script: Script) => void; + setIsValid: (isValid: boolean) => void; + setZodErrors: (zodErrors: z.ZodError | null) => void; + categories: Category[]; +}; + +const CategoryTag = memo(({ + category, + onRemove +}: { + category: Category; + onRemove: () => void; +}) => ( + + {category.name} + + +)); + +CategoryTag.displayName = 'CategoryTag'; + +function Categories({ + script, + setScript, + categories, +}: Omit) { + const addCategory = (categoryId: number) => { + setScript({ + ...script, + categories: [...new Set([...script.categories, categoryId])], + }); + }; + + const removeCategory = (categoryId: number) => { + setScript({ + ...script, + categories: script.categories.filter((id: number) => id !== categoryId), + }); + }; + + const categoryMap = new Map(categories.map(c => [c.id, c])); + + return ( +
+ + +
+ {script.categories.map((categoryId) => { + const category = categoryMap.get(categoryId); + return category ? ( + removeCategory(categoryId)} + /> + ) : null; + })} +
+
+ ); +} + +export default memo(Categories); diff --git a/frontend/src/app/json-editor/_components/InstallMethod.tsx b/frontend/src/app/json-editor/_components/InstallMethod.tsx new file mode 100644 index 0000000..8a597c5 --- /dev/null +++ b/frontend/src/app/json-editor/_components/InstallMethod.tsx @@ -0,0 +1,240 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { OperatingSystems } from "@/config/siteConfig"; +import { PlusCircle, Trash2 } from "lucide-react"; +import { memo, useCallback, useRef } from "react"; +import { z } from "zod"; +import { InstallMethodSchema, ScriptSchema, type Script } from "../_schemas/schemas"; + +type InstallMethodProps = { + script: Script; + setScript: (value: Script | ((prevState: Script) => Script)) => void; + setIsValid: (isValid: boolean) => void; + setZodErrors: (zodErrors: z.ZodError | null) => void; +}; + +function InstallMethod({ + script, + setScript, + setIsValid, + setZodErrors, +}: InstallMethodProps) { + const cpuRefs = useRef<(HTMLInputElement | null)[]>([]); + const ramRefs = useRef<(HTMLInputElement | null)[]>([]); + const hddRefs = useRef<(HTMLInputElement | null)[]>([]); + + const addInstallMethod = useCallback(() => { + setScript((prev) => { + const method = InstallMethodSchema.parse({ + type: "default", + script: `${prev.type}/${prev.slug}.sh`, + resources: { + cpu: null, + ram: null, + hdd: null, + os: null, + version: null, + }, + }); + return { + ...prev, + install_methods: [...prev.install_methods, method], + }; + }); + }, [setScript]); + + const updateInstallMethod = useCallback( + ( + index: number, + key: keyof Script["install_methods"][number], + value: Script["install_methods"][number][keyof Script["install_methods"][number]], + ) => { + setScript((prev) => { + const updatedMethods = prev.install_methods.map((method, i) => { + if (i === index) { + const updatedMethod = { ...method, [key]: value }; + + if (key === "type") { + updatedMethod.script = + value === "alpine" + ? `${prev.type}/alpine-${prev.slug}.sh` + : `${prev.type}/${prev.slug}.sh`; + + // Set OS to Alpine and reset version if type is alpine + if (value === "alpine") { + updatedMethod.resources.os = "Alpine"; + updatedMethod.resources.version = null; + } + } + + return updatedMethod; + } + return method; + }); + + const updated = { + ...prev, + install_methods: updatedMethods, + }; + + const result = ScriptSchema.safeParse(updated); + setIsValid(result.success); + if (!result.success) { + setZodErrors(result.error); + } else { + setZodErrors(null); + } + return updated; + }); + }, + [setScript, setIsValid, setZodErrors], + ); + + const removeInstallMethod = useCallback( + (index: number) => { + setScript((prev) => ({ + ...prev, + install_methods: prev.install_methods.filter((_, i) => i !== index), + })); + }, + [setScript], + ); + + return ( + <> +

Install Methods

+ {script.install_methods.map((method, index) => ( +
+ +
+ { + cpuRefs.current[index] = el; + }} + placeholder="CPU in Cores" + type="number" + value={method.resources.cpu || ""} + onChange={(e) => + updateInstallMethod(index, "resources", { + ...method.resources, + cpu: e.target.value ? Number(e.target.value) : null, + }) + } + /> + { + ramRefs.current[index] = el; + }} + placeholder="RAM in MB" + type="number" + value={method.resources.ram || ""} + onChange={(e) => + updateInstallMethod(index, "resources", { + ...method.resources, + ram: e.target.value ? Number(e.target.value) : null, + }) + } + /> + { + hddRefs.current[index] = el; + }} + placeholder="HDD in GB" + type="number" + value={method.resources.hdd || ""} + onChange={(e) => + updateInstallMethod(index, "resources", { + ...method.resources, + hdd: e.target.value ? Number(e.target.value) : null, + }) + } + /> +
+
+ + +
+ +
+ ))} + + + ); +} + +export default memo(InstallMethod); diff --git a/frontend/src/app/json-editor/_components/Note.tsx b/frontend/src/app/json-editor/_components/Note.tsx new file mode 100644 index 0000000..3242b51 --- /dev/null +++ b/frontend/src/app/json-editor/_components/Note.tsx @@ -0,0 +1,130 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { AlertColors } from "@/config/siteConfig"; +import { cn } from "@/lib/utils"; +import { PlusCircle, Trash2 } from "lucide-react"; +import { z } from "zod"; +import { ScriptSchema, type Script } from "../_schemas/schemas"; +import { memo, useCallback, useRef } from "react"; + +type NoteProps = { + script: Script; + setScript: (script: Script) => void; + setIsValid: (isValid: boolean) => void; + setZodErrors: (zodErrors: z.ZodError | null) => void; +}; + +function Note({ + script, + setScript, + setIsValid, + setZodErrors, +}: NoteProps) { + const inputRefs = useRef<(HTMLInputElement | null)[]>([]); + + const addNote = useCallback(() => { + setScript({ + ...script, + notes: [...script.notes, { text: "", type: "" }], + }); + }, [script, setScript]); + + const updateNote = useCallback(( + index: number, + key: keyof Script["notes"][number], + value: string, + ) => { + const updated: Script = { + ...script, + notes: script.notes.map((note, i) => + i === index ? { ...note, [key]: value } : note, + ), + }; + const result = ScriptSchema.safeParse(updated); + setIsValid(result.success); + setZodErrors(result.success ? null : result.error); + setScript(updated); + // Restore focus after state update + if (key === "text") { + setTimeout(() => { + inputRefs.current[index]?.focus(); + }, 0); + } + }, [script, setScript, setIsValid, setZodErrors]); + + const removeNote = useCallback((index: number) => { + setScript({ + ...script, + notes: script.notes.filter((_, i) => i !== index), + }); + }, [script, setScript]); + + const NoteItem = memo( + ({ note, index }: { note: Script["notes"][number]; index: number }) => ( +
+ updateNote(index, "text", e.target.value)} + ref={(el) => { + inputRefs.current[index] = el; + }} + /> + + +
+ ), + ); + + NoteItem.displayName = 'NoteItem'; + + return ( + <> +

Notes

+ {script.notes.map((note, index) => ( + + ))} + + + ); +} + +export default memo(Note); diff --git a/frontend/src/app/json-editor/_schemas/schemas.ts b/frontend/src/app/json-editor/_schemas/schemas.ts new file mode 100644 index 0000000..ad9d16b --- /dev/null +++ b/frontend/src/app/json-editor/_schemas/schemas.ts @@ -0,0 +1,45 @@ +import { z } from "zod"; + +export const InstallMethodSchema = z.object({ + type: z.enum(["default", "alpine"], { + errorMap: () => ({ message: "Type must be either 'default' or 'alpine'" }) + }), + script: z.string().min(1, "Script content cannot be empty"), + resources: z.object({ + cpu: z.number().nullable(), + ram: z.number().nullable(), + hdd: z.number().nullable(), + os: z.string().nullable(), + version: z.string().nullable(), + }), +}); + +const NoteSchema = z.object({ + text: z.string().min(1, "Note text cannot be empty"), + type: z.string().min(1, "Note type cannot be empty"), +}); + +export const ScriptSchema = z.object({ + name: z.string().min(1, "Name is required"), + slug: z.string().min(1, "Slug is required"), + categories: z.array(z.number()), + date_created: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").min(1, "Date is required"), + type: z.enum(["vm", "ct", "misc", "turnkey"], { + errorMap: () => ({ message: "Type must be either 'vm', 'ct', 'misc' or 'turnkey'" }) + }), + updateable: z.boolean(), + privileged: z.boolean(), + interface_port: z.number().nullable(), + documentation: z.string().nullable(), + website: z.string().url().nullable(), + logo: z.string().url().nullable(), + description: z.string().min(1, "Description is required"), + install_methods: z.array(InstallMethodSchema).min(1, "At least one install method is required"), + default_credentials: z.object({ + username: z.string().nullable(), + password: z.string().nullable(), + }), + notes: z.array(NoteSchema), +}); + +export type Script = z.infer; diff --git a/frontend/src/app/json-editor/page.tsx b/frontend/src/app/json-editor/page.tsx new file mode 100644 index 0000000..4e16155 --- /dev/null +++ b/frontend/src/app/json-editor/page.tsx @@ -0,0 +1,355 @@ +"use client"; + +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "@/components/ui/calendar"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; +import { Textarea } from "@/components/ui/textarea"; +import { fetchCategories } from "@/lib/data"; +import { Category } from "@/lib/types"; +import { cn } from "@/lib/utils"; +import { format } from "date-fns"; +import { CalendarIcon, Check, Clipboard, Download } from "lucide-react"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { toast } from "sonner"; +import { z } from "zod"; +import Categories from "./_components/Categories"; +import InstallMethod from "./_components/InstallMethod"; +import Note from "./_components/Note"; +import { ScriptSchema, type Script } from "./_schemas/schemas"; + +const initialScript: Script = { + name: "", + slug: "", + categories: [], + date_created: "", + type: "ct", + updateable: false, + privileged: false, + interface_port: null, + documentation: null, + website: null, + logo: null, + description: "", + install_methods: [], + default_credentials: { + username: null, + password: null, + }, + notes: [], +}; + +export default function JSONGenerator() { + const [script, setScript] = useState + + + + + + +
+ +
+
+
+ {children} + +
+
+
+
+
+
+ + + ); +} diff --git a/frontend/src/app/manifest.ts b/frontend/src/app/manifest.ts new file mode 100644 index 0000000..1cfc38f --- /dev/null +++ b/frontend/src/app/manifest.ts @@ -0,0 +1,28 @@ +import { basePath } from "@/config/siteConfig"; +import type { MetadataRoute } from "next"; + +export const generateStaticParams = () => { + return []; +}; + +export default function manifest(): MetadataRoute.Manifest { + return { + name: "Proxmox VE Helper-Scripts", + short_name: "Proxmox VE Helper-Scripts", + description: + "A Re-designed Front-end for the Proxmox VE Helper-Scripts Repository. Featuring over 200+ scripts to help you manage your Proxmox VE environment.", + theme_color: "#030712", + background_color: "#030712", + display: "standalone", + orientation: "portrait", + scope: `${basePath}`, + start_url: `${basePath}`, + icons: [ + { + src: "logo.png", + sizes: "512x512", + type: "image/png", + }, + ], + }; +} diff --git a/frontend/src/app/not-found.tsx b/frontend/src/app/not-found.tsx new file mode 100644 index 0000000..8307ae2 --- /dev/null +++ b/frontend/src/app/not-found.tsx @@ -0,0 +1,20 @@ +"use client"; +import { Button } from "@/components/ui/button"; + +export default function NotFoundPage() { + return ( +
+
+

+ 404 +

+

+ Oops, the page you are looking for could not be found. +

+
+ +
+ ); +} diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx new file mode 100644 index 0000000..b12bbac --- /dev/null +++ b/frontend/src/app/page.tsx @@ -0,0 +1,137 @@ +"use client"; +import AnimatedGradientText from "@/components/ui/animated-gradient-text"; +import { Button } from "@/components/ui/button"; +import { CardFooter } from "@/components/ui/card"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import Particles from "@/components/ui/particles"; +import { Separator } from "@/components/ui/separator"; +import { basePath } from "@/config/siteConfig"; +import { cn } from "@/lib/utils"; +import { ArrowRightIcon, ExternalLink } from "lucide-react"; +import { useTheme } from "next-themes"; +import Link from "next/link"; +import { useEffect, useState } from "react"; +import { FaGithub } from "react-icons/fa"; + +function CustomArrowRightIcon() { + return ; +} + +export default function Page() { + const { theme } = useTheme(); + + const [color, setColor] = useState("#000000"); + + useEffect(() => { + setColor(theme === "dark" ? "#ffffff" : "#000000"); + }, [theme]); + + return ( +
+ +
+
+ + +
+ +
+ ❤️ + + Scripts by tteck + + +
+ + + + Thank You! + + A big thank you to tteck and the many contributors who have + made this project possible. Your hard work is truly + appreciated by the entire Proxmox community! + + + +
+ + + + + +
+

+ Make managing your Homelab a breeze +

+
+

+ We are a community-driven initiative that simplifies the setup + of Proxmox Virtual Environment (VE). +

+

+ With 300+ scripts to help you manage your{" "} + Proxmox VE environment. Whether you're a seasoned + user or a newcomer, we've got you covered. +

+
+
+
+ + + +
+
+
+
+ ); +} diff --git a/frontend/src/app/robots.ts b/frontend/src/app/robots.ts new file mode 100644 index 0000000..fc01ac8 --- /dev/null +++ b/frontend/src/app/robots.ts @@ -0,0 +1,14 @@ +import { basePath } from "@/config/siteConfig"; +import type { MetadataRoute } from "next"; + +export const dynamic = "force-static"; + +export default function robots(): MetadataRoute.Robots { + return { + rules: { + userAgent: "*", + allow: "/", + }, + sitemap: `https://community-scripts.github.io/${basePath}/sitemap.xml`, + }; +} diff --git a/frontend/src/app/scripts/_components/ScriptAccordion.tsx b/frontend/src/app/scripts/_components/ScriptAccordion.tsx new file mode 100644 index 0000000..11bd26e --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptAccordion.tsx @@ -0,0 +1,132 @@ +import { useCallback, useEffect, useRef } from "react"; + +import { formattedBadge } from "@/components/CommandMenu"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { Category } from "@/lib/types"; +import { cn } from "@/lib/utils"; +import Image from "next/image"; +import Link from "next/link"; +import { useState } from "react"; +import { basePath } from "@/config/siteConfig"; + +export default function ScriptAccordion({ + items, + selectedScript, + setSelectedScript, +}: { + items: Category[]; + selectedScript: string | null; + setSelectedScript: (script: string | null) => void; +}) { + const [expandedItem, setExpandedItem] = useState( + undefined, + ); + const linkRefs = useRef<{ [key: string]: HTMLAnchorElement | null }>({}); + + const handleAccordionChange = (value: string | undefined) => { + setExpandedItem(value); + }; + + const handleSelected = useCallback( + (slug: string) => { + setSelectedScript(slug); + }, + [setSelectedScript], + ); + + useEffect(() => { + if (selectedScript) { + const category = items.find((category) => + category.scripts.some((script) => script.slug === selectedScript), + ); + if (category) { + setExpandedItem(category.name); + handleSelected(selectedScript); + } + } + }, [selectedScript, items, handleSelected]); + return ( + + {items.map((category) => ( + + +
+ {category.name} + + {category.scripts.length} + +
{" "} +
+ + {category.scripts + .slice() + .sort((a, b) => a.name.localeCompare(b.name)) + .map((script, index) => ( +
+ handleSelected(script.slug)} + ref={(el) => { + linkRefs.current[script.slug] = el; + }} + > +
+ + ((e.currentTarget as HTMLImageElement).src = + `/${basePath}/logo.png`) + } + alt={script.name} + className="mr-1 w-4 h-4 rounded-full" + /> + + {script.name} + +
+ {formattedBadge(script.type)} + +
+ ))} +
+
+ ))} +
+ ); +} diff --git a/frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx b/frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx new file mode 100644 index 0000000..3713a16 --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx @@ -0,0 +1,223 @@ +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { basePath, mostPopularScripts } from "@/config/siteConfig"; +import { extractDate } from "@/lib/time"; +import { Category, Script } from "@/lib/types"; +import { CalendarPlus } from "lucide-react"; +import Image from "next/image"; +import Link from "next/link"; +import { useMemo, useState } from "react"; + +const ITEMS_PER_PAGE = 3; + +export const getDisplayValueFromType = (type: string) => { + switch (type) { + case "ct": + return "LXC"; + case "vm": + return "VM"; + case "misc": + return ""; + default: + return ""; + } +}; + +export function LatestScripts({ items }: { items: Category[] }) { + const [page, setPage] = useState(1); + + const latestScripts = useMemo(() => { + if (!items) return []; + + const scripts = items.flatMap((category) => category.scripts || []); + + // Filter out duplicates by slug + const uniqueScriptsMap = new Map(); + scripts.forEach((script) => { + if (!uniqueScriptsMap.has(script.slug)) { + uniqueScriptsMap.set(script.slug, script); + } + }); + + return Array.from(uniqueScriptsMap.values()).sort( + (a, b) => + new Date(b.date_created).getTime() - new Date(a.date_created).getTime(), + ); + }, [items]); + + const goToNextPage = () => { + setPage((prevPage) => prevPage + 1); + }; + + const goToPreviousPage = () => { + setPage((prevPage) => prevPage - 1); + }; + + const startIndex = (page - 1) * ITEMS_PER_PAGE; + const endIndex = page * ITEMS_PER_PAGE; + + if (!items) { + return null; + } + + return ( +
+ {latestScripts.length > 0 && ( +
+

Newest Scripts

+
+ {page > 1 && ( +
+ Previous +
+ )} + {endIndex < latestScripts.length && ( +
+ {page === 1 ? "More.." : "Next"} +
+ )} +
+
+ )} +
+ {latestScripts.slice(startIndex, endIndex).map((script) => ( + + + +
+ + ((e.currentTarget as HTMLImageElement).src = + `/${basePath}/logo.png`) + } + className="h-11 w-11 object-contain" + /> +
+
+

+ {script.name} {getDisplayValueFromType(script.type)} +

+

+ + {extractDate(script.date_created)} +

+
+
+
+ + + {script.description} + + + + + +
+ ))} +
+
+ ); +} + +export function MostViewedScripts({ items }: { items: Category[] }) { + const mostViewedScripts = items.reduce((acc: Script[], category) => { + const foundScripts = category.scripts.filter((script) => + mostPopularScripts.includes(script.slug), + ); + return acc.concat(foundScripts); + }, []); + + return ( +
+ {mostViewedScripts.length > 0 && ( + <> +

Most Viewed Scripts

+ + )} +
+ {mostViewedScripts.map((script) => ( + + + +
+ + ((e.currentTarget as HTMLImageElement).src = + `/${basePath}/logo.png`) + } + className="h-11 w-11 object-contain" + /> +
+
+

+ {script.name} {getDisplayValueFromType(script.type)} +

+

+ + {extractDate(script.date_created)} +

+
+
+
+ + + {script.description} + + + + + +
+ ))} +
+
+ ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItem.tsx b/frontend/src/app/scripts/_components/ScriptItem.tsx new file mode 100644 index 0000000..973514a --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItem.tsx @@ -0,0 +1,107 @@ +"use client"; +import { Separator } from "@/components/ui/separator"; +import { extractDate } from "@/lib/time"; +import { Script } from "@/lib/types"; +import { X } from "lucide-react"; +import Image from "next/image"; + +import { getDisplayValueFromType } from "./ScriptInfoBlocks"; +import Alerts from "./ScriptItems/Alerts"; +import Buttons from "./ScriptItems/Buttons"; +import DefaultPassword from "./ScriptItems/DefaultPassword"; +import DefaultSettings from "./ScriptItems/DefaultSettings"; +import Description from "./ScriptItems/Description"; +import InstallCommand from "./ScriptItems/InstallCommand"; +import InterFaces from "./ScriptItems/InterFaces"; +import Tooltips from "./ScriptItems/Tooltips"; +import { basePath } from "@/config/siteConfig"; + +function ScriptItem({ + item, + setSelectedScript, +}: { + item: Script; + setSelectedScript: (script: string | null) => void; +}) { + const closeScript = () => { + window.history.pushState({}, document.title, window.location.pathname); + setSelectedScript(null); + }; + + const defaultInstallMethod = item.install_methods?.[0]; + const os = defaultInstallMethod?.resources?.os || "Proxmox Node"; + const version = defaultInstallMethod?.resources?.version || ""; + + return ( +
+
+
+
+

Selected Script

+ +
+
+
+
+ + ((e.currentTarget as HTMLImageElement).src = + `/${basePath}/logo.png`) + } + height={400} + alt={item.name} + unoptimized + /> +
+
+
+

+ {item.name} {getDisplayValueFromType(item.type)} +

+

+ Date added: {extractDate(item.date_created)} +

+

+ Default OS: {os} {version} +

+
+
+ +
+
+
+
+
+ + +
+
+ +
+
+ + +
+
+
+

+ How to {item.type == "misc" ? "use" : "install"} +

+ +
+ + +
+
+ +
+
+
+
+ ); +} + +export default ScriptItem; diff --git a/frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx b/frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx new file mode 100644 index 0000000..b915be3 --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx @@ -0,0 +1,35 @@ +import TextCopyBlock from "@/components/TextCopyBlock"; +import { AlertColors } from "@/config/siteConfig"; +import { Script } from "@/lib/types"; +import { cn } from "@/lib/utils"; +import { AlertCircle, NotepadText } from "lucide-react"; + +type NoteProps = { + text: string; + type: keyof typeof AlertColors; +} + +export default function Alerts({ item }: { item: Script }) { + return ( + <> + {item?.notes?.length > 0 && + item.notes.map((note: NoteProps, index: number) => ( +
+

+ {note.type == "info" ? ( + + ) : ( + + )} + {TextCopyBlock(note.text)} +

+
+ ))} + + ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItems/Buttons.tsx b/frontend/src/app/scripts/_components/ScriptItems/Buttons.tsx new file mode 100644 index 0000000..8031868 --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/Buttons.tsx @@ -0,0 +1,81 @@ +import { Button } from "@/components/ui/button"; +import { basePath } from "@/config/siteConfig"; +import { Script } from "@/lib/types"; +import { BookOpenText, Code, Globe, RefreshCcw } from "lucide-react"; +import Link from "next/link"; + +const generateInstallSourceUrl = (slug: string) => { + const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`; + return `${baseUrl}/install/${slug}-install.sh`; +}; + +const generateSourceUrl = (slug: string, type: string) => { + const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`; + return type === "vm" ? `${baseUrl}/vm/${slug}.sh` : `${baseUrl}/misc/${slug}.sh`; + return `${baseUrl}/misc/${slug}.sh`; +}; + +const generateUpdateUrl = (slug: string) => { + const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`; + return `${baseUrl}/ct/${slug}.sh`; +}; + +interface ButtonLinkProps { + href: string; + icon: React.ReactNode; + text: string; +} + +const ButtonLink = ({ href, icon, text }: ButtonLinkProps) => ( + +); + +export default function Buttons({ item }: { item: Script }) { + const isCtOrDefault = ["ct"].includes(item.type); + const installSourceUrl = isCtOrDefault ? generateInstallSourceUrl(item.slug) : null; + const updateSourceUrl = isCtOrDefault ? generateUpdateUrl(item.slug) : null; + const sourceUrl = !isCtOrDefault ? generateSourceUrl(item.slug) : null; + + const buttons = [ + item.website && { + href: item.website, + icon: , + text: "Website", + }, + item.documentation && { + href: item.documentation, + icon: , + text: "Documentation", + }, + installSourceUrl && { + href: installSourceUrl, + icon: , + text: "Install-Source", + }, + updateSourceUrl && { + href: updateSourceUrl, + icon: , + text: "Update-Source", + }, + sourceUrl && { + href: sourceUrl, + icon: , + text: "Source Code", + }, + ].filter(Boolean) as ButtonLinkProps[]; + + return ( +
+ {buttons.map((props, index) => ( + + ))} +
+ ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItems/DefaultPassword.tsx b/frontend/src/app/scripts/_components/ScriptItems/DefaultPassword.tsx new file mode 100644 index 0000000..15a9623 --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/DefaultPassword.tsx @@ -0,0 +1,42 @@ +import handleCopy from "@/components/handleCopy"; +import { Button } from "@/components/ui/button"; +import { Separator } from "@/components/ui/separator"; +import { Script } from "@/lib/types"; + +export default function DefaultPassword({ item }: { item: Script }) { + const { username, password } = item.default_credentials; + const hasDefaultLogin = username && password; + + if (!hasDefaultLogin) return null; + + const copyCredential = (type: "username" | "password") => { + handleCopy(type, item.default_credentials[type] ?? ""); + }; + + return ( +
+
+

Default Login Credentials

+
+ +
+

+ You can use the following credentials to login to the {item.name}{" "} + {item.type}. +

+ {["username", "password"].map((type) => ( +
+ {type.charAt(0).toUpperCase() + type.slice(1)}:{" "} + +
+ ))} +
+
+ ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItems/DefaultSettings.tsx b/frontend/src/app/scripts/_components/ScriptItems/DefaultSettings.tsx new file mode 100644 index 0000000..bfa6175 --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/DefaultSettings.tsx @@ -0,0 +1,51 @@ +import { Script } from "@/lib/types"; + +export default function DefaultSettings({ item }: { item: Script }) { + const getDisplayValueFromRAM = (ram: number) => + ram >= 1024 ? `${Math.floor(ram / 1024)}GB` : `${ram}MB`; + + const ResourceDisplay = ({ + settings, + title, + }: { + settings: (typeof item.install_methods)[0]; + title: string; + }) => { + const { cpu, ram, hdd } = settings.resources; + return ( +
+

{title}

+

CPU: {cpu}vCPU

+

+ RAM: {getDisplayValueFromRAM(ram ?? 0)} +

+

HDD: {hdd}GB

+
+ ); + }; + + const defaultSettings = item.install_methods.find( + (method) => method.type === "default", + ); + const defaultAlpineSettings = item.install_methods.find( + (method) => method.type === "alpine", + ); + + const hasDefaultSettings = + defaultSettings?.resources && + Object.values(defaultSettings.resources).some(Boolean); + + return ( + <> + {hasDefaultSettings && ( + + )} + {defaultAlpineSettings && ( + + )} + + ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItems/Description.tsx b/frontend/src/app/scripts/_components/ScriptItems/Description.tsx new file mode 100644 index 0000000..6a09f0a --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/Description.tsx @@ -0,0 +1,13 @@ +import TextCopyBlock from "@/components/TextCopyBlock"; +import { Script } from "@/lib/types"; + +export default function Description({ item }: { item: Script }) { + return ( +
+

Description

+

+ {TextCopyBlock(item.description)} +

+
+ ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItems/InstallCommand.tsx b/frontend/src/app/scripts/_components/ScriptItems/InstallCommand.tsx new file mode 100644 index 0000000..26d941c --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/InstallCommand.tsx @@ -0,0 +1,85 @@ +import CodeCopyButton from "@/components/ui/code-copy-button"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { basePath } from "@/config/siteConfig"; +import { Script } from "@/lib/types"; +import { getDisplayValueFromType } from "../ScriptInfoBlocks"; + +const getInstallCommand = (scriptPath?: string, isAlpine = false) => { + return `bash -c "$(wget -q${isAlpine ? "" : "L"}O - https://github.com/community-scripts/${basePath}/raw/main/${scriptPath})"`; +}; + +export default function InstallCommand({ item }: { item: Script }) { + const alpineScript = item.install_methods.find( + (method) => method.type === "alpine", + ); + + const defaultScript = item.install_methods.find( + (method) => method.type === "default", + ); + + const renderInstructions = (isAlpine = false) => ( + <> +

+ {isAlpine ? ( + <> + As an alternative option, you can use Alpine Linux and the{" "} + {item.name} package to create a {item.name}{" "} + {getDisplayValueFromType(item.type)} container with faster creation + time and minimal system resource usage. You are also obliged to + adhere to updates provided by the package maintainer. + + ) : item.type == "misc" ? ( + <> + To use the {item.name} script, run the command below in the shell. + + ) : ( + <> + {" "} + To create a new Proxmox VE {item.name}{" "} + {getDisplayValueFromType(item.type)}, run the command below in the + Proxmox VE Shell. + + )} +

+ {isAlpine && ( +

+ To create a new Proxmox VE Alpine-{item.name}{" "} + {getDisplayValueFromType(item.type)}, run the command below in the + Proxmox VE Shell +

+ )} + + ); + + return ( +
+ {alpineScript ? ( + + + Default + Alpine Linux + + + {renderInstructions()} + + {getInstallCommand(defaultScript?.script)} + + + + {renderInstructions(true)} + + {getInstallCommand(alpineScript.script, true)} + + + + ) : defaultScript?.script ? ( + <> + {renderInstructions()} + + {getInstallCommand(defaultScript.script)} + + + ) : null} +
+ ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItems/InterFaces.tsx b/frontend/src/app/scripts/_components/ScriptItems/InterFaces.tsx new file mode 100644 index 0000000..99f855f --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/InterFaces.tsx @@ -0,0 +1,41 @@ +import handleCopy from "@/components/handleCopy"; +import { buttonVariants } from "@/components/ui/button"; +import { Script } from "@/lib/types"; +import { cn } from "@/lib/utils"; +import { ClipboardIcon } from "lucide-react"; + +const CopyButton = ({ + label, + value, +}: { + label: string; + value: string | number; +}) => ( + + {value} + handleCopy(label, String(value))} + className="size-4 cursor-pointer" + /> + +); + +export default function InterFaces({ item }: { item: Script }) { + return ( +
+ {item.interface_port !== null ? ( +
+

+ {"Default Interface:"} +

{" "} + +
+ ) : null} +
+ ); +} diff --git a/frontend/src/app/scripts/_components/ScriptItems/Tooltips.tsx b/frontend/src/app/scripts/_components/ScriptItems/Tooltips.tsx new file mode 100644 index 0000000..9adb58b --- /dev/null +++ b/frontend/src/app/scripts/_components/ScriptItems/Tooltips.tsx @@ -0,0 +1,52 @@ +import { Badge } from "@/components/ui/badge"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { Script } from "@/lib/types"; +import { CircleHelp } from "lucide-react"; +import React from "react"; + +interface TooltipProps { + variant: "warning" | "success"; + label: string; + content: string; +} + +const TooltipBadge: React.FC = ({ variant, label, content }) => ( + + + + + {label} + + + + {content} + + + +); + +export default function Tooltips({ item }: { item: Script }) { + return ( +
+ {item.privileged && ( + + )} + {item.updateable && ( + + )} +
+ ); +} diff --git a/frontend/src/app/scripts/_components/Sidebar.tsx b/frontend/src/app/scripts/_components/Sidebar.tsx new file mode 100644 index 0000000..3680210 --- /dev/null +++ b/frontend/src/app/scripts/_components/Sidebar.tsx @@ -0,0 +1,43 @@ +"use client"; + +import type { Category, Script } from "@/lib/types"; +import ScriptAccordion from "./ScriptAccordion"; + +const Sidebar = ({ + items, + selectedScript, + setSelectedScript, +}: { + items: Category[]; + selectedScript: string | null; + setSelectedScript: (script: string | null) => void; +}) => { + const uniqueScripts = items.reduce((acc, category) => { + for (const script of category.scripts) { + if (!acc.some((s) => s.name === script.name)) { + acc.push(script); + } + } + return acc; + }, [] as Script[]); + + return ( +
+
+

Categories

+

+ {uniqueScripts.length} Total scripts +

+
+
+ +
+
+ ); +}; + +export default Sidebar; \ No newline at end of file diff --git a/frontend/src/app/scripts/page.tsx b/frontend/src/app/scripts/page.tsx new file mode 100644 index 0000000..a02f80b --- /dev/null +++ b/frontend/src/app/scripts/page.tsx @@ -0,0 +1,79 @@ +"use client"; + +export const dynamic = "force-static"; + +import ScriptItem from "@/app/scripts/_components/ScriptItem"; +import { fetchCategories } from "@/lib/data"; +import { Category, Script } from "@/lib/types"; +import { Loader2 } from "lucide-react"; +import { useQueryState } from "nuqs"; +import { Suspense, useEffect, useState } from "react"; +import { + LatestScripts, + MostViewedScripts, +} from "./_components/ScriptInfoBlocks"; +import Sidebar from "./_components/Sidebar"; + +function ScriptContent() { + const [selectedScript, setSelectedScript] = useQueryState("id"); + const [links, setLinks] = useState([]); + const [item, setItem] = useState