diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..485eb66 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +dist +node_modules +tailwind.config.ts diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..54181d5 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,40 @@ +{ + "env": { + "browser": true, + "es6": true, + "node": true, + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + "plugin:import/recommended", + "plugin:jsx-a11y/recommended", + "plugin:tailwindcss/recommended", + "prettier", + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaFeatures": { + "jsx": true, + }, + "ecmaVersion": "latest", + "sourceType": "module", + }, + "plugins": ["react", "@typescript-eslint", "react-hooks", "import", "jsx-a11y", "prettier"], + "settings": { + "react": { + "version": "detect", + }, + }, + "rules": { + "react/react-in-jsx-scope": "off", + "import/no-unresolved": "off", + "@typescript-eslint/consistent-type-imports": "error", + }, + "globals": { + "chrome": "readonly", + }, + "ignorePatterns": ["watch.js", "dist/**"], +} diff --git a/.example.env b/.example.env new file mode 100644 index 0000000..7507c20 --- /dev/null +++ b/.example.env @@ -0,0 +1 @@ +VITE_EXAMPLE=example \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..c50eb91 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Jonghakseo \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..e5ab532 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: Jonghakseo diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..a144fa7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: Jonghakseo + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. Mac, Window, Linux] + - Browser [e.g. chrome, firefox] + - Node Version [e.g. 18.19.1] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..f076f7a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: Jonghakseo + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml new file mode 100644 index 0000000..dffe542 --- /dev/null +++ b/.github/auto_assign.yml @@ -0,0 +1,30 @@ +# Set to true to add reviewers to pull requests +addReviewers: true + +# Set to true to add assignees to pull requests +addAssignees: author + +# A list of reviewers to be added to pull requests (GitHub user name) +reviewers: + - Jonghakseo + +# A number of reviewers added to the pull request +# Set 0 to add all the reviewers (default: 0) +numberOfReviewers: 0 + +# A list of assignees, overrides reviewers if set +# assignees: +# - assigneeA + +# A number of assignees to add to the pull request +# Set to 0 to add all of the assignees. +# Uses numberOfReviewers if unset. +# numberOfAssignees: 2 + +# A list of keywords to be skipped the process that add reviewers if pull requests include it +# skipKeywords: +# - wip + +filterLabels: + exclude: + - dependencies diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3a3cce5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..a3a4409 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,23 @@ + + +> `*` denotes required fields + +## Priority* + +- [ ] High: This PR needs to be merged first, before other tasks. +- [x] Medium: This PR should be merged quickly to prevent conflicts due to common changes. (default) +- [ ] Low: This PR does not affect other tasks, so it can be merged later. + +## Purpose of the PR* + + +## Changes* + + +## How to check the feature + + + + +## Reference + diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..3c25536 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,21 @@ +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 90 +# Number of days of inactivity before a stale Issue or Pull Request is closed +daysUntilClose: 30 +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - pinned + - security +# Label to use when marking as stale +staleLabel: stale +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when removing the stale label. Set to `false` to disable +unmarkComment: false +# Comment to post when closing a stale Issue or Pull Request. Set to `false` to disable +closeComment: true +# Limit to only `issues` or `pulls` +only: issues diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml new file mode 100644 index 0000000..f4c725e --- /dev/null +++ b/.github/workflows/auto-assign.yml @@ -0,0 +1,12 @@ +name: 'Auto Assign' +on: + pull_request: + types: [opened, ready_for_review] + +jobs: + add-reviews: + runs-on: ubuntu-latest + steps: + - uses: kentaro-m/auto-assign-action@v1.2.5 + with: + configuration-path: '.github/auto_assign.yml' diff --git a/.github/workflows/build-zip.yml b/.github/workflows/build-zip.yml new file mode 100644 index 0000000..7a99be9 --- /dev/null +++ b/.github/workflows/build-zip.yml @@ -0,0 +1,27 @@ +name: Build And Upload Extension Zip Via Artifact + +on: + push: + branches: [ main ] + pull_request: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: pnpm + + - run: pnpm install --frozen-lockfile --prefer-offline + + - run: pnpm build + + - uses: actions/upload-artifact@v4 + with: + path: dist/* diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 0000000..4c55b5e --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,34 @@ +name: Run E2E Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + chrome: + name: E2E tests for Chrome + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: pnpm + - run: pnpm install --frozen-lockfile --prefer-offline + - run: pnpm e2e + + firefox: + name: E2E tests for Firefox + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: pnpm + - run: pnpm install --frozen-lockfile --prefer-offline + - run: pnpm e2e:firefox diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100644 index 0000000..bdac30b --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,16 @@ +name: Greetings + +on: [pull_request_target, issues] + +jobs: + greeting: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: 'Thank you for your contribution. We will check and reply to you as soon as possible.' + pr-message: 'Thank you for your contribution. We will check and reply to you as soon as possible.' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..b6bb8f8 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint Check + +on: + push: + branches: [ main ] + pull_request: + +jobs: + eslint: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: pnpm + + - run: pnpm install --frozen-lockfile --prefer-offline + + - run: pnpm lint diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml new file mode 100644 index 0000000..2b962af --- /dev/null +++ b/.github/workflows/prettier.yml @@ -0,0 +1,30 @@ +name: Formating validation + +on: + pull_request: + push: + branches: [main] + +jobs: + prettier: + name: Prettier Check + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Run Prettier + id: prettier-run + uses: rutajdash/prettier-cli-action@v1.0.0 + with: + config_path: ./.prettierrc + file_pattern: "*.{js,jsx,ts,tsx,json}" + + # This step only runs if prettier finds errors causing the previous step to fail + # This steps lists the files where errors were found + - name: Prettier Output + if: ${{ failure() }} + shell: bash + run: | + echo "The following files aren't formatted properly:" + echo "${{steps.prettier-run.outputs.prettier_output}}" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..10d229f --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# dependencies +**/node_modules + +# testing +**/coverage + +# build +**/dist +**/build +**/dist-zip + +# env +**/.env.* +**/.env + +# etc +.DS_Store +.idea +**/.turbo + +# compiled +chrome-extension/public/manifest.json +**/tailwind-output.css diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..409035c --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +pnpm dlx lint-staged --allow-empty diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..2687d1f --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +public-hoist-pattern[]=@testing-library/dom +engine-strict=true \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..1d9b783 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22.12.0 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..822a463 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +dist +node_modules +.gitignore +.github +.eslintignore +.husky +.nvmrc +.prettierignore +LICENSE +*.md +pnpm-lock.yaml \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0196fc4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "trailingComma": "all", + "semi": true, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 120, + "bracketSameLine": true, + "htmlWhitespaceSensitivity": "strict" +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d8c6624 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 Seo Jong Hak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100755 index 0000000..0477873 --- /dev/null +++ b/README.md @@ -0,0 +1,249 @@ +
+ + + + + Logo + + +![](https://img.shields.io/badge/React-61DAFB?style=flat-square&logo=react&logoColor=black) +![](https://img.shields.io/badge/Typescript-3178C6?style=flat-square&logo=typescript&logoColor=white) +![](https://badges.aleen42.com/src/vitejs.svg) + +![GitHub action badge](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/actions/workflows/build-zip.yml/badge.svg) +![GitHub action badge](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/actions/workflows/lint.yml/badge.svg) + +hits + + +> This boilerplate +> has [Legacy version](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/tree/legacy) + +
+ +> [!NOTE] +> This project is listed in the [Awesome Vite](https://github.com/vitejs/awesome-vite) + +> [!TIP] +> Share storage state between all pages +> +> https://github.com/user-attachments/assets/3b8e189f-6443-490e-a455-4f9570267f8c + +## Table of Contents + +- [Intro](#intro) +- [Features](#features) +- [Structure](#structure) + - [ChromeExtension](#structure-chrome-extension) + - [Packages](#structure-packages) + - [Pages](#structure-pages) +- [Getting started](#getting-started) + - [Chrome](#getting-started-chrome) + - [Firefox](#getting-started-firefox) +- [Install dependency](#install-dependency) + - [For root](#install-dependency-for-root) + - [For module](#install-dependency-for-module) +- [Community](#community) +- [Reference](#reference) +- [Star History](#star-history) +- [Contributors](#contributors) + +## Intro + +This boilerplate helps you create Chrome/Firefox extensions using React and Typescript. It improves +the build speed and development experience by using Vite and Turborepo. + +## Features + +- [React18](https://reactjs.org/) +- [TypeScript](https://www.typescriptlang.org/) +- [Tailwindcss](https://tailwindcss.com/) +- [Vite](https://vitejs.dev/) with [Rollup](https://rollupjs.org/) +- [Turborepo](https://turbo.build/repo) +- [Prettier](https://prettier.io/) +- [ESLint](https://eslint.org/) +- [Chrome Extensions Manifest Version 3](https://developer.chrome.com/docs/extensions/mv3/intro/) +- [Custom i18n package](/packages/i18n/) +- [Custom HMR (Hot Module Rebuild) plugin](/packages/hmr/) +- [End-to-end testing with WebdriverIO](https://webdriver.io/) + +## Getting started + +1. When you're using Windows run this: + - `git config --global core.eol lf` + - `git config --global core.autocrlf input` + + **This will set the EOL (End of line) character to be the same as on Linux/macOS. Without this, our bash script won't work, and you will have conflicts with developers on Linux/macOS.** +2. Clone this repository. +3. Check your node version is >= than in `.nvmrc` file, recommend to use [nvm](https://github.com/nvm-sh/nvm?tab=readme-ov-file#intro) +4. Edit `/packages/i18n/locales/`{your locale(s)}/`messages.json` +5. In the objects `extensionDescription` and `extensionName`, change the `message` fields (leave `description` alone) +6. In `/.package.json`, change the `version` to the desired version of your extension. +7. Install pnpm globally: `npm install -g pnpm` (check your node version >= 22.12.0)) +8. Run `pnpm install` + +Then, depending on the target browser: + +### For Chrome: + +1. Run: + - Dev: `pnpm dev` (on Windows, you should run as administrator; see [issue#456](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/456)) + - Prod: `pnpm build` +2. Open in browser - `chrome://extensions` +3. Check - Developer mode +4. Click - Load unpacked in the upper left corner +5. Select the `dist` directory from the boilerplate project + +### For Firefox: + +1. Run: + - Dev: `pnpm dev:firefox` + - Prod: `pnpm build:firefox` +2. Open in browser - `about:debugging#/runtime/this-firefox` +3. Click - Load Temporary Add-on... in the upper right corner +4. Select the `./dist/manifest.json` file from the boilerplate project + +> [!NOTE] +> In Firefox, you load add-ons in temporary mode. That means they'll disappear after each browser close. You have to load the add-on on every browser launch. + +## Install dependency for turborepo: + +### For root: + +1. Run `pnpm i -w` + +### For module: + +1. Run `pnpm i -F ` + +`package` - Name of the package you want to install e.g. `nodemon` \ +`module-name` - You can find it inside each `package.json` under the key `name`, e.g. `@extension/content-script`, you can use only `content-script` without `@extension/` prefix + +## Environment variables + +To add an environment variable: + +1. Copy `.example.env` to `.env` (in the same directory) +2. Add a new record inside `.env`, prefixed with `VITE_`, e.g. `VITE_MY_API_KEY=...` +3. Edit `./vite-env.d.ts` and in the `ImportMetaEnv` interface, add your variable with the appropriate type, e.g. + + `readonly VITE_MY_API_KEY: string;` +4. Then you can read the variable via `import.meta.env.VITE_MY_API_KEY` (learn more at [Env Variables and Modes](https://vite.dev/guide/env-and-mode)) + +#### If you want to set it for each package independently: + +1. Create `.env` inside that package +2. Open related `vite.config.mts` and add `envDir: '.'` at the end of this config +3. Rest steps like above + +#### Remember you can't use global and local at the same time for the same package(It will be overwritten) + +## Boilerplate structure + +### Chrome extension + +The extension lives in the `chrome-extension` directory and includes the following files: + +- [`manifest.js`](chrome-extension/manifest.js) - script that outputs the `manifest.json` +- [`src/background`](chrome-extension/src/background) - [background script](https://developer.chrome.com/docs/extensions/mv3/background_pages/) + (`background.service_worker` in manifest.json) +- [`public`](chrome-extension/public/) - icons referenced in the manifest; content CSS for user's page injection + +> [!IMPORTANT] +> To facilitate development, the boilerplate is configured to "Read and change all your data on all websites". +> In production, it's best practice to limit the premissions to only the strictly necessary websites. See +> [Declaring permissions](https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions) +> and edit `manifest.js` accordingly. + +### Pages + +Code that is transpiled to be part of the extension lives in the [pages](pages/) directory. + +- [`content`](pages/content/) - [content scripts](https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts) + (`content_scripts` in manifest.json) +- [`content-ui`](pages/content-ui) - React UI rendered in the current page (you can see it at the very bottom when you get started) + (`content_scripts` in manifest.json) +- [`content-runtime`](pages/content-runtime/src/) - [injected content scripts](https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts#functionality); + this can be injected from `popup` like standard `content` +- [`devtools`](pages/devtools/) - [extend the browser DevTools](https://developer.chrome.com/docs/extensions/how-to/devtools/extend-devtools#creating) + (`devtools_page` in manifest.json) +- [`devtools-panel`](pages/devtools-panel/) - [DevTools panel](https://developer.chrome.com/docs/extensions/reference/api/devtools/panels) + for [devtools](pages/devtools/src/index.ts) +- [`new-tab`](pages/new-tab/) - [override the default New Tab page](https://developer.chrome.com/docs/extensions/develop/ui/override-chrome-pages) + (`chrome_url_overrides.newtab` in manifest.json) +- [`options`](pages/options/) - [options page](https://developer.chrome.com/docs/extensions/develop/ui/options-page) + (`options_page` in manifest.json) +- [`popup`](pages/popup/) - [popup](https://developer.chrome.com/docs/extensions/reference/api/action#popup) shown when clicking the extension in the toolbar + (`action.default_popup` in manifest.json) +- [`side-panel`](pages/side-panel/) - [sidepanel (Chrome 114+)](https://developer.chrome.com/docs/extensions/reference/api/sidePanel) + (`side_panel.default_path` in manifest.json) + +### Packages + +Some shared packages: + +- `dev-utils` - utilities for Chrome extension development (manifest-parser, logger) +- `i18n` - custom internationalization package; provides i18n function with type safety and other validation +- `hmr` - custom HMR plugin for Vite, injection script for reload/refresh, HMR dev-server +- `shared` - shared code for the entire project (types, constants, custom hooks, components etc.) +- `storage` - helpers for easier integration with [storage](https://developer.chrome.com/docs/extensions/reference/api/storage), e.g. local/session storages +- `tailwind-config` - shared Tailwind config for entire project +- `tsconfig` - shared tsconfig for the entire project +- `ui` - function to merge your Tailwind config with the global one; you can save components here +- `vite-config` - shared Vite config for the entire project +- `zipper` - run `pnpm zip` to pack the `dist` folder into `extension-YYYYMMDD-HHmmss.zip` inside the newly created `dist-zip` +- `e2e` - run `pnpm e2e` for end-to-end tests of your zipped extension on different browsers + +## Troubleshooting + +### Hot module reload seems to have frozen + +If saving source files doesn't cause the extension HMR code to trigger a reload of the browser page, try this: + +1. Ctrl+C the development server and restart it (`pnpm run dev`) +2. If you get a [`grpc` error](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/612), + [kill the `turbo` process](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/612#issuecomment-2518982339) and run `pnpm dev` again. + +## Community + +To chat with other community members, you can join the [Discord](https://discord.gg/4ERQ6jgV9a) server. +You can ask questions on that server, and you can also help others. + +Also, suggest new features or share any challenges you've faced while developing Chrome extensions! + +## Reference + +- [Chrome Extensions](https://developer.chrome.com/docs/extensions) +- [Vite Plugin](https://vitejs.dev/guide/api-plugin.html) +- [Rollup](https://rollupjs.org/guide/en/) +- [Turborepo](https://turbo.build/repo/docs) +- [Rollup-plugin-chrome-extension](https://www.extend-chrome.dev/rollup-plugin) + +## Star History + + + + + + Star History Chart + + + +## Contributors + +This Boilerplate is made possible thanks to all of its contributors. + + + All Contributors + + +--- + +## Special Thanks To + +| JetBrains Logo (Main) logo. | Jackson Hong | +|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + +--- + +Made by [Jonghakseo](https://jonghakseo.github.io/) diff --git a/UPDATE-PACKAGE-VERSIONS.md b/UPDATE-PACKAGE-VERSIONS.md new file mode 100644 index 0000000..d160286 --- /dev/null +++ b/UPDATE-PACKAGE-VERSIONS.md @@ -0,0 +1,8 @@ +For update package version in all ```package.json``` files use this command in root: + +FOR WINDOWS YOU NEED TO USE E.G ```GIT BASH``` CONSOLE OR OTHER WHICH SUPPORT UNIX COMMANDS +```bash +pnpm update-version +``` + +If script was run successfully you will see ```Updated versions to ``` diff --git a/chrome-extension/manifest.js b/chrome-extension/manifest.js new file mode 100755 index 0000000..d88070c --- /dev/null +++ b/chrome-extension/manifest.js @@ -0,0 +1,82 @@ +import fs from 'node:fs'; +import deepmerge from 'deepmerge'; + +const packageJson = JSON.parse(fs.readFileSync('../package.json', 'utf8')); + +const isFirefox = process.env.__FIREFOX__ === 'true'; + +/** + * If you want to disable the sidePanel, you can delete withSidePanel function and remove the sidePanel HoC on the manifest declaration. + * + * ```js + * const manifest = { // remove `withSidePanel()` + * ``` + */ +function withSidePanel(manifest) { + // Firefox does not support sidePanel + if (isFirefox) { + return manifest; + } + return deepmerge(manifest, { + side_panel: { + default_path: 'side-panel/index.html', + }, + permissions: ['sidePanel'], + }); +} + +/** + * After changing, please reload the extension at `chrome://extensions` + * @type {chrome.runtime.ManifestV3} + */ +const manifest = withSidePanel({ + manifest_version: 3, + default_locale: 'en', + /** + * if you want to support multiple languages, you can use the following reference + * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization + */ + name: '__MSG_extensionName__', + version: packageJson.version, + description: '__MSG_extensionDescription__', + host_permissions: [''], + permissions: ['storage', 'scripting', 'tabs', 'notifications'], + options_page: 'options/index.html', + background: { + service_worker: 'background.iife.js', + type: 'module', + }, + action: { + default_popup: 'popup/index.html', + default_icon: 'icon-34.png', + }, + chrome_url_overrides: { + newtab: 'new-tab/index.html', + }, + icons: { + 128: 'icon-128.png', + }, + content_scripts: [ + { + matches: ['http://*/*', 'https://*/*', ''], + js: ['content/index.iife.js'], + }, + { + matches: ['http://*/*', 'https://*/*', ''], + js: ['content-ui/index.iife.js'], + }, + { + matches: ['http://*/*', 'https://*/*', ''], + css: ['content.css'], // public folder + }, + ], + devtools_page: 'devtools/index.html', + web_accessible_resources: [ + { + resources: ['*.js', '*.css', '*.svg', 'icon-128.png', 'icon-34.png'], + matches: ['*://*/*'], + }, + ], +}); + +export default manifest; diff --git a/chrome-extension/package.json b/chrome-extension/package.json new file mode 100644 index 0000000..1622bc0 --- /dev/null +++ b/chrome-extension/package.json @@ -0,0 +1,35 @@ +{ + "name": "chrome-extension", + "version": "0.3.5", + "description": "chrome extension - core settings", + "type": "module", + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "test": "vitest run", + "lint": "eslint ./ --ext .ts,.js,.tsx,.jsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "webextension-polyfill": "^0.12.0", + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*" + }, + "devDependencies": { + "@extension/dev-utils": "workspace:*", + "@extension/hmr": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "@laynezh/vite-plugin-lib-assets": "^0.6.1", + "@types/ws": "^8.5.13", + "magic-string": "^0.30.10", + "ts-loader": "^9.5.1", + "deepmerge": "^4.3.1", + "cross-env": "^7.0.3" + } +} diff --git a/chrome-extension/public/content.css b/chrome-extension/public/content.css new file mode 100644 index 0000000..e69de29 diff --git a/chrome-extension/public/icon-128.png b/chrome-extension/public/icon-128.png new file mode 100644 index 0000000..d5bdad9 Binary files /dev/null and b/chrome-extension/public/icon-128.png differ diff --git a/chrome-extension/public/icon-34.png b/chrome-extension/public/icon-34.png new file mode 100644 index 0000000..a741ff6 Binary files /dev/null and b/chrome-extension/public/icon-34.png differ diff --git a/chrome-extension/src/background/index.ts b/chrome-extension/src/background/index.ts new file mode 100644 index 0000000..b16541b --- /dev/null +++ b/chrome-extension/src/background/index.ts @@ -0,0 +1,9 @@ +import 'webextension-polyfill'; +import { exampleThemeStorage } from '@extension/storage'; + +exampleThemeStorage.get().then(theme => { + console.log('theme', theme); +}); + +console.log('background loaded'); +console.log("Edit 'chrome-extension/src/background/index.ts' and save to reload."); diff --git a/chrome-extension/tsconfig.json b/chrome-extension/tsconfig.json new file mode 100644 index 0000000..c1ba1cc --- /dev/null +++ b/chrome-extension/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@extension/tsconfig/app", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + } + }, + "include": ["src", "utils", "vite.config.mts", "../node_modules/@types"] +} diff --git a/chrome-extension/utils/plugins/make-manifest-plugin.ts b/chrome-extension/utils/plugins/make-manifest-plugin.ts new file mode 100644 index 0000000..a8fe31b --- /dev/null +++ b/chrome-extension/utils/plugins/make-manifest-plugin.ts @@ -0,0 +1,67 @@ +import fs from 'node:fs'; +import { resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import process from 'node:process'; +import { colorLog, ManifestParser } from '@extension/dev-utils'; +import type { PluginOption } from 'vite'; +import type { Manifest } from '@extension/dev-utils/dist/lib/manifest-parser/type'; + +const rootDir = resolve(__dirname, '..', '..'); +const refreshFile = resolve(__dirname, '..', 'refresh.js'); +const manifestFile = resolve(rootDir, 'manifest.js'); + +const getManifestWithCacheBurst = (): Promise<{ default: chrome.runtime.ManifestV3 }> => { + const withCacheBurst = (path: string) => `${path}?${Date.now().toString()}`; + /** + * In Windows, import() doesn't work without file:// protocol. + * So, we need to convert path to file:// protocol. (url.pathToFileURL) + */ + if (process.platform === 'win32') { + return import(withCacheBurst(pathToFileURL(manifestFile).href)); + } + + return import(withCacheBurst(manifestFile)); +}; + +export default function makeManifestPlugin(config: { outDir: string }): PluginOption { + function makeManifest(manifest: chrome.runtime.ManifestV3, to: string) { + if (!fs.existsSync(to)) { + fs.mkdirSync(to); + } + const manifestPath = resolve(to, 'manifest.json'); + + const isFirefox = process.env.__FIREFOX__ === 'true'; + const isDev = process.env.__DEV__ === 'true'; + + if (isDev) { + addRefreshContentScript(manifest); + } + + fs.writeFileSync(manifestPath, ManifestParser.convertManifestToString(manifest, isFirefox ? 'firefox' : 'chrome')); + if (isDev) { + fs.copyFileSync(refreshFile, resolve(to, 'refresh.js')); + } + + colorLog(`Manifest file copy complete: ${manifestPath}`, 'success'); + } + + return { + name: 'make-manifest', + buildStart() { + this.addWatchFile(manifestFile); + }, + async writeBundle() { + const outDir = config.outDir; + const manifest = await getManifestWithCacheBurst(); + makeManifest(manifest.default, outDir); + }, + }; +} + +function addRefreshContentScript(manifest: Manifest) { + manifest.content_scripts = manifest.content_scripts || []; + manifest.content_scripts.push({ + matches: ['http://*/*', 'https://*/*', ''], + js: ['refresh.js'], // for public's HMR(refresh) support + }); +} diff --git a/chrome-extension/utils/refresh.js b/chrome-extension/utils/refresh.js new file mode 100644 index 0000000..5d3dad3 --- /dev/null +++ b/chrome-extension/utils/refresh.js @@ -0,0 +1,72 @@ +/* eslint-disable */ +(function () { + 'use strict'; + // This is the custom ID for HMR (chrome-extension/vite.config.mts) + const __HMR_ID = 'chrome-extension-hmr'; + + const LOCAL_RELOAD_SOCKET_PORT = 8081; + const LOCAL_RELOAD_SOCKET_URL = `ws://localhost:${LOCAL_RELOAD_SOCKET_PORT}`; + + const DO_UPDATE = 'do_update'; + const DONE_UPDATE = 'done_update'; + + class MessageInterpreter { + // eslint-disable-next-line @typescript-eslint/no-empty-function + constructor() {} + + static send(message) { + return JSON.stringify(message); + } + + static receive(serializedMessage) { + return JSON.parse(serializedMessage); + } + } + + function initClient({ id, onUpdate }) { + const ws = new WebSocket(LOCAL_RELOAD_SOCKET_URL); + + ws.onopen = () => { + ws.addEventListener('message', event => { + const message = MessageInterpreter.receive(String(event.data)); + + if (message.type === DO_UPDATE && message.id === id) { + onUpdate(); + ws.send(MessageInterpreter.send({ type: DONE_UPDATE })); + return; + } + }); + }; + } + + function addRefresh() { + let pendingReload = false; + + initClient({ + id: __HMR_ID, + onUpdate: () => { + // disable reload when tab is hidden + if (document.hidden) { + pendingReload = true; + return; + } + reload(); + }, + }); + + // reload + function reload() { + pendingReload = false; + window.location.reload(); + } + + // reload when tab is visible + function reloadWhenTabIsVisible() { + !document.hidden && pendingReload && reload(); + } + + document.addEventListener('visibilitychange', reloadWhenTabIsVisible); + } + + addRefresh(); +})(); diff --git a/chrome-extension/vite.config.mts b/chrome-extension/vite.config.mts new file mode 100644 index 0000000..295dc33 --- /dev/null +++ b/chrome-extension/vite.config.mts @@ -0,0 +1,47 @@ +import { resolve } from 'node:path'; +import { defineConfig, type PluginOption } from "vite"; +import libAssetsPlugin from '@laynezh/vite-plugin-lib-assets'; +import makeManifestPlugin from './utils/plugins/make-manifest-plugin'; +import { watchPublicPlugin, watchRebuildPlugin } from '@extension/hmr'; +import { isDev, isProduction, watchOption } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +const outDir = resolve(rootDir, '..', 'dist'); +export default defineConfig({ + resolve: { + alias: { + '@root': rootDir, + '@src': srcDir, + '@assets': resolve(srcDir, 'assets'), + }, + }, + plugins: [ + libAssetsPlugin({ + outputPath: outDir, + }) as PluginOption, + watchPublicPlugin(), + makeManifestPlugin({ outDir }), + isDev && watchRebuildPlugin({ reload: true, id: 'chrome-extension-hmr' }), + ], + publicDir: resolve(rootDir, 'public'), + build: { + lib: { + formats: ['iife'], + entry: resolve(__dirname, 'src/background/index.ts'), + name: 'BackgroundScript', + fileName: 'background', + }, + outDir, + emptyOutDir: false, + sourcemap: isDev, + minify: isProduction, + reportCompressedSize: isProduction, + watch: watchOption, + rollupOptions: { + external: ['chrome'], + }, + }, + envDir: '../', +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..46581e8 --- /dev/null +++ b/package.json @@ -0,0 +1,76 @@ +{ + "name": "chrome-extension-boilerplate-react-vite", + "version": "0.3.5", + "description": "chrome extension boilerplate", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite.git" + }, + "type": "module", + "scripts": { + "clean:bundle": "rimraf dist && turbo clean:bundle", + "clean:node_modules": "pnpx rimraf node_modules && pnpx turbo clean:node_modules", + "clean:turbo": "rimraf .turbo && turbo clean:turbo", + "clean": "pnpm clean:bundle && pnpm clean:turbo && pnpm clean:node_modules", + "clean:install": "pnpm clean:node_modules && pnpm install --frozen-lockfile", + "build": "pnpm clean:bundle && turbo ready && turbo build", + "build:firefox": "pnpm clean:bundle && turbo ready && cross-env __FIREFOX__=true turbo build", + "zip": "pnpm build && pnpm -F zipper zip", + "zip:firefox": "pnpm build:firefox && cross-env __FIREFOX__=true pnpm -F zipper zip", + "dev": "turbo ready && cross-env __DEV__=true turbo watch dev --concurrency 20", + "dev:firefox": "turbo ready && cross-env __DEV__=true __FIREFOX__=true turbo watch dev --concurrency 20", + "e2e": "pnpm build && pnpm zip && turbo e2e", + "e2e:firefox": "pnpm build:firefox && pnpm zip:firefox && cross-env __FIREFOX__=true turbo e2e", + "type-check": "turbo type-check", + "lint": "turbo lint --continue -- --fix --cache --cache-location node_modules/.cache/.eslintcache", + "lint:fix": "turbo lint:fix --continue -- --fix --cache --cache-location node_modules/.cache/.eslintcache", + "prettier": "turbo prettier --continue -- --cache --cache-location node_modules/.cache/.prettiercache", + "prepare": "husky", + "update-version": "bash update_version.sh" + }, + "dependencies": { + "eslint-plugin-tailwindcss": "^3.17.4", + "react": "18.3.1", + "react-dom": "18.3.1" + }, + "devDependencies": { + "@types/chrome": "^0.0.270", + "@types/node": "^22.5.5", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.18.0", + "@typescript-eslint/parser": "^7.18.0", + "autoprefixer": "^10.4.20", + "cross-env": "^7.0.3", + "esbuild": "^0.23.0", + "eslint": "8.57.0", + "eslint-config-airbnb-typescript": "18.0.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsx-a11y": "6.9.0", + "eslint-plugin-prettier": "5.2.1", + "eslint-plugin-react": "7.35.0", + "eslint-plugin-react-hooks": "4.6.2", + "husky": "^9.1.4", + "lint-staged": "^15.2.7", + "postcss": "^8.4.47", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "tailwindcss": "^3.4.14", + "tslib": "^2.6.3", + "typescript": "5.5.4", + "turbo": "^2.3.3", + "vite": "6.0.5", + "run-script-os": "^1.1.6" + }, + "lint-staged": { + "*.{js,jsx,ts,tsx,json}": [ + "prettier --write" + ] + }, + "packageManager": "pnpm@9.15.1", + "engines": { + "node": ">=22.12.0" + } +} diff --git a/packages/dev-utils/.eslintignore b/packages/dev-utils/.eslintignore new file mode 100644 index 0000000..de4d1f0 --- /dev/null +++ b/packages/dev-utils/.eslintignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/packages/dev-utils/index.ts b/packages/dev-utils/index.ts new file mode 100644 index 0000000..6e936df --- /dev/null +++ b/packages/dev-utils/index.ts @@ -0,0 +1,2 @@ +export * from './lib/manifest-parser'; +export * from './lib/logger'; diff --git a/packages/dev-utils/lib/logger.ts b/packages/dev-utils/lib/logger.ts new file mode 100644 index 0000000..0077b60 --- /dev/null +++ b/packages/dev-utils/lib/logger.ts @@ -0,0 +1,53 @@ +import type { ValueOf } from '@extension/shared'; + +type ColorType = 'success' | 'info' | 'error' | 'warning' | keyof typeof COLORS; + +export function colorLog(message: string, type: ColorType) { + let color: ValueOf; + + switch (type) { + case 'success': + color = COLORS.FgGreen; + break; + case 'info': + color = COLORS.FgBlue; + break; + case 'error': + color = COLORS.FgRed; + break; + case 'warning': + color = COLORS.FgYellow; + break; + default: + color = COLORS[type]; + break; + } + + console.log(color, message); +} + +const COLORS = { + Reset: '\x1b[0m', + Bright: '\x1b[1m', + Dim: '\x1b[2m', + Underscore: '\x1b[4m', + Blink: '\x1b[5m', + Reverse: '\x1b[7m', + Hidden: '\x1b[8m', + FgBlack: '\x1b[30m', + FgRed: '\x1b[31m', + FgGreen: '\x1b[32m', + FgYellow: '\x1b[33m', + FgBlue: '\x1b[34m', + FgMagenta: '\x1b[35m', + FgCyan: '\x1b[36m', + FgWhite: '\x1b[37m', + BgBlack: '\x1b[40m', + BgRed: '\x1b[41m', + BgGreen: '\x1b[42m', + BgYellow: '\x1b[43m', + BgBlue: '\x1b[44m', + BgMagenta: '\x1b[45m', + BgCyan: '\x1b[46m', + BgWhite: '\x1b[47m', +} as const; diff --git a/packages/dev-utils/lib/manifest-parser/impl.ts b/packages/dev-utils/lib/manifest-parser/impl.ts new file mode 100644 index 0000000..415a2be --- /dev/null +++ b/packages/dev-utils/lib/manifest-parser/impl.ts @@ -0,0 +1,36 @@ +import type { ManifestParserInterface, Manifest } from './type'; + +export const ManifestParserImpl: ManifestParserInterface = { + convertManifestToString: (manifest, env) => { + if (env === 'firefox') { + manifest = convertToFirefoxCompatibleManifest(manifest); + } + return JSON.stringify(manifest, null, 2); + }, +}; + +function convertToFirefoxCompatibleManifest(manifest: Manifest) { + const manifestCopy = { + ...manifest, + } as { [key: string]: unknown }; + + manifestCopy.background = { + scripts: [manifest.background?.service_worker], + type: 'module', + }; + manifestCopy.options_ui = { + page: manifest.options_page, + browser_style: false, + }; + manifestCopy.content_security_policy = { + extension_pages: "script-src 'self'; object-src 'self'", + }; + manifestCopy.browser_specific_settings = { + gecko: { + id: 'example@example.com', + strict_min_version: '109.0', + }, + }; + delete manifestCopy.options_page; + return manifestCopy as Manifest; +} diff --git a/packages/dev-utils/lib/manifest-parser/index.ts b/packages/dev-utils/lib/manifest-parser/index.ts new file mode 100644 index 0000000..eba4115 --- /dev/null +++ b/packages/dev-utils/lib/manifest-parser/index.ts @@ -0,0 +1,2 @@ +import { ManifestParserImpl } from './impl'; +export const ManifestParser = ManifestParserImpl; diff --git a/packages/dev-utils/lib/manifest-parser/type.ts b/packages/dev-utils/lib/manifest-parser/type.ts new file mode 100644 index 0000000..d00982c --- /dev/null +++ b/packages/dev-utils/lib/manifest-parser/type.ts @@ -0,0 +1,5 @@ +export type Manifest = chrome.runtime.ManifestV3; + +export interface ManifestParserInterface { + convertManifestToString: (manifest: Manifest, env: 'chrome' | 'firefox') => string; +} diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json new file mode 100644 index 0000000..6183a29 --- /dev/null +++ b/packages/dev-utils/package.json @@ -0,0 +1,28 @@ +{ + "name": "@extension/dev-utils", + "version": "0.3.5", + "description": "chrome extension - dev utils", + "private": true, + "sideEffects": false, + "files": [ + "dist/**" + ], + "main": "dist/index.js", + "module": "dist/index.js", + "types": "index.ts", + "scripts": { + "clean:bundle": "rimraf dist", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "ready": "tsc", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "@extension/shared": "workspace:*" + } +} diff --git a/packages/dev-utils/tsconfig.json b/packages/dev-utils/tsconfig.json new file mode 100644 index 0000000..f6877b2 --- /dev/null +++ b/packages/dev-utils/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "types": ["chrome"] + }, + "include": ["index.ts", "lib"] +} diff --git a/packages/hmr/index.ts b/packages/hmr/index.ts new file mode 100644 index 0000000..9d821d7 --- /dev/null +++ b/packages/hmr/index.ts @@ -0,0 +1 @@ +export * from './lib/plugins'; diff --git a/packages/hmr/lib/constant.ts b/packages/hmr/lib/constant.ts new file mode 100644 index 0000000..8166866 --- /dev/null +++ b/packages/hmr/lib/constant.ts @@ -0,0 +1,6 @@ +export const LOCAL_RELOAD_SOCKET_PORT = 8081; +export const LOCAL_RELOAD_SOCKET_URL = `ws://localhost:${LOCAL_RELOAD_SOCKET_PORT}`; + +export const DO_UPDATE = 'do_update'; +export const DONE_UPDATE = 'done_update'; +export const BUILD_COMPLETE = 'build_complete'; diff --git a/packages/hmr/lib/initializers/initClient.ts b/packages/hmr/lib/initializers/initClient.ts new file mode 100644 index 0000000..d9ead86 --- /dev/null +++ b/packages/hmr/lib/initializers/initClient.ts @@ -0,0 +1,18 @@ +import { DO_UPDATE, DONE_UPDATE, LOCAL_RELOAD_SOCKET_URL } from '../constant'; +import MessageInterpreter from '../interpreter'; + +export default function initClient({ id, onUpdate }: { id: string; onUpdate: () => void }) { + const ws = new WebSocket(LOCAL_RELOAD_SOCKET_URL); + + ws.onopen = () => { + ws.addEventListener('message', event => { + const message = MessageInterpreter.receive(String(event.data)); + + if (message.type === DO_UPDATE && message.id === id) { + onUpdate(); + ws.send(MessageInterpreter.send({ type: DONE_UPDATE })); + return; + } + }); + }; +} diff --git a/packages/hmr/lib/initializers/initReloadServer.ts b/packages/hmr/lib/initializers/initReloadServer.ts new file mode 100644 index 0000000..7214b68 --- /dev/null +++ b/packages/hmr/lib/initializers/initReloadServer.ts @@ -0,0 +1,45 @@ +import type { WebSocket } from 'ws'; +import { WebSocketServer } from 'ws'; +import { BUILD_COMPLETE, DO_UPDATE, DONE_UPDATE, LOCAL_RELOAD_SOCKET_PORT, LOCAL_RELOAD_SOCKET_URL } from '../constant'; +import MessageInterpreter from '../interpreter'; + +const clientsThatNeedToUpdate: Set = new Set(); + +function initReloadServer() { + const wss = new WebSocketServer({ port: LOCAL_RELOAD_SOCKET_PORT }); + + wss.on('listening', () => { + console.log(`[HMR] Server listening at ${LOCAL_RELOAD_SOCKET_URL}`); + }); + + wss.on('connection', ws => { + clientsThatNeedToUpdate.add(ws); + + ws.addEventListener('close', () => { + clientsThatNeedToUpdate.delete(ws); + }); + + ws.addEventListener('message', event => { + if (typeof event.data !== 'string') return; + + const message = MessageInterpreter.receive(event.data); + + if (message.type === DONE_UPDATE) { + ws.close(); + } + + if (message.type === BUILD_COMPLETE) { + clientsThatNeedToUpdate.forEach((ws: WebSocket) => + ws.send(MessageInterpreter.send({ type: DO_UPDATE, id: message.id })), + ); + } + }); + }); + + wss.on('error', error => { + console.error(`[HMR] Failed to start server at ${LOCAL_RELOAD_SOCKET_URL}`); + throw error; + }); +} + +initReloadServer(); diff --git a/packages/hmr/lib/injections/refresh.ts b/packages/hmr/lib/injections/refresh.ts new file mode 100644 index 0000000..8795340 --- /dev/null +++ b/packages/hmr/lib/injections/refresh.ts @@ -0,0 +1,33 @@ +import initClient from '../initializers/initClient'; + +function addRefresh() { + let pendingReload = false; + + initClient({ + // @ts-expect-error That's because of the dynamic code loading + id: __HMR_ID, + onUpdate: () => { + // disable reload when tab is hidden + if (document.hidden) { + pendingReload = true; + return; + } + reload(); + }, + }); + + // reload + function reload(): void { + pendingReload = false; + window.location.reload(); + } + + // reload when tab is visible + function reloadWhenTabIsVisible(): void { + !document.hidden && pendingReload && reload(); + } + + document.addEventListener('visibilitychange', reloadWhenTabIsVisible); +} + +addRefresh(); diff --git a/packages/hmr/lib/injections/reload.ts b/packages/hmr/lib/injections/reload.ts new file mode 100644 index 0000000..10a728d --- /dev/null +++ b/packages/hmr/lib/injections/reload.ts @@ -0,0 +1,15 @@ +import initClient from '../initializers/initClient'; + +function addReload() { + const reload = () => { + chrome.runtime.reload(); + }; + + initClient({ + // @ts-expect-error That's because of the dynamic code loading + id: __HMR_ID, + onUpdate: reload, + }); +} + +addReload(); diff --git a/packages/hmr/lib/interpreter/index.ts b/packages/hmr/lib/interpreter/index.ts new file mode 100644 index 0000000..663e277 --- /dev/null +++ b/packages/hmr/lib/interpreter/index.ts @@ -0,0 +1,14 @@ +import type { SerializedMessage, WebSocketMessage } from '../types'; + +export default class MessageInterpreter { + // eslint-disable-next-line @typescript-eslint/no-empty-function + private constructor() {} + + static send(message: WebSocketMessage): SerializedMessage { + return JSON.stringify(message); + } + + static receive(serializedMessage: SerializedMessage): WebSocketMessage { + return JSON.parse(serializedMessage); + } +} diff --git a/packages/hmr/lib/plugins/index.ts b/packages/hmr/lib/plugins/index.ts new file mode 100644 index 0000000..fba147b --- /dev/null +++ b/packages/hmr/lib/plugins/index.ts @@ -0,0 +1,3 @@ +export * from './watch-rebuild-plugin'; +export * from './make-entry-point-plugin'; +export * from './watch-public-plugin'; diff --git a/packages/hmr/lib/plugins/make-entry-point-plugin.ts b/packages/hmr/lib/plugins/make-entry-point-plugin.ts new file mode 100644 index 0000000..da005b8 --- /dev/null +++ b/packages/hmr/lib/plugins/make-entry-point-plugin.ts @@ -0,0 +1,74 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import type { PluginOption } from 'vite'; + +/** + * make entry point file for content script cache busting + */ +export function makeEntryPointPlugin(): PluginOption { + const cleanupTargets = new Set(); + const isFirefox = process.env.__FIREFOX__ === 'true'; + + return { + name: 'make-entry-point-plugin', + generateBundle(options, bundle) { + const outputDir = options.dir; + + if (!outputDir) { + throw new Error('Output directory not found'); + } + + for (const module of Object.values(bundle)) { + const fileName = path.basename(module.fileName); + const newFileName = fileName.replace('.js', '_dev.js'); + + switch (module.type) { + case 'asset': + if (fileName.endsWith('.map')) { + cleanupTargets.add(path.resolve(outputDir, fileName)); + + const originalFileName = fileName.replace('.map', ''); + const replacedSource = String(module.source).replaceAll(originalFileName, newFileName); + + module.source = ''; + fs.writeFileSync(path.resolve(outputDir, newFileName), replacedSource); + break; + } + break; + + case 'chunk': { + fs.writeFileSync(path.resolve(outputDir, newFileName), module.code); + + if (isFirefox) { + const contentDirectory = extractContentDir(outputDir); + module.code = `import(browser.runtime.getURL("${contentDirectory}/${newFileName}"));`; + } else { + module.code = `import('./${newFileName}');`; + } + break; + } + } + } + }, + closeBundle() { + cleanupTargets.forEach(target => { + fs.unlinkSync(target); + }); + }, + }; +} + +/** + * Extract content directory from output directory for Firefox + * @param outputDir + */ +function extractContentDir(outputDir: string) { + const parts = outputDir.split(path.sep); + const distIndex = parts.indexOf('dist'); + + if (distIndex !== -1 && distIndex < parts.length - 1) { + return parts.slice(distIndex + 1); + } + + throw new Error('Output directory does not contain "dist"'); +} diff --git a/packages/hmr/lib/plugins/watch-public-plugin.ts b/packages/hmr/lib/plugins/watch-public-plugin.ts new file mode 100644 index 0000000..4dd184a --- /dev/null +++ b/packages/hmr/lib/plugins/watch-public-plugin.ts @@ -0,0 +1,15 @@ +import type { PluginOption } from 'vite'; +import fg from 'fast-glob'; + +export function watchPublicPlugin(): PluginOption { + return { + name: 'watch-public-plugin', + async buildStart() { + const files = await fg(['public/**/*']); + + for (const file of files) { + this.addWatchFile(file); + } + }, + }; +} diff --git a/packages/hmr/lib/plugins/watch-rebuild-plugin.ts b/packages/hmr/lib/plugins/watch-rebuild-plugin.ts new file mode 100644 index 0000000..3b3b88a --- /dev/null +++ b/packages/hmr/lib/plugins/watch-rebuild-plugin.ts @@ -0,0 +1,68 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import type { PluginOption } from 'vite'; +import { WebSocket } from 'ws'; +import MessageInterpreter from '../interpreter'; +import { BUILD_COMPLETE, LOCAL_RELOAD_SOCKET_URL } from '../constant'; +import type { PluginConfig } from '../types'; + +const injectionsPath = path.resolve(__dirname, '..', '..', '..', 'build', 'injections'); + +const refreshCode = fs.readFileSync(path.resolve(injectionsPath, 'refresh.js'), 'utf-8'); +const reloadCode = fs.readFileSync(path.resolve(injectionsPath, 'reload.js'), 'utf-8'); + +export function watchRebuildPlugin(config: PluginConfig): PluginOption { + const { refresh, reload, id: _id, onStart } = config; + const hmrCode = (refresh ? refreshCode : '') + (reload ? reloadCode : ''); + + let ws: WebSocket | null = null; + + const id = _id ?? Math.random().toString(36); + let reconnectTries = 0; + + function initializeWebSocket() { + ws = new WebSocket(LOCAL_RELOAD_SOCKET_URL); + + ws.onopen = () => { + console.log(`[HMR] Connected to dev-server at ${LOCAL_RELOAD_SOCKET_URL}`); + }; + + ws.onerror = () => { + console.error(`[HMR] Failed to connect server at ${LOCAL_RELOAD_SOCKET_URL}`); + console.warn('Retrying in 3 seconds...'); + ws = null; + + if (reconnectTries <= 2) { + setTimeout(() => { + reconnectTries++; + initializeWebSocket(); + }, 3_000); + } else { + console.error(`[HMR] Cannot establish connection to server at ${LOCAL_RELOAD_SOCKET_URL}`); + } + }; + } + + return { + name: 'watch-rebuild', + writeBundle() { + onStart?.(); + if (!ws) { + initializeWebSocket(); + return; + } + /** + * When the build is complete, send a message to the reload server. + * The reload server will send a message to the client to reload or refresh the extension. + */ + ws.send(MessageInterpreter.send({ type: BUILD_COMPLETE, id })); + }, + generateBundle(_options, bundle) { + for (const module of Object.values(bundle)) { + if (module.type === 'chunk') { + module.code = `(function() {let __HMR_ID = "${id}";\n` + hmrCode + '\n' + '})();' + '\n' + module.code; + } + } + }, + }; +} diff --git a/packages/hmr/lib/types.ts b/packages/hmr/lib/types.ts new file mode 100644 index 0000000..d9c8e05 --- /dev/null +++ b/packages/hmr/lib/types.ts @@ -0,0 +1,20 @@ +import type { BUILD_COMPLETE, DO_UPDATE, DONE_UPDATE } from './constant'; + +type UpdateRequestMessage = { + type: typeof DO_UPDATE; + id: string; +}; + +type UpdateCompleteMessage = { type: typeof DONE_UPDATE }; +type BuildCompletionMessage = { type: typeof BUILD_COMPLETE; id: string }; + +export type SerializedMessage = string; + +export type WebSocketMessage = UpdateCompleteMessage | UpdateRequestMessage | BuildCompletionMessage; + +export type PluginConfig = { + onStart?: () => void; + reload?: boolean; + refresh?: boolean; + id?: string; +}; diff --git a/packages/hmr/package.json b/packages/hmr/package.json new file mode 100644 index 0000000..e50494d --- /dev/null +++ b/packages/hmr/package.json @@ -0,0 +1,37 @@ +{ + "name": "@extension/hmr", + "version": "0.3.5", + "description": "chrome extension - hot module reload/refresh", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "main": "dist/index.js", + "module": "dist/index.js", + "types": "index.ts", + "scripts": { + "clean:bundle": "rimraf dist && pnpx rimraf build", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "build:tsc": "tsc -b tsconfig.build.json", + "build:rollup": "rollup --config rollup.config.mjs", + "ready": "pnpm run build:tsc && pnpm run build:rollup", + "dev": "node dist/lib/initializers/initReloadServer.js", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "@rollup/plugin-sucrase": "^5.0.2", + "@types/ws": "^8.5.13", + "esm": "^3.2.25", + "fast-glob": "^3.3.2", + "rollup": "^4.24.0", + "ts-node": "^10.9.2", + "ws": "8.18.0" + } +} diff --git a/packages/hmr/rollup.config.mjs b/packages/hmr/rollup.config.mjs new file mode 100644 index 0000000..7b2e0ba --- /dev/null +++ b/packages/hmr/rollup.config.mjs @@ -0,0 +1,30 @@ +import sucrase from '@rollup/plugin-sucrase'; + +const plugins = [ + sucrase({ + exclude: ['node_modules/**'], + transforms: ['typescript'], + }), +]; + +/** + * @type {import("rollup").RollupOptions[]} + */ +export default [ + { + plugins, + input: 'lib/injections/reload.ts', + output: { + format: 'iife', + file: 'build/injections/reload.js', + }, + }, + { + plugins, + input: 'lib/injections/refresh.ts', + output: { + format: 'iife', + file: 'build/injections/refresh.js', + }, + }, +]; diff --git a/packages/hmr/tsconfig.build.json b/packages/hmr/tsconfig.build.json new file mode 100644 index 0000000..5514417 --- /dev/null +++ b/packages/hmr/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "types": ["chrome"] + }, + "exclude": ["lib/injections/**/*"], + "include": ["lib", "index.ts"] +} diff --git a/packages/hmr/tsconfig.json b/packages/hmr/tsconfig.json new file mode 100644 index 0000000..8656bec --- /dev/null +++ b/packages/hmr/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "types": ["chrome"] + }, + "include": ["lib", "index.ts", "rollup.config.mjs"] +} diff --git a/packages/i18n/.eslintignore b/packages/i18n/.eslintignore new file mode 100644 index 0000000..de4d1f0 --- /dev/null +++ b/packages/i18n/.eslintignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/packages/i18n/.gitignore b/packages/i18n/.gitignore new file mode 100644 index 0000000..7030680 --- /dev/null +++ b/packages/i18n/.gitignore @@ -0,0 +1 @@ +lib/i18n.ts diff --git a/packages/i18n/README.md b/packages/i18n/README.md new file mode 100644 index 0000000..d95eb72 --- /dev/null +++ b/packages/i18n/README.md @@ -0,0 +1,223 @@ +# I18n Package + +This package provides a set of tools to help you internationalize your Chrome Extension. + +https://developer.chrome.com/docs/extensions/reference/api/i18n + +## Installation + +If you want to use the i18n translation function in each pages, you need to add the following to the package.json file. + +```json +{ + "dependencies": { + "@extension/i18n": "workspace:*" + } +} +``` + +Then run the following command to install the package. + +```bash +pnpm install +``` + +## Manage translations + +You can manage translations in the `locales` directory. + +`locales/en/messages.json` + +```json +{ + "helloWorld": { + "message": "Hello, World!" + } +} +``` + +`locales/ko/messages.json` + +```json +{ + "helloWorld": { + "message": "μ•ˆλ…•ν•˜μ„Έμš”, μ—¬λŸ¬λΆ„!" + } +} +``` + +## Delete or Add a new language + +When you want to delete or add a new language, you don't need to edit some util files like `lib/types.ts` or `lib/getMessageFromLocale.ts`. +That's because we provide a script to generate util files automatically by the `generate-i18n.mjs` file. + +Following the steps below to delete or add a new language. + +### Delete a language + +If you want to delete unused languages, you can delete the corresponding directory in the `locales` directory. + +``` +locales +β”œβ”€β”€ en +β”‚ └── messages.json +└── ko // delete this directory + └── messages.json +``` + +Then run the following command. (or just run `pnpm dev` or `pnpm build` on root) + +```bash +pnpm genenrate-i8n +``` + +### Add a new language + +If you want to add a new language, you can create a new directory in the `locales` directory. + +``` +locales +β”œβ”€β”€ en +β”‚ └── messages.json +β”œβ”€β”€ ko +β”‚ └── messages.json +└── ja // create this directory + └── messages.json // and create this file +``` + +Then same as above, run the following command. (or just run `pnpm dev` or `pnpm build` on root) + +```bash +pnpm genenrate-i8n +``` + + +## Usage + +### Translation function + +Just import the `t` function and use it to translate the key. + +```typescript +import { t } from '@extension/i18n'; + +console.log(t('loading')); // Loading... +``` + +```typescript jsx +import { t } from '@extension/i18n'; + +const Component = () => { + return ( + + ); +}; +``` + +### Placeholders + +If you want to use placeholders, you can use the following format. + +> For more information, see the [Message Placeholders](https://developer.chrome.com/docs/extensions/how-to/ui/localization-message-formats#placeholders) section. + +`locales/en/messages.json` + +```json +{ + "greeting": { + "description": "Greeting message", + "message": "Hello, My name is $NAME$", + "placeholders": { + "name": { + "content": "$1", + "example": "John Doe" + } + } + }, + "hello": { + "description": "Placeholder example", + "message": "Hello $1" + } +} +``` + +`locales/ko/messages.json` + +```json +{ + "greeting": { + "description": "인사 λ©”μ‹œμ§€", + "message": "μ•ˆλ…•ν•˜μ„Έμš”, 제 이름은 $NAME$μž…λ‹ˆλ‹€.", + "placeholders": { + "name": { + "content": "$1", + "example": "μ„œμ’…ν•™" + } + } + }, + "hello": { + "description": "Placeholder μ˜ˆμ‹œ", + "message": "μ•ˆλ…• $1" + } +} +``` + +If you want to replace the placeholder, you can pass the value as the second argument. + +Function `t` has exactly the same interface as the `chrome.i18n.getMessage` function. + +```typescript +import { t } from '@extension/i18n'; + +console.log(t('greeting', 'John Doe')); // Hello, My name is John Doe +console.log(t('greeting', ['John Doe'])); // Hello, My name is John Doe + +console.log(t('hello')); // Hello +console.log(t('hello', 'World')); // Hello World +console.log(t('hello', ['World'])); // Hello World +``` + +### Locale setting on development + +If you want to show specific language, you can set the `devLocale` property. (only for development) + +```typescript +import { t } from '@extension/i18n'; + +t.devLocale = "ko"; + +console.log(t('hello')); // μ•ˆλ…• +``` + +### Type Safety + +When you forget to add a key to all language's `messages.json` files, you will get a Typescript error. + +`locales/en/messages.json` + +```json +{ + "hello": { + "message": "Hello World!" + } +} +``` + +`locales/ko/messages.json` + +```json +{ + "helloWorld": { + "message": "μ•ˆλ…•ν•˜μ„Έμš”, μ—¬λŸ¬λΆ„!" + } +} +``` + +```typescript +import { t } from '@extension/i18n'; + +// Error: TS2345: Argument of type "hello" is not assignable to parameter of type +console.log(t('hello')); +``` diff --git a/packages/i18n/build.dev.mjs b/packages/i18n/build.dev.mjs new file mode 100644 index 0000000..f0a11fe --- /dev/null +++ b/packages/i18n/build.dev.mjs @@ -0,0 +1,6 @@ +import path from 'node:path'; +import { build } from './build.mjs'; + +const i18nPath = path.resolve('lib', 'i18n-dev.ts'); + +void build(i18nPath); diff --git a/packages/i18n/build.mjs b/packages/i18n/build.mjs new file mode 100644 index 0000000..adb0674 --- /dev/null +++ b/packages/i18n/build.mjs @@ -0,0 +1,29 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import esbuild from 'esbuild'; +import { rimraf } from 'rimraf'; + +/** + * @param i18nPath {string} + */ +export async function build(i18nPath) { + fs.cpSync(i18nPath, path.resolve('lib', 'i18n.ts')); + + await esbuild.build({ + entryPoints: ['./index.ts'], + tsconfig: './tsconfig.json', + bundle: true, + packages: 'bundle', + target: 'es6', + outdir: './dist', + sourcemap: true, + format: 'esm', + }); + + const outDir = path.resolve('..', '..', 'dist'); + const localePath = path.resolve(outDir, '_locales'); + rimraf.sync(localePath); + fs.cpSync(path.resolve('locales'), localePath, { recursive: true }); + + console.log('I18n build complete'); +} diff --git a/packages/i18n/build.prod.mjs b/packages/i18n/build.prod.mjs new file mode 100644 index 0000000..e305a92 --- /dev/null +++ b/packages/i18n/build.prod.mjs @@ -0,0 +1,6 @@ +import path from 'node:path'; +import { build } from './build.mjs'; + +const i18nPath = path.resolve('lib', 'i18n-prod.ts'); + +void build(i18nPath); diff --git a/packages/i18n/genenrate-i18n.mjs b/packages/i18n/genenrate-i18n.mjs new file mode 100644 index 0000000..6caaac6 --- /dev/null +++ b/packages/i18n/genenrate-i18n.mjs @@ -0,0 +1,127 @@ +import fs from 'node:fs'; + +/** + * @url https://developer.chrome.com/docs/extensions/reference/api/i18n#support_multiple_languages + */ +const SUPPORTED_LANGUAGES = { + ar: 'Arabic', + am: 'Amharic', + bg: 'Bulgarian', + bn: 'Bengali', + ca: 'Catalan', + cs: 'Czech', + da: 'Danish', + de: 'German', + el: 'Greek', + en: 'English', + en_AU: 'English (Australia)', + en_GB: 'English (Great Britain)', + en_US: 'English (USA)', + es: 'Spanish', + es_419: 'Spanish (Latin America and Caribbean)', + et: 'Estonian', + fa: 'Persian', + fi: 'Finnish', + fil: 'Filipino', + fr: 'French', + gu: 'Gujarati', + he: 'Hebrew', + hi: 'Hindi', + hr: 'Croatian', + hu: 'Hungarian', + id: 'Indonesian', + it: 'Italian', + ja: 'Japanese', + kn: 'Kannada', + ko: 'Korean', + lt: 'Lithuanian', + lv: 'Latvian', + ml: 'Malayalam', + mr: 'Marathi', + ms: 'Malay', + nl: 'Dutch', + no: 'Norwegian', + pl: 'Polish', + pt_BR: 'Portuguese (Brazil)', + pt_PT: 'Portuguese (Portugal)', + ro: 'Romanian', + ru: 'Russian', + sk: 'Slovak', + sl: 'Slovenian', + sr: 'Serbian', + sv: 'Swedish', + sw: 'Swahili', + ta: 'Tamil', + te: 'Telugu', + th: 'Thai', + tr: 'Turkish', + uk: 'Ukrainian', + vi: 'Vietnamese', + zh_CN: 'Chinese (China)', + zh_TW: 'Chinese (Taiwan)', +}; + +const locales = fs.readdirSync('locales'); + +locales.forEach(locale => { + if (!(locale in SUPPORTED_LANGUAGES)) { + throw new Error(`Unsupported language: ${locale}`); + } +}); + +makeTypeFile(locales); +makeGetMessageFromLocaleFile(locales); + +function makeTypeFile(locales) { + const typeFile = `/** + * This file is generated by generate-i18n.mjs + * Do not edit this file directly + */ +${locales.map(locale => `import type ${locale}Message from '../locales/${locale}/messages.json';`).join('\n')} + +export type MessageKey = ${locales.map(locale => `keyof typeof ${locale}Message`).join(' & ')}; + +export type DevLocale = ${locales.map(locale => `'${locale}'`).join(' | ')}; +`; + + fs.writeFileSync('lib/type.ts', typeFile); +} + +function makeGetMessageFromLocaleFile(locales) { + const defaultLocaleCode = `(() => { + const locales = ${JSON.stringify(locales).replace(/"/g, "'").replace(/,/g, ', ')}; + const firstLocale = locales[0]; + const defaultLocale = Intl.DateTimeFormat().resolvedOptions().locale.replace('-', '_'); + if (locales.includes(defaultLocale)) { + return defaultLocale; + } + const defaultLocaleWithoutRegion = defaultLocale.split('_')[0]; + if (locales.includes(defaultLocaleWithoutRegion)) { + return defaultLocaleWithoutRegion; + } + return firstLocale; +})()`; + + const getMessageFromLocaleFile = `/** + * This file is generated by generate-i18n.mjs + * Do not edit this file directly + */ +${locales.map(locale => `import ${locale}Message from '../locales/${locale}/messages.json';`).join('\n')} + +export function getMessageFromLocale(locale: string) { + switch (locale) { +${locales + .map( + locale => ` case '${locale}': + return ${locale}Message;`, + ) + .join('\n')} + default: + throw new Error('Unsupported locale'); + } +} + +export const defaultLocale = ${defaultLocaleCode}; +`; + fs.writeFileSync('lib/getMessageFromLocale.ts', getMessageFromLocaleFile); +} diff --git a/packages/i18n/index.ts b/packages/i18n/index.ts new file mode 100644 index 0000000..42c4f57 --- /dev/null +++ b/packages/i18n/index.ts @@ -0,0 +1,6 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import { t as t_dev_or_prod } from './lib/i18n'; +import type { t as t_dev } from './lib/i18n-dev'; + +export const t = t_dev_or_prod as unknown as typeof t_dev; diff --git a/packages/i18n/lib/getMessageFromLocale.ts b/packages/i18n/lib/getMessageFromLocale.ts new file mode 100644 index 0000000..e27539e --- /dev/null +++ b/packages/i18n/lib/getMessageFromLocale.ts @@ -0,0 +1,31 @@ +/** + * This file is generated by generate-i18n.mjs + * Do not edit this file directly + */ +import enMessage from '../locales/en/messages.json'; +import koMessage from '../locales/ko/messages.json'; + +export function getMessageFromLocale(locale: string) { + switch (locale) { + case 'en': + return enMessage; + case 'ko': + return koMessage; + default: + throw new Error('Unsupported locale'); + } +} + +export const defaultLocale = (() => { + const locales = ['en', 'ko']; + const firstLocale = locales[0]; + const defaultLocale = Intl.DateTimeFormat().resolvedOptions().locale.replace('-', '_'); + if (locales.includes(defaultLocale)) { + return defaultLocale; + } + const defaultLocaleWithoutRegion = defaultLocale.split('_')[0]; + if (locales.includes(defaultLocaleWithoutRegion)) { + return defaultLocaleWithoutRegion; + } + return firstLocale; +})(); diff --git a/packages/i18n/lib/i18n-dev.ts b/packages/i18n/lib/i18n-dev.ts new file mode 100644 index 0000000..cb60cce --- /dev/null +++ b/packages/i18n/lib/i18n-dev.ts @@ -0,0 +1,44 @@ +import type { DevLocale, MessageKey } from './type'; +import { defaultLocale, getMessageFromLocale } from './getMessageFromLocale'; + +type I18nValue = { + message: string; + placeholders?: Record; +}; + +function translate(key: MessageKey, substitutions?: string | string[]) { + const value = getMessageFromLocale(t.devLocale)[key] as I18nValue; + let message = value.message; + /** + * This is a placeholder replacement logic. But it's not perfect. + * It just imitates the behavior of the Chrome extension i18n API. + * Please check the official document for more information And double-check the behavior on production build. + * + * @url https://developer.chrome.com/docs/extensions/how-to/ui/localization-message-formats#placeholders + */ + if (value.placeholders) { + Object.entries(value.placeholders).forEach(([key, { content }]) => { + if (!content) { + return; + } + message = message.replace(new RegExp(`\\$${key}\\$`, 'gi'), content); + }); + } + if (!substitutions) { + return message; + } + if (Array.isArray(substitutions)) { + return substitutions.reduce((acc, cur, idx) => acc.replace(`$${idx + 1}`, cur), message); + } + return message.replace(/\$(\d+)/, substitutions); +} + +function removePlaceholder(message: string) { + return message.replace(/\$\d+/g, ''); +} + +export const t = (...args: Parameters) => { + return removePlaceholder(translate(...args)); +}; + +t.devLocale = defaultLocale as DevLocale; diff --git a/packages/i18n/lib/i18n-prod.ts b/packages/i18n/lib/i18n-prod.ts new file mode 100644 index 0000000..3deed43 --- /dev/null +++ b/packages/i18n/lib/i18n-prod.ts @@ -0,0 +1,7 @@ +import type { DevLocale, MessageKey } from './type'; + +export function t(key: MessageKey, substitutions?: string | string[]) { + return chrome.i18n.getMessage(key, substitutions); +} + +t.devLocale = '' as DevLocale; // for type consistency with i18n-dev.ts diff --git a/packages/i18n/lib/type.ts b/packages/i18n/lib/type.ts new file mode 100644 index 0000000..6f038c1 --- /dev/null +++ b/packages/i18n/lib/type.ts @@ -0,0 +1,10 @@ +/** + * This file is generated by generate-i18n.mjs + * Do not edit this file directly + */ +import type enMessage from '../locales/en/messages.json'; +import type koMessage from '../locales/ko/messages.json'; + +export type MessageKey = keyof typeof enMessage & keyof typeof koMessage; + +export type DevLocale = 'en' | 'ko'; diff --git a/packages/i18n/locales/en/messages.json b/packages/i18n/locales/en/messages.json new file mode 100644 index 0000000..5a18652 --- /dev/null +++ b/packages/i18n/locales/en/messages.json @@ -0,0 +1,30 @@ +{ + "extensionDescription": { + "description": "Extension description", + "message": "Chrome extension boilerplate developed with Vite, React and Typescript" + }, + "extensionName": { + "description": "Extension name", + "message": "Chrome extension boilerplate" + }, + "toggleTheme": { + "message": "Toggle theme" + }, + "loading": { + "message": "Loading..." + }, + "greeting": { + "description": "Greeting message", + "message": "Hello, My name is $NAME$", + "placeholders": { + "name": { + "content": "$1", + "example": "John Doe" + } + } + }, + "hello": { + "description": "Placeholder example", + "message": "Hello $1" + } +} diff --git a/packages/i18n/locales/ko/messages.json b/packages/i18n/locales/ko/messages.json new file mode 100644 index 0000000..fef8a7e --- /dev/null +++ b/packages/i18n/locales/ko/messages.json @@ -0,0 +1,30 @@ +{ + "extensionDescription": { + "description": "Extension description", + "message": "React, Typescript, Viteλ₯Ό μ‚¬μš©ν•œ 크둬 μ΅μŠ€ν…μ…˜ λ³΄μΌλŸ¬ν”Œλ ˆμ΄νŠΈμž…λ‹ˆλ‹€." + }, + "extensionName": { + "description": "Extension name", + "message": "크둬 μ΅μŠ€ν…μ…˜ λ³΄μΌλŸ¬ν”Œλ ˆμ΄νŠΈ" + }, + "toggleTheme": { + "message": "ν…Œλ§ˆ λ³€κ²½" + }, + "loading": { + "message": "λ‘œλ”© 쀑..." + }, + "greeting": { + "description": "인사 λ©”μ‹œμ§€", + "message": "μ•ˆλ…•ν•˜μ„Έμš”, 제 이름은 $NAME$μž…λ‹ˆλ‹€.", + "placeholders": { + "name": { + "content": "$1", + "example": "μ„œμ’…ν•™" + } + } + }, + "hello": { + "description": "Placeholder μ˜ˆμ‹œ", + "message": "μ•ˆλ…• $1" + } +} diff --git a/packages/i18n/package.json b/packages/i18n/package.json new file mode 100644 index 0000000..1d1e74e --- /dev/null +++ b/packages/i18n/package.json @@ -0,0 +1,29 @@ +{ + "name": "@extension/i18n", + "version": "0.3.5", + "description": "chrome extension - internationalization", + "private": true, + "sideEffects": false, + "files": [ + "dist/**" + ], + "types": "index.ts", + "main": "./dist/index.js", + "scripts": { + "clean:bundle": "rimraf dist", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "genenrate-i8n": "node genenrate-i18n.mjs", + "ready": "pnpm genenrate-i8n && node build.dev.mjs", + "build": "pnpm genenrate-i8n && node build.prod.mjs", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "@extension/hmr": "workspace:*" + } +} diff --git a/packages/i18n/tsconfig.json b/packages/i18n/tsconfig.json new file mode 100644 index 0000000..650fd4e --- /dev/null +++ b/packages/i18n/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "types": ["chrome"] + }, + "include": ["index.ts", "lib", "locales"] +} diff --git a/packages/shared/.eslintignore b/packages/shared/.eslintignore new file mode 100644 index 0000000..de4d1f0 --- /dev/null +++ b/packages/shared/.eslintignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/packages/shared/README.md b/packages/shared/README.md new file mode 100644 index 0000000..7d40c22 --- /dev/null +++ b/packages/shared/README.md @@ -0,0 +1,12 @@ +# Shared Package + +This package contains code shared with other packages. +To use the code in the package, you need to add the following to the package.json file. + +```json +{ + "dependencies": { + "@extension/shared": "workspace:*" + } +} +``` diff --git a/packages/shared/build.mjs b/packages/shared/build.mjs new file mode 100644 index 0000000..c28a283 --- /dev/null +++ b/packages/shared/build.mjs @@ -0,0 +1,15 @@ +import esbuild from 'esbuild'; + +/** + * @type { import('esbuild').BuildOptions } + */ +const buildOptions = { + entryPoints: ['./index.ts', './lib/**/*.ts', './lib/**/*.tsx'], + tsconfig: './tsconfig.json', + bundle: false, + target: 'es6', + outdir: './dist', + sourcemap: true, +}; + +await esbuild.build(buildOptions); diff --git a/packages/shared/index.ts b/packages/shared/index.ts new file mode 100644 index 0000000..80eece6 --- /dev/null +++ b/packages/shared/index.ts @@ -0,0 +1,3 @@ +export * from './lib/hooks'; +export * from './lib/hoc'; +export * from './lib/utils'; diff --git a/packages/shared/lib/hoc/index.ts b/packages/shared/lib/hoc/index.ts new file mode 100644 index 0000000..0ea60db --- /dev/null +++ b/packages/shared/lib/hoc/index.ts @@ -0,0 +1,4 @@ +import { withSuspense } from './withSuspense'; +import { withErrorBoundary } from './withErrorBoundary'; + +export { withSuspense, withErrorBoundary }; diff --git a/packages/shared/lib/hoc/withErrorBoundary.tsx b/packages/shared/lib/hoc/withErrorBoundary.tsx new file mode 100644 index 0000000..4b6f950 --- /dev/null +++ b/packages/shared/lib/hoc/withErrorBoundary.tsx @@ -0,0 +1,43 @@ +import type { ComponentType, ErrorInfo, ReactElement } from 'react'; +import { Component } from 'react'; + +class ErrorBoundary extends Component< + { + children: ReactElement; + fallback: ReactElement; + }, + { + hasError: boolean; + } +> { + state = { hasError: false }; + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error(error, errorInfo); + } + + render() { + if (this.state.hasError) { + return this.props.fallback; + } + + return this.props.children; + } +} + +export function withErrorBoundary>( + Component: ComponentType, + ErrorComponent: ReactElement, +) { + return function WithErrorBoundary(props: T) { + return ( + + + + ); + }; +} diff --git a/packages/shared/lib/hoc/withSuspense.tsx b/packages/shared/lib/hoc/withSuspense.tsx new file mode 100644 index 0000000..8f7c94f --- /dev/null +++ b/packages/shared/lib/hoc/withSuspense.tsx @@ -0,0 +1,15 @@ +import type { ComponentType, ReactElement } from 'react'; +import { Suspense } from 'react'; + +export function withSuspense>( + Component: ComponentType, + SuspenseComponent: ReactElement, +) { + return function WithSuspense(props: T) { + return ( + + + + ); + }; +} diff --git a/packages/shared/lib/hooks/index.ts b/packages/shared/lib/hooks/index.ts new file mode 100644 index 0000000..ce185d9 --- /dev/null +++ b/packages/shared/lib/hooks/index.ts @@ -0,0 +1 @@ +export * from './useStorage'; diff --git a/packages/shared/lib/hooks/useStorage.tsx b/packages/shared/lib/hooks/useStorage.tsx new file mode 100644 index 0000000..4285f85 --- /dev/null +++ b/packages/shared/lib/hooks/useStorage.tsx @@ -0,0 +1,50 @@ +import { useSyncExternalStore } from 'react'; +import type { BaseStorage } from '@extension/storage'; + +type WrappedPromise = ReturnType; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const storageMap: Map, WrappedPromise> = new Map(); + +export function useStorage< + Storage extends BaseStorage, + Data = Storage extends BaseStorage ? Data : unknown, +>(storage: Storage) { + const _data = useSyncExternalStore(storage.subscribe, storage.getSnapshot); + + if (!storageMap.has(storage)) { + storageMap.set(storage, wrapPromise(storage.get())); + } + if (_data !== null) { + storageMap.set(storage, { read: () => _data }); + } + + return (_data ?? storageMap.get(storage)!.read()) as Exclude>; +} + +function wrapPromise(promise: Promise) { + let status = 'pending'; + let result: R; + const suspender = promise.then( + r => { + status = 'success'; + result = r; + }, + e => { + status = 'error'; + result = e; + }, + ); + + return { + read() { + switch (status) { + case 'pending': + throw suspender; + case 'error': + throw result; + default: + return result; + } + }, + }; +} diff --git a/packages/shared/lib/utils/index.ts b/packages/shared/lib/utils/index.ts new file mode 100644 index 0000000..40b21b3 --- /dev/null +++ b/packages/shared/lib/utils/index.ts @@ -0,0 +1 @@ +export * from './shared-types'; diff --git a/packages/shared/lib/utils/shared-types.ts b/packages/shared/lib/utils/shared-types.ts new file mode 100644 index 0000000..5f2cf2c --- /dev/null +++ b/packages/shared/lib/utils/shared-types.ts @@ -0,0 +1 @@ +export type ValueOf = T[keyof T]; diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 0000000..5c1bca0 --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,27 @@ +{ + "name": "@extension/shared", + "version": "0.3.5", + "description": "chrome extension - shared code", + "private": true, + "sideEffects": false, + "files": [ + "dist/**" + ], + "types": "index.ts", + "main": "./dist/index.js", + "scripts": { + "clean:bundle": "rimraf dist", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "ready": "node build.mjs", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/storage": "workspace:*", + "@extension/tsconfig": "workspace:*" + } +} diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 0000000..f6877b2 --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "types": ["chrome"] + }, + "include": ["index.ts", "lib"] +} diff --git a/packages/storage/.eslintignore b/packages/storage/.eslintignore new file mode 100644 index 0000000..de4d1f0 --- /dev/null +++ b/packages/storage/.eslintignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/packages/storage/build.mjs b/packages/storage/build.mjs new file mode 100644 index 0000000..4cfc753 --- /dev/null +++ b/packages/storage/build.mjs @@ -0,0 +1,15 @@ +import esbuild from 'esbuild'; + +/** + * @type { import('esbuild').BuildOptions } + */ +const buildOptions = { + entryPoints: ['./index.ts', './lib/**/*.ts'], + tsconfig: './tsconfig.json', + bundle: false, + target: 'es6', + outdir: './dist', + sourcemap: true, +}; + +await esbuild.build(buildOptions); diff --git a/packages/storage/index.ts b/packages/storage/index.ts new file mode 100644 index 0000000..f41a696 --- /dev/null +++ b/packages/storage/index.ts @@ -0,0 +1 @@ +export * from './lib'; diff --git a/packages/storage/lib/base/base.ts b/packages/storage/lib/base/base.ts new file mode 100644 index 0000000..0ed6ccc --- /dev/null +++ b/packages/storage/lib/base/base.ts @@ -0,0 +1,157 @@ +import type { BaseStorage, StorageConfig, ValueOrUpdate } from './types'; +import { SessionAccessLevelEnum, StorageEnum } from './enums'; + +/** + * Chrome reference error while running `processTailwindFeatures` in tailwindcss. + * To avoid this, we need to check if the globalThis.chrome is available and add fallback logic. + */ +const chrome = globalThis.chrome; + +/** + * Sets or updates an arbitrary cache with a new value or the result of an update function. + */ +async function updateCache(valueOrUpdate: ValueOrUpdate, cache: D | null): Promise { + // Type guard to check if our value or update is a function + function isFunction(value: ValueOrUpdate): value is (prev: D) => D | Promise { + return typeof value === 'function'; + } + + // Type guard to check in case of a function, if its a Promise + function returnsPromise(func: (prev: D) => D | Promise): func is (prev: D) => Promise { + // Use ReturnType to infer the return type of the function and check if it's a Promise + return (func as (prev: D) => Promise) instanceof Promise; + } + + if (isFunction(valueOrUpdate)) { + // Check if the function returns a Promise + if (returnsPromise(valueOrUpdate)) { + return valueOrUpdate(cache as D); + } else { + return valueOrUpdate(cache as D); + } + } else { + return valueOrUpdate; + } +} + +/** + * If one session storage needs access from content scripts, we need to enable it globally. + * @default false + */ +let globalSessionAccessLevelFlag: StorageConfig['sessionAccessForContentScripts'] = false; + +/** + * Checks if the storage permission is granted in the manifest.json. + */ +function checkStoragePermission(storageEnum: StorageEnum): void { + if (!chrome) { + return; + } + + if (chrome.storage[storageEnum] === undefined) { + throw new Error(`Check your storage permission in manifest.json: ${storageEnum} is not defined`); + } +} + +/** + * Creates a storage area for persisting and exchanging data. + */ +export function createStorage(key: string, fallback: D, config?: StorageConfig): BaseStorage { + let cache: D | null = null; + let initedCache = false; + let listeners: Array<() => void> = []; + + const storageEnum = config?.storageEnum ?? StorageEnum.Local; + const liveUpdate = config?.liveUpdate ?? false; + + const serialize = config?.serialization?.serialize ?? ((v: D) => v); + const deserialize = config?.serialization?.deserialize ?? (v => v as D); + + // Set global session storage access level for StoryType.Session, only when not already done but needed. + if ( + globalSessionAccessLevelFlag === false && + storageEnum === StorageEnum.Session && + config?.sessionAccessForContentScripts === true + ) { + checkStoragePermission(storageEnum); + chrome?.storage[storageEnum] + .setAccessLevel({ + accessLevel: SessionAccessLevelEnum.ExtensionPagesAndContentScripts, + }) + .catch(error => { + console.warn(error); + console.warn('Please call setAccessLevel into different context, like a background script.'); + }); + globalSessionAccessLevelFlag = true; + } + + // Register life cycle methods + const get = async (): Promise => { + checkStoragePermission(storageEnum); + const value = await chrome?.storage[storageEnum].get([key]); + + if (!value) { + return fallback; + } + + return deserialize(value[key]) ?? fallback; + }; + + const _emitChange = () => { + listeners.forEach(listener => listener()); + }; + + const set = async (valueOrUpdate: ValueOrUpdate) => { + if (!initedCache) { + cache = await get(); + } + cache = await updateCache(valueOrUpdate, cache); + + await chrome?.storage[storageEnum].set({ [key]: serialize(cache) }); + _emitChange(); + }; + + const subscribe = (listener: () => void) => { + listeners = [...listeners, listener]; + + return () => { + listeners = listeners.filter(l => l !== listener); + }; + }; + + const getSnapshot = () => { + return cache; + }; + + get().then(data => { + cache = data; + initedCache = true; + _emitChange(); + }); + + // Listener for live updates from the browser + async function _updateFromStorageOnChanged(changes: { [key: string]: chrome.storage.StorageChange }) { + // Check if the key we are listening for is in the changes object + if (changes[key] === undefined) return; + + const valueOrUpdate: ValueOrUpdate = deserialize(changes[key].newValue); + + if (cache === valueOrUpdate) return; + + cache = await updateCache(valueOrUpdate, cache); + + _emitChange(); + } + + // Register listener for live updates for our storage area + if (liveUpdate) { + chrome?.storage[storageEnum].onChanged.addListener(_updateFromStorageOnChanged); + } + + return { + get, + set, + getSnapshot, + subscribe, + }; +} diff --git a/packages/storage/lib/base/enums.ts b/packages/storage/lib/base/enums.ts new file mode 100644 index 0000000..4f76282 --- /dev/null +++ b/packages/storage/lib/base/enums.ts @@ -0,0 +1,42 @@ +/** + * Storage area type for persisting and exchanging data. + * @see https://developer.chrome.com/docs/extensions/reference/storage/#overview + */ +export enum StorageEnum { + /** + * Persist data locally against browser restarts. Will be deleted by uninstalling the extension. + * @default + */ + Local = 'local', + /** + * Uploads data to the users account in the cloud and syncs to the users browsers on other devices. Limits apply. + */ + Sync = 'sync', + /** + * Requires an [enterprise policy](https://www.chromium.org/administrators/configuring-policy-for-extensions) with a + * json schema for company wide config. + */ + Managed = 'managed', + /** + * Only persist data until the browser is closed. Recommended for service workers which can shutdown anytime and + * therefore need to restore their state. Set {@link SessionAccessLevelEnum} for permitting content scripts access. + * @implements Chromes [Session Storage](https://developer.chrome.com/docs/extensions/reference/storage/#property-session) + */ + Session = 'session', +} + +/** + * Global access level requirement for the {@link StorageEnum.Session} Storage Area. + * @implements Chromes [Session Access Level](https://developer.chrome.com/docs/extensions/reference/storage/#method-StorageArea-setAccessLevel) + */ +export enum SessionAccessLevelEnum { + /** + * Storage can only be accessed by Extension pages (not Content scripts). + * @default + */ + ExtensionPagesOnly = 'TRUSTED_CONTEXTS', + /** + * Storage can be accessed by both Extension pages and Content scripts. + */ + ExtensionPagesAndContentScripts = 'TRUSTED_AND_UNTRUSTED_CONTEXTS', +} diff --git a/packages/storage/lib/base/types.ts b/packages/storage/lib/base/types.ts new file mode 100644 index 0000000..52fd09f --- /dev/null +++ b/packages/storage/lib/base/types.ts @@ -0,0 +1,45 @@ +import type { StorageEnum } from './enums'; + +export type ValueOrUpdate = D | ((prev: D) => Promise | D); + +export type BaseStorage = { + get: () => Promise; + set: (value: ValueOrUpdate) => Promise; + getSnapshot: () => D | null; + subscribe: (listener: () => void) => () => void; +}; + +export type StorageConfig = { + /** + * Assign the {@link StorageEnum} to use. + * @default Local + */ + storageEnum?: StorageEnum; + /** + * Only for {@link StorageEnum.Session}: Grant Content scripts access to storage area? + * @default false + */ + sessionAccessForContentScripts?: boolean; + /** + * Keeps state live in sync between all instances of the extension. Like between popup, side panel and content scripts. + * To allow chrome background scripts to stay in sync as well, use {@link StorageEnum.Session} storage area with + * {@link StorageConfig.sessionAccessForContentScripts} potentially also set to true. + * @see https://stackoverflow.com/a/75637138/2763239 + * @default false + */ + liveUpdate?: boolean; + /** + * An optional props for converting values from storage and into it. + * @default undefined + */ + serialization?: { + /** + * convert non-native values to string to be saved in storage + */ + serialize: (value: D) => string; + /** + * convert string value from storage to non-native values + */ + deserialize: (text: string) => D; + }; +}; diff --git a/packages/storage/lib/impl/exampleThemeStorage.ts b/packages/storage/lib/impl/exampleThemeStorage.ts new file mode 100644 index 0000000..9573c27 --- /dev/null +++ b/packages/storage/lib/impl/exampleThemeStorage.ts @@ -0,0 +1,24 @@ +import { StorageEnum } from '../base/enums'; +import { createStorage } from '../base/base'; +import type { BaseStorage } from '../base/types'; + +type Theme = 'light' | 'dark'; + +type ThemeStorage = BaseStorage & { + toggle: () => Promise; +}; + +const storage = createStorage('theme-storage-key', 'light', { + storageEnum: StorageEnum.Local, + liveUpdate: true, +}); + +// You can extend it with your own methods +export const exampleThemeStorage: ThemeStorage = { + ...storage, + toggle: async () => { + await storage.set(currentTheme => { + return currentTheme === 'light' ? 'dark' : 'light'; + }); + }, +}; diff --git a/packages/storage/lib/impl/index.ts b/packages/storage/lib/impl/index.ts new file mode 100644 index 0000000..bb9f0cb --- /dev/null +++ b/packages/storage/lib/impl/index.ts @@ -0,0 +1 @@ +export * from './exampleThemeStorage'; diff --git a/packages/storage/lib/index.ts b/packages/storage/lib/index.ts new file mode 100644 index 0000000..3172289 --- /dev/null +++ b/packages/storage/lib/index.ts @@ -0,0 +1,2 @@ +export type { BaseStorage } from './base/types'; +export * from './impl'; diff --git a/packages/storage/package.json b/packages/storage/package.json new file mode 100644 index 0000000..ac6f7d4 --- /dev/null +++ b/packages/storage/package.json @@ -0,0 +1,26 @@ +{ + "name": "@extension/storage", + "version": "0.3.5", + "description": "chrome extension - storage", + "private": true, + "sideEffects": false, + "files": [ + "dist/**" + ], + "main": "./dist/index.js", + "types": "index.ts", + "scripts": { + "clean:bundle": "rimraf dist", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "ready": "node build.mjs", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*" + } +} diff --git a/packages/storage/tsconfig.json b/packages/storage/tsconfig.json new file mode 100644 index 0000000..f6877b2 --- /dev/null +++ b/packages/storage/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "types": ["chrome"] + }, + "include": ["index.ts", "lib"] +} diff --git a/packages/tailwind-config/package.json b/packages/tailwind-config/package.json new file mode 100644 index 0000000..f651647 --- /dev/null +++ b/packages/tailwind-config/package.json @@ -0,0 +1,7 @@ +{ + "name": "@extension/tailwindcss-config", + "version": "0.3.5", + "description": "chrome extension - tailwindcss configuration", + "main": "tailwind.config.ts", + "private": true +} diff --git a/packages/tailwind-config/tailwind.config.ts b/packages/tailwind-config/tailwind.config.ts new file mode 100644 index 0000000..1b88671 --- /dev/null +++ b/packages/tailwind-config/tailwind.config.ts @@ -0,0 +1,8 @@ +import type { Config } from 'tailwindcss/types/config'; + +export default { + theme: { + extend: {}, + }, + plugins: [], +} as Omit; diff --git a/packages/tsconfig/app.json b/packages/tsconfig/app.json new file mode 100644 index 0000000..aa9d24d --- /dev/null +++ b/packages/tsconfig/app.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Chrome Extension App", + "extends": "./base.json" +} diff --git a/packages/tsconfig/base.json b/packages/tsconfig/base.json new file mode 100644 index 0000000..98562ce --- /dev/null +++ b/packages/tsconfig/base.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Base", + "compilerOptions": { + "allowJs": true, + "noEmit": true, + "module": "esnext", + "downlevelIteration": true, + "isolatedModules": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "noImplicitReturns": true, + "jsx": "react-jsx", + "lib": ["DOM", "ESNext"] + } +} diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json new file mode 100644 index 0000000..57b3bea --- /dev/null +++ b/packages/tsconfig/package.json @@ -0,0 +1,6 @@ +{ + "name": "@extension/tsconfig", + "version": "0.3.5", + "description": "chrome extension - tsconfig", + "private": true +} diff --git a/packages/tsconfig/utils.json b/packages/tsconfig/utils.json new file mode 100644 index 0000000..fd59646 --- /dev/null +++ b/packages/tsconfig/utils.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Chrome Extension Utils", + "extends": "./base.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "module": "CommonJS", + "moduleResolution": "Node", + "target": "ES6", + "types": ["node"] + } +} diff --git a/packages/ui/README.md b/packages/ui/README.md new file mode 100644 index 0000000..dee0fac --- /dev/null +++ b/packages/ui/README.md @@ -0,0 +1,352 @@ +# UI Package + +This package provides components that make up the UI. + +## Installation + +First, move to the page you want to use. + +```shell +cd pages/options +``` + +Add the following to the dependencies in `package.json`. + +```json +{ + "dependencies": { + "@extension/ui": "workspace:*" + } +} +``` + +Then, run `pnpm install`. + +```shell +pnpm install +``` + +Add the following to the `tailwind.config.ts` file. + +```ts +import baseConfig from '@extension/tailwindcss-config'; +import { withUI } from '@extension/ui'; + +export default withUI({ + ...baseConfig, + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], +}); +``` + +Add the following to the `index.tsx` file. + +```tsx +import '@extension/ui/dist/global.css'; +``` + +## Add Component + +Add the following to the `lib/components/index.ts` file. + +```tsx +export * from './Button'; +``` + +Add the following to the `lib/components/Button.tsx` file. + +```tsx +import { ComponentPropsWithoutRef } from 'react'; +import { cn } from '../utils'; + +export type ButtonProps = { + theme?: 'light' | 'dark'; +} & ComponentPropsWithoutRef<'button'>; + +export function Button({ theme, className, children, ...props }: ButtonProps) { + return ( + + ); +} +``` + +## Usage + +```tsx +import { Button } from '@extension/ui'; + +export default function ToggleButton() { + const [theme, setTheme] = useState<'light' | 'dark'>('light'); + + const toggle = () => { + setTheme(theme === 'light' ? 'dark' : 'light'); + }; + + return ( + + ); +} +``` + +## Modifying the tailwind config of the UI library + +Modify the `tailwind.config.ts` file to make global style changes to the package. + +## Modifying the css variable of the UI library + +Modify the css variable in the `ui/lib/global.css` code to change the css variable of the package. + +## Guide for Adding shadcn to the UI Package + +You can refer to the this [manual guide](https://ui.shadcn.com/docs/installation/manual) + +1. Create components.json in packages/ui + +Create a file named `components.json` in the `packages/ui` directory with the following content: + +```json +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "lib/global.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/lib/components", + "utils": "@/lib/utils", + "ui": "@/lib/components/ui", + "lib": "@/lib" + } +} +``` + +2. Install dependencies + +Run the following command from the root of your project: + +```shell +pnpm add tailwindcss-animate class-variance-authority -F ui +``` + +3. Edit `withUI.ts` in `lib` folder + +This configuration file is from the manual guide. You can refer to the manual guide to modify the configuration file. ([`Configure tailwind.config.js`](https://ui.shadcn.com/docs/installation/manual)) + +```ts +import deepmerge from 'deepmerge'; +import type { Config } from 'tailwindcss/types/config'; +import { fontFamily } from 'tailwindcss/defaultTheme'; +import tailwindAnimate from 'tailwindcss-animate'; + +export function withUI(tailwindConfig: Config): Config { + return deepmerge( + shadcnConfig, + deepmerge(tailwindConfig, { + content: ['./node_modules/@extension/ui/lib/**/*.{tsx,ts,js,jsx}'], + }), + ); +} + +const shadcnConfig = { + darkMode: ['class'], + theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', + }, + }, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + }, + borderRadius: { + lg: `var(--radius)`, + md: `calc(var(--radius) - 2px)`, + sm: 'calc(var(--radius) - 4px)', + }, + fontFamily: { + sans: ['var(--font-sans)', ...fontFamily.sans], + }, + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + }, + }, + plugins: [tailwindAnimate], +}; +``` + +4. Edit `global.css` in `lib` folder + +This configuration also comes from the manual guide. You can refer to the manual guide to modify the configuration file. ([`Configure styles`](https://ui.shadcn.com/docs/installation/manual)) + +```css +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 47.4% 11.2%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 47.4% 11.2%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + + --card: 0 0% 100%; + --card-foreground: 222.2 47.4% 11.2%; + + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 100% 50%; + --destructive-foreground: 210 40% 98%; + + --ring: 215 20.2% 65.1%; + + --radius: 0.5rem; + } + + .dark { + --background: 224 71% 4%; + --foreground: 213 31% 91%; + + --muted: 223 47% 11%; + --muted-foreground: 215.4 16.3% 56.9%; + + --accent: 216 34% 17%; + --accent-foreground: 210 40% 98%; + + --popover: 224 71% 4%; + --popover-foreground: 215 20.2% 65.1%; + + --border: 216 34% 17%; + --input: 216 34% 17%; + + --card: 224 71% 4%; + --card-foreground: 213 31% 91%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 1.2%; + + --secondary: 222.2 47.4% 11.2%; + --secondary-foreground: 210 40% 98%; + + --destructive: 0 63% 31%; + --destructive-foreground: 210 40% 98%; + + --ring: 216 34% 17%; + + --radius: 0.5rem; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + font-feature-settings: "rlig" 1, "calt" 1; + } +} +``` + +5. Add shadcn components + +Finally, run this command from the root of your project to add the button component: + +```shell +pnpm dlx shadcn@latest add button -c ./packages/ui +``` + +This will add the shadcn button component to your UI package. + +Remember to adjust any paths or package names if your project structure differs from the assumed layout in this guide. + +6. Export components + +Make the `index.ts` file in the `components/ui` directory export the button component: + +```ts +export * from './button'; +``` + +Edit the `index.ts` file in the `packages/ui` directory to export the shadcn ui component: + +```ts +// export * from './lib/components'; // remove this line: duplicated button component +export * from './lib/components/ui'; +``` diff --git a/packages/ui/build.mjs b/packages/ui/build.mjs new file mode 100644 index 0000000..5b6d691 --- /dev/null +++ b/packages/ui/build.mjs @@ -0,0 +1,32 @@ +import fs from 'node:fs'; +import { replaceTscAliasPaths } from 'tsc-alias'; +import { resolve } from 'node:path'; +import esbuild from 'esbuild'; + +/** + * @type { import('esbuild').BuildOptions } + */ +const buildOptions = { + entryPoints: ['./index.ts', './lib/**/*.ts', './lib/**/*.tsx'], + tsconfig: './tsconfig.json', + bundle: false, + target: 'es6', + outdir: './dist', + sourcemap: true, +}; + +await esbuild.build(buildOptions); + +/** + * Post build paths resolve since ESBuild only natively + * support paths resolution for bundling scenario + * @url https://github.com/evanw/esbuild/issues/394#issuecomment-1537247216 + */ +await replaceTscAliasPaths({ + configFile: 'tsconfig.json', + watch: false, + outDir: 'dist', + declarationDir: 'dist', +}); + +fs.copyFileSync(resolve('lib', 'global.css'), resolve('dist', 'global.css')); diff --git a/packages/ui/index.ts b/packages/ui/index.ts new file mode 100644 index 0000000..69816af --- /dev/null +++ b/packages/ui/index.ts @@ -0,0 +1,3 @@ +export * from './lib/components'; +export * from './lib/utils'; +export * from './lib/withUI'; diff --git a/packages/ui/lib/components/Button.tsx b/packages/ui/lib/components/Button.tsx new file mode 100644 index 0000000..88c4100 --- /dev/null +++ b/packages/ui/lib/components/Button.tsx @@ -0,0 +1,20 @@ +import type { ComponentPropsWithoutRef } from 'react'; +import { cn } from '../utils'; + +export type ButtonProps = { + theme?: 'light' | 'dark'; +} & ComponentPropsWithoutRef<'button'>; + +export function Button({ theme, className, children, ...props }: ButtonProps) { + return ( + + ); +} diff --git a/packages/ui/lib/components/index.ts b/packages/ui/lib/components/index.ts new file mode 100644 index 0000000..8b166a8 --- /dev/null +++ b/packages/ui/lib/components/index.ts @@ -0,0 +1 @@ +export * from './Button'; diff --git a/packages/ui/lib/global.css b/packages/ui/lib/global.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/packages/ui/lib/global.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/packages/ui/lib/utils.ts b/packages/ui/lib/utils.ts new file mode 100644 index 0000000..a4a5e22 --- /dev/null +++ b/packages/ui/lib/utils.ts @@ -0,0 +1,7 @@ +import type { ClassValue } from 'clsx'; +import { clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]) => { + return twMerge(clsx(inputs)); +}; diff --git a/packages/ui/lib/withUI.ts b/packages/ui/lib/withUI.ts new file mode 100644 index 0000000..ce7de6e --- /dev/null +++ b/packages/ui/lib/withUI.ts @@ -0,0 +1,8 @@ +import deepmerge from 'deepmerge'; +import type { Config } from 'tailwindcss/types/config'; + +export function withUI(tailwindConfig: Config): Config { + return deepmerge(tailwindConfig, { + content: ['./node_modules/@extension/ui/lib/**/*.{tsx,ts,js,jsx}'], + }); +} diff --git a/packages/ui/package.json b/packages/ui/package.json new file mode 100644 index 0000000..0eb8d03 --- /dev/null +++ b/packages/ui/package.json @@ -0,0 +1,34 @@ +{ + "name": "@extension/ui", + "version": "0.3.5", + "description": "chrome extension - ui components", + "private": true, + "sideEffects": false, + "type": "module", + "files": [ + "dist/**", + "dist/global.css" + ], + "types": "index.ts", + "main": "./dist/index.js", + "scripts": { + "clean:bundle": "rimraf dist", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "ready": "node build.mjs", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "deepmerge": "^4.3.1", + "tsc-alias": "^1.8.10" + }, + "dependencies": { + "clsx": "^2.1.1", + "tailwind-merge": "^2.4.0" + } +} diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json new file mode 100644 index 0000000..f09ba2f --- /dev/null +++ b/packages/ui/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "outDir": "dist", + "baseUrl": ".", + "types": ["chrome"], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["index.ts", "lib"] +} diff --git a/packages/vite-config/index.mjs b/packages/vite-config/index.mjs new file mode 100644 index 0000000..5e70410 --- /dev/null +++ b/packages/vite-config/index.mjs @@ -0,0 +1,2 @@ +export * from './lib/env.mjs'; +export * from './lib/withPageConfig.mjs'; diff --git a/packages/vite-config/lib/env.mjs b/packages/vite-config/lib/env.mjs new file mode 100644 index 0000000..34ed304 --- /dev/null +++ b/packages/vite-config/lib/env.mjs @@ -0,0 +1,2 @@ +export const isDev = process.env.__DEV__ === 'true'; +export const isProduction = !isDev; diff --git a/packages/vite-config/lib/withPageConfig.mjs b/packages/vite-config/lib/withPageConfig.mjs new file mode 100644 index 0000000..bf91e3d --- /dev/null +++ b/packages/vite-config/lib/withPageConfig.mjs @@ -0,0 +1,45 @@ +import { defineConfig } from 'vite'; +import { watchRebuildPlugin } from '@extension/hmr'; +import react from '@vitejs/plugin-react-swc'; +import deepmerge from 'deepmerge'; +import { isDev, isProduction } from './env.mjs'; + +export const watchOption = isDev ? { + buildDelay: 100, + chokidar: { + ignored:[ + /\/packages\/.*\.(ts|tsx|map)$/, + ] + } +}: undefined; + +/** + * @typedef {import('vite').UserConfig} UserConfig + * @param {UserConfig} config + * @returns {UserConfig} + */ +export function withPageConfig(config) { + return defineConfig( + deepmerge( + { + base: '', + plugins: [react(), isDev && watchRebuildPlugin({ refresh: true })], + build: { + sourcemap: isDev, + minify: isProduction, + reportCompressedSize: isProduction, + emptyOutDir: isProduction, + watch: watchOption, + rollupOptions: { + external: ['chrome'], + }, + }, + define: { + 'process.env.NODE_ENV': isDev ? `"development"` : `"production"`, + }, + envDir: '../..' + }, + config, + ), + ); +} diff --git a/packages/vite-config/package.json b/packages/vite-config/package.json new file mode 100644 index 0000000..1e76f39 --- /dev/null +++ b/packages/vite-config/package.json @@ -0,0 +1,18 @@ +{ + "name": "@extension/vite-config", + "version": "0.3.5", + "description": "chrome extension - vite base configuration", + "main": "index.mjs", + "type": "module", + "private": true, + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean": "pnpm clean:node_modules" + }, + "devDependencies": { + "@extension/hmr": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@vitejs/plugin-react-swc": "^3.7.2", + "deepmerge": "^4.3.1" + } +} diff --git a/packages/zipper/.eslintignore b/packages/zipper/.eslintignore new file mode 100644 index 0000000..de4d1f0 --- /dev/null +++ b/packages/zipper/.eslintignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/packages/zipper/index.ts b/packages/zipper/index.ts new file mode 100644 index 0000000..efbfe21 --- /dev/null +++ b/packages/zipper/index.ts @@ -0,0 +1,13 @@ +import { resolve } from 'node:path'; +import { zipBundle } from './lib/zip-bundle'; + +const YYYYMMDD = new Date().toISOString().slice(0, 10).replace(/-/g, ''); +const HHmmss = new Date().toISOString().slice(11, 19).replace(/:/g, ''); +const fileName = `extension-${YYYYMMDD}-${HHmmss}`; + +// package the root dist file +zipBundle({ + distDirectory: resolve(__dirname, '../../dist'), + buildDirectory: resolve(__dirname, '../../dist-zip'), + archiveName: process.env.__FIREFOX__ ? `${fileName}.xpi` : `${fileName}.zip`, +}); diff --git a/packages/zipper/lib/zip-bundle/index.ts b/packages/zipper/lib/zip-bundle/index.ts new file mode 100644 index 0000000..ddb5f2c --- /dev/null +++ b/packages/zipper/lib/zip-bundle/index.ts @@ -0,0 +1,113 @@ +import { createReadStream, createWriteStream, existsSync, mkdirSync } from 'node:fs'; +import { posix, resolve } from 'node:path'; +import glob from 'fast-glob'; +import { AsyncZipDeflate, Zip } from 'fflate'; + +// Converts bytes to megabytes +function toMB(bytes: number): number { + return bytes / 1024 / 1024; +} + +// Creates the build directory if it doesn't exist +function ensureBuildDirectoryExists(buildDirectory: string): void { + if (!existsSync(buildDirectory)) { + mkdirSync(buildDirectory, { recursive: true }); + } +} + +// Logs the package size and duration +function logPackageSize(size: number, startTime: number): void { + console.log(`Zip Package size: ${toMB(size).toFixed(2)} MB in ${Date.now() - startTime}ms`); +} + +// Handles file streaming and zipping +function streamFileToZip( + absPath: string, + relPath: string, + zip: Zip, + onAbort: () => void, + onError: (error: Error) => void, +): void { + const data = new AsyncZipDeflate(relPath, { level: 9 }); + zip.add(data); + + createReadStream(absPath) + .on('data', (chunk: Buffer) => data.push(chunk, false)) + .on('end', () => data.push(new Uint8Array(0), true)) + .on('error', error => { + onAbort(); + onError(error); + }); +} + +// Zips the bundle +export const zipBundle = async ( + { + distDirectory, + buildDirectory, + archiveName, + }: { + distDirectory: string; + buildDirectory: string; + archiveName: string; + }, + withMaps = false, +): Promise => { + ensureBuildDirectoryExists(buildDirectory); + + const zipFilePath = resolve(buildDirectory, archiveName); + const output = createWriteStream(zipFilePath); + + const fileList = await glob( + [ + '**/*', // Pick all nested files + ...(!withMaps ? ['!**/(*.js.map|*.css.map)'] : []), // Exclude source maps conditionally + ], + { + cwd: distDirectory, + onlyFiles: true, + }, + ); + + return new Promise((pResolve, pReject) => { + let aborted = false; + let totalSize = 0; + const timer = Date.now(); + const zip = new Zip((err, data, final) => { + if (err) { + pReject(err); + } else { + totalSize += data.length; + output.write(data); + if (final) { + logPackageSize(totalSize, timer); + output.end(); + pResolve(); + } + } + }); + + // Handle file read streams + for (const file of fileList) { + if (aborted) return; + + const absPath = resolve(distDirectory, file); + const absPosixPath = posix.resolve(distDirectory, file); + const relPosixPath = posix.relative(distDirectory, absPosixPath); + + console.log(`Adding file: ${relPosixPath}`); + streamFileToZip( + absPath, + relPosixPath, + zip, + () => { + aborted = true; + zip.terminate(); + }, + error => pReject(`Error reading file ${absPath}: ${error.message}`), + ); + } + + zip.end(); + }); +}; diff --git a/packages/zipper/package.json b/packages/zipper/package.json new file mode 100644 index 0000000..7c470a5 --- /dev/null +++ b/packages/zipper/package.json @@ -0,0 +1,31 @@ +{ + "name": "@extension/zipper", + "version": "0.3.5", + "description": "chrome extension - zipper", + "private": true, + "sideEffects": false, + "files": [ + "dist/**" + ], + "main": "dist/index.js", + "module": "dist/index.js", + "types": "index.ts", + "scripts": { + "clean:bundle": "rimraf dist", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "zip": "tsx index.ts", + "ready": "tsc", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "fast-glob": "^3.3.2", + "fflate": "^0.8.2", + "tsx": "^4.19.2" + } +} diff --git a/packages/zipper/tsconfig.json b/packages/zipper/tsconfig.json new file mode 100644 index 0000000..9dc866c --- /dev/null +++ b/packages/zipper/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "types": ["chrome", "node"] + }, + "include": ["index.ts", "lib"] +} diff --git a/pages/content-runtime/package.json b/pages/content-runtime/package.json new file mode 100644 index 0000000..34b5f3c --- /dev/null +++ b/pages/content-runtime/package.json @@ -0,0 +1,26 @@ +{ + "name": "@extension/content-runtime-script", + "version": "0.3.5", + "description": "chrome extension - content runtime script", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "@extension/hmr": "workspace:*", + "@extension/vite-config": "workspace:*" + } +} diff --git a/pages/content-runtime/src/App.tsx b/pages/content-runtime/src/App.tsx new file mode 100644 index 0000000..8cbbd37 --- /dev/null +++ b/pages/content-runtime/src/App.tsx @@ -0,0 +1,9 @@ +import { useEffect } from 'react'; + +export default function App() { + useEffect(() => { + console.log('runtime content view loaded'); + }, []); + + return
runtime content view
; +} diff --git a/pages/content-runtime/src/Root.tsx b/pages/content-runtime/src/Root.tsx new file mode 100644 index 0000000..8b39064 --- /dev/null +++ b/pages/content-runtime/src/Root.tsx @@ -0,0 +1,37 @@ +import { createRoot } from 'react-dom/client'; +import App from '@src/App'; +// eslint-disable-next-line +// @ts-ignore +import injectedStyle from '@src/index.css?inline'; + +export function mount() { + const root = document.createElement('div'); + root.id = 'chrome-extension-boilerplate-react-vite-runtime-content-view-root'; + + document.body.append(root); + + const rootIntoShadow = document.createElement('div'); + rootIntoShadow.id = 'shadow-root'; + + const shadowRoot = root.attachShadow({ mode: 'open' }); + + if (navigator.userAgent.includes('Firefox')) { + /** + * In the firefox environment, adoptedStyleSheets cannot be used due to the bug + * @url https://bugzilla.mozilla.org/show_bug.cgi?id=1770592 + * + * Injecting styles into the document, this may cause style conflicts with the host page + */ + const styleElement = document.createElement('style'); + styleElement.innerHTML = injectedStyle; + shadowRoot.appendChild(styleElement); + } else { + /** Inject styles into shadow dom */ + const globalStyleSheet = new CSSStyleSheet(); + globalStyleSheet.replaceSync(injectedStyle); + shadowRoot.adoptedStyleSheets = [globalStyleSheet]; + } + + shadowRoot.appendChild(rootIntoShadow); + createRoot(rootIntoShadow).render(); +} diff --git a/pages/content-runtime/src/index.css b/pages/content-runtime/src/index.css new file mode 100644 index 0000000..151be5a --- /dev/null +++ b/pages/content-runtime/src/index.css @@ -0,0 +1,3 @@ +.runtime-content-view-text { + font-size: 20px; +} diff --git a/pages/content-runtime/src/index.ts b/pages/content-runtime/src/index.ts new file mode 100644 index 0000000..c37dc9a --- /dev/null +++ b/pages/content-runtime/src/index.ts @@ -0,0 +1,4 @@ +import { mount } from '@src/Root'; + +mount(); +console.log('runtime script loaded'); diff --git a/pages/content-runtime/tsconfig.json b/pages/content-runtime/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/content-runtime/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/content-runtime/vite.config.mts b/pages/content-runtime/vite.config.mts new file mode 100644 index 0000000..010e144 --- /dev/null +++ b/pages/content-runtime/vite.config.mts @@ -0,0 +1,23 @@ +import { resolve } from 'node:path'; +import { withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + lib: { + formats: ['iife'], + entry: resolve(__dirname, 'src/index.ts'), + name: 'ContentRuntimeScript', + fileName: 'index', + }, + outDir: resolve(rootDir, '..', '..', 'dist', 'content-runtime'), + }, +}); diff --git a/pages/content-ui/package.json b/pages/content-ui/package.json new file mode 100644 index 0000000..33ebe4d --- /dev/null +++ b/pages/content-ui/package.json @@ -0,0 +1,38 @@ +{ + "name": "@extension/content-ui", + "version": "0.3.5", + "description": "chrome extension - content ui", + "type": "module", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:bundle": "rimraf dist", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:bundle && pnpm clean:node_modules && pnpm clean:turbo", + "build:tailwindcss": "pnpm tailwindcss -i ./src/tailwind-input.css -o ./dist/tailwind-output.css -m", + "build": "pnpm build:tailwindcss && vite build", + "build:watch": "concurrently \"cross-env __DEV__=true vite build --mode development\" \"pnpm build:tailwindcss -- -w\"", + "dev": "pnpm build:tailwindcss && pnpm build:watch", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*", + "@extension/ui": "workspace:*" + }, + "devDependencies": { + "@extension/tailwindcss-config": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/hmr": "workspace:*", + "@extension/vite-config": "workspace:*", + "concurrently": "^9.0.1", + "cross-env": "^7.0.3" + } +} diff --git a/pages/content-ui/public/logo.svg b/pages/content-ui/public/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/pages/content-ui/public/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pages/content-ui/src/App.tsx b/pages/content-ui/src/App.tsx new file mode 100644 index 0000000..70a0de3 --- /dev/null +++ b/pages/content-ui/src/App.tsx @@ -0,0 +1,23 @@ +import { useEffect } from 'react'; +import { Button } from '@extension/ui'; +import { useStorage } from '@extension/shared'; +import { exampleThemeStorage } from '@extension/storage'; + +export default function App() { + const theme = useStorage(exampleThemeStorage); + + useEffect(() => { + console.log('content ui loaded'); + }, []); + + return ( +
+
+ Edit pages/content-ui/src/app.tsx and save to reload. +
+ +
+ ); +} diff --git a/pages/content-ui/src/index.tsx b/pages/content-ui/src/index.tsx new file mode 100644 index 0000000..ad1aada --- /dev/null +++ b/pages/content-ui/src/index.tsx @@ -0,0 +1,33 @@ +import { createRoot } from 'react-dom/client'; +import App from '@src/App'; +import tailwindcssOutput from '../dist/tailwind-output.css?inline'; + +const root = document.createElement('div'); +root.id = 'chrome-extension-boilerplate-react-vite-content-view-root'; + +document.body.append(root); + +const rootIntoShadow = document.createElement('div'); +rootIntoShadow.id = 'shadow-root'; + +const shadowRoot = root.attachShadow({ mode: 'open' }); + +if (navigator.userAgent.includes('Firefox')) { + /** + * In the firefox environment, adoptedStyleSheets cannot be used due to the bug + * @url https://bugzilla.mozilla.org/show_bug.cgi?id=1770592 + * + * Injecting styles into the document, this may cause style conflicts with the host page + */ + const styleElement = document.createElement('style'); + styleElement.innerHTML = tailwindcssOutput; + shadowRoot.appendChild(styleElement); +} else { + /** Inject styles into shadow dom */ + const globalStyleSheet = new CSSStyleSheet(); + globalStyleSheet.replaceSync(tailwindcssOutput); + shadowRoot.adoptedStyleSheets = [globalStyleSheet]; +} + +shadowRoot.appendChild(rootIntoShadow); +createRoot(rootIntoShadow).render(); diff --git a/pages/content-ui/src/tailwind-input.css b/pages/content-ui/src/tailwind-input.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/pages/content-ui/src/tailwind-input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/pages/content-ui/tailwind.config.ts b/pages/content-ui/tailwind.config.ts new file mode 100644 index 0000000..7be8fa8 --- /dev/null +++ b/pages/content-ui/tailwind.config.ts @@ -0,0 +1,7 @@ +import baseConfig from '@extension/tailwindcss-config'; +import { withUI } from '@extension/ui'; + +export default withUI({ + ...baseConfig, + content: ['src/**/*.{ts,tsx}'], +}); diff --git a/pages/content-ui/tsconfig.json b/pages/content-ui/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/content-ui/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/content-ui/vite.config.mts b/pages/content-ui/vite.config.mts new file mode 100644 index 0000000..2157014 --- /dev/null +++ b/pages/content-ui/vite.config.mts @@ -0,0 +1,25 @@ +import { resolve } from 'node:path'; +import { makeEntryPointPlugin } from '@extension/hmr'; +import { isDev, withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + plugins: [isDev && makeEntryPointPlugin()], + publicDir: resolve(rootDir, 'public'), + build: { + lib: { + entry: resolve(srcDir, 'index.tsx'), + name: 'contentUI', + formats: ['iife'], + fileName: 'index', + }, + outDir: resolve(rootDir, '..', '..', 'dist', 'content-ui'), + }, +}); diff --git a/pages/content/package.json b/pages/content/package.json new file mode 100644 index 0000000..a3c9e33 --- /dev/null +++ b/pages/content/package.json @@ -0,0 +1,31 @@ +{ + "name": "@extension/content-script", + "version": "0.3.5", + "description": "chrome extension - content script", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*" + }, + "devDependencies": { + "@extension/hmr": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "cross-env": "^7.0.3" + } +} diff --git a/pages/content/public/logo.svg b/pages/content/public/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/pages/content/public/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pages/content/src/index.ts b/pages/content/src/index.ts new file mode 100644 index 0000000..50a3921 --- /dev/null +++ b/pages/content/src/index.ts @@ -0,0 +1,5 @@ +import { toggleTheme } from '@src/toggleTheme'; + +console.log('content script loaded'); + +void toggleTheme(); diff --git a/pages/content/src/toggleTheme.ts b/pages/content/src/toggleTheme.ts new file mode 100644 index 0000000..6b27bc5 --- /dev/null +++ b/pages/content/src/toggleTheme.ts @@ -0,0 +1,7 @@ +import { exampleThemeStorage } from '@extension/storage'; + +export async function toggleTheme() { + console.log('initial theme:', await exampleThemeStorage.get()); + await exampleThemeStorage.toggle(); + console.log('toggled theme:', await exampleThemeStorage.get()); +} diff --git a/pages/content/tsconfig.json b/pages/content/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/content/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/content/vite.config.mts b/pages/content/vite.config.mts new file mode 100644 index 0000000..3679a89 --- /dev/null +++ b/pages/content/vite.config.mts @@ -0,0 +1,25 @@ +import { resolve } from 'node:path'; +import { makeEntryPointPlugin } from '@extension/hmr'; +import { isDev, withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + plugins: [isDev && makeEntryPointPlugin()], + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + formats: ['iife'], + name: 'ContentScript', + fileName: 'index', + }, + outDir: resolve(rootDir, '..', '..', 'dist', 'content'), + }, +}); diff --git a/pages/devtools-panel/index.html b/pages/devtools-panel/index.html new file mode 100644 index 0000000..8402fc1 --- /dev/null +++ b/pages/devtools-panel/index.html @@ -0,0 +1,12 @@ + + + + + Devtools Panel + + + +
+ + + diff --git a/pages/devtools-panel/package.json b/pages/devtools-panel/package.json new file mode 100644 index 0000000..15828b6 --- /dev/null +++ b/pages/devtools-panel/package.json @@ -0,0 +1,38 @@ +{ + "name": "@extension/devtools-panel", + "version": "0.3.5", + "description": "chrome extension - devtools panel", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*" + }, + "devDependencies": { + "@extension/tailwindcss-config": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "postcss-load-config": "^6.0.1", + "cross-env": "^7.0.3" + }, + "postcss": { + "plugins": { + "tailwindcss": {}, + "autoprefixer": {} + } + } +} diff --git a/pages/devtools-panel/public/logo_horizontal.svg b/pages/devtools-panel/public/logo_horizontal.svg new file mode 100644 index 0000000..232e97b --- /dev/null +++ b/pages/devtools-panel/public/logo_horizontal.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/devtools-panel/public/logo_horizontal_dark.svg b/pages/devtools-panel/public/logo_horizontal_dark.svg new file mode 100644 index 0000000..cf19a3e --- /dev/null +++ b/pages/devtools-panel/public/logo_horizontal_dark.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/devtools-panel/src/Panel.css b/pages/devtools-panel/src/Panel.css new file mode 100644 index 0000000..7354dea --- /dev/null +++ b/pages/devtools-panel/src/Panel.css @@ -0,0 +1,28 @@ +.App { + text-align: center; + height: 100vh; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; +} + +.App-logo { + height: 40vmin; +} + +.App-header { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); +} + +code { + background: rgba(148, 163, 184, 0.5); + border-radius: 0.25rem; + padding: 0.2rem 0.5rem; +} diff --git a/pages/devtools-panel/src/Panel.tsx b/pages/devtools-panel/src/Panel.tsx new file mode 100644 index 0000000..f9e71ae --- /dev/null +++ b/pages/devtools-panel/src/Panel.tsx @@ -0,0 +1,44 @@ +import '@src/Panel.css'; +import { useStorage, withErrorBoundary, withSuspense } from '@extension/shared'; +import { exampleThemeStorage } from '@extension/storage'; +import type { ComponentPropsWithoutRef } from 'react'; + +const Panel = () => { + const theme = useStorage(exampleThemeStorage); + const isLight = theme === 'light'; + const logo = isLight ? 'devtools-panel/logo_horizontal.svg' : 'devtools-panel/logo_horizontal_dark.svg'; + const goGithubSite = () => + chrome.tabs.create({ url: 'https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite' }); + + return ( +
+
+ +

+ Edit pages/devtools-panel/src/Panel.tsx +

+ Toggle theme +
+
+ ); +}; + +const ToggleButton = (props: ComponentPropsWithoutRef<'button'>) => { + const theme = useStorage(exampleThemeStorage); + return ( + + ); +}; + +export default withErrorBoundary(withSuspense(Panel,
Loading ...
),
Error Occur
); diff --git a/pages/devtools-panel/src/index.css b/pages/devtools-panel/src/index.css new file mode 100644 index 0000000..392b3d2 --- /dev/null +++ b/pages/devtools-panel/src/index.css @@ -0,0 +1,17 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', + 'Droid Sans', 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + position: relative; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; +} diff --git a/pages/devtools-panel/src/index.tsx b/pages/devtools-panel/src/index.tsx new file mode 100644 index 0000000..065021d --- /dev/null +++ b/pages/devtools-panel/src/index.tsx @@ -0,0 +1,15 @@ +import { createRoot } from 'react-dom/client'; +import '@src/index.css'; +import Panel from '@src/Panel'; + +function init() { + const appContainer = document.querySelector('#app-container'); + if (!appContainer) { + throw new Error('Can not find #app-container'); + } + const root = createRoot(appContainer); + + root.render(); +} + +init(); diff --git a/pages/devtools-panel/tailwind.config.ts b/pages/devtools-panel/tailwind.config.ts new file mode 100644 index 0000000..3428bbb --- /dev/null +++ b/pages/devtools-panel/tailwind.config.ts @@ -0,0 +1,7 @@ +import baseConfig from '@extension/tailwindcss-config'; +import type { Config } from 'tailwindcss/types/config'; + +export default { + ...baseConfig, + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], +} as Config; diff --git a/pages/devtools-panel/tsconfig.json b/pages/devtools-panel/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/devtools-panel/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/devtools-panel/vite.config.mts b/pages/devtools-panel/vite.config.mts new file mode 100644 index 0000000..b5cccae --- /dev/null +++ b/pages/devtools-panel/vite.config.mts @@ -0,0 +1,17 @@ +import { resolve } from 'node:path'; +import { withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + outDir: resolve(rootDir, '..', '..', 'dist', 'devtools-panel'), + }, +}); diff --git a/pages/devtools/index.html b/pages/devtools/index.html new file mode 100644 index 0000000..80ebcea --- /dev/null +++ b/pages/devtools/index.html @@ -0,0 +1,11 @@ + + + + + Devtools + + + + + + diff --git a/pages/devtools/package.json b/pages/devtools/package.json new file mode 100644 index 0000000..e30d6ff --- /dev/null +++ b/pages/devtools/package.json @@ -0,0 +1,29 @@ +{ + "name": "@extension/devtools", + "version": "0.3.5", + "description": "chrome extension - devtools", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "cross-env": "^7.0.3" + } +} diff --git a/pages/devtools/public/logo.svg b/pages/devtools/public/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/pages/devtools/public/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pages/devtools/src/index.ts b/pages/devtools/src/index.ts new file mode 100644 index 0000000..41fd50c --- /dev/null +++ b/pages/devtools/src/index.ts @@ -0,0 +1,6 @@ +try { + console.log("Edit 'pages/devtools/src/index.ts' and save to reload."); + chrome.devtools.panels.create('Dev Tools', '/icon-34.png', '/devtools-panel/index.html'); +} catch (e) { + console.error(e); +} diff --git a/pages/devtools/tsconfig.json b/pages/devtools/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/devtools/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/devtools/vite.config.mts b/pages/devtools/vite.config.mts new file mode 100644 index 0000000..6aa03bf --- /dev/null +++ b/pages/devtools/vite.config.mts @@ -0,0 +1,17 @@ +import { resolve } from 'node:path'; +import { withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + outDir: resolve(rootDir, '..', '..', 'dist', 'devtools'), + }, +}); diff --git a/pages/new-tab/index.html b/pages/new-tab/index.html new file mode 100644 index 0000000..121ef98 --- /dev/null +++ b/pages/new-tab/index.html @@ -0,0 +1,12 @@ + + + + + New Tab + + + +
+ + + diff --git a/pages/new-tab/package.json b/pages/new-tab/package.json new file mode 100644 index 0000000..8757b80 --- /dev/null +++ b/pages/new-tab/package.json @@ -0,0 +1,41 @@ +{ + "name": "@extension/new-tab", + "version": "0.3.5", + "description": "chrome extension - new tab", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*", + "@extension/ui": "workspace:*", + "@extension/i18n": "workspace:*" + }, + "devDependencies": { + "@extension/tailwindcss-config": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "sass": "1.79.4", + "postcss-load-config": "^6.0.1", + "cross-env": "^7.0.3" + }, + "postcss": { + "plugins": { + "tailwindcss": {}, + "autoprefixer": {} + } + } +} diff --git a/pages/new-tab/public/logo_horizontal.svg b/pages/new-tab/public/logo_horizontal.svg new file mode 100644 index 0000000..232e97b --- /dev/null +++ b/pages/new-tab/public/logo_horizontal.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/new-tab/public/logo_horizontal_dark.svg b/pages/new-tab/public/logo_horizontal_dark.svg new file mode 100644 index 0000000..cf19a3e --- /dev/null +++ b/pages/new-tab/public/logo_horizontal_dark.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/new-tab/src/NewTab.css b/pages/new-tab/src/NewTab.css new file mode 100644 index 0000000..26c291a --- /dev/null +++ b/pages/new-tab/src/NewTab.css @@ -0,0 +1,22 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; +} + +.App-header { + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); +} + +code { + background: rgba(148, 163, 184, 0.5); + border-radius: 0.25rem; + padding: 0.2rem 0.5rem; +} diff --git a/pages/new-tab/src/NewTab.scss b/pages/new-tab/src/NewTab.scss new file mode 100644 index 0000000..8960c7b --- /dev/null +++ b/pages/new-tab/src/NewTab.scss @@ -0,0 +1,10 @@ +$myColor: red; + +h1, +h2, +h3, +h4, +h5, +h6 { + color: $myColor; +} diff --git a/pages/new-tab/src/NewTab.tsx b/pages/new-tab/src/NewTab.tsx new file mode 100644 index 0000000..4f185af --- /dev/null +++ b/pages/new-tab/src/NewTab.tsx @@ -0,0 +1,34 @@ +import '@src/NewTab.css'; +import '@src/NewTab.scss'; +import { useStorage, withErrorBoundary, withSuspense } from '@extension/shared'; +import { exampleThemeStorage } from '@extension/storage'; +import { Button } from '@extension/ui'; +import { t } from '@extension/i18n'; + +const NewTab = () => { + const theme = useStorage(exampleThemeStorage); + const isLight = theme === 'light'; + const logo = isLight ? 'new-tab/logo_horizontal.svg' : 'new-tab/logo_horizontal_dark.svg'; + const goGithubSite = () => + chrome.tabs.create({ url: 'https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite' }); + + console.log(t('hello', 'World')); + return ( +
+
+ +

+ Edit pages/new-tab/src/NewTab.tsx +

+
The color of this paragraph is defined using SASS.
+ +
+
+ ); +}; + +export default withErrorBoundary(withSuspense(NewTab,
{t('loading')}
),
Error Occur
); diff --git a/pages/new-tab/src/index.css b/pages/new-tab/src/index.css new file mode 100644 index 0000000..5138222 --- /dev/null +++ b/pages/new-tab/src/index.css @@ -0,0 +1,15 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', + 'Droid Sans', 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; +} diff --git a/pages/new-tab/src/index.tsx b/pages/new-tab/src/index.tsx new file mode 100644 index 0000000..1262fd0 --- /dev/null +++ b/pages/new-tab/src/index.tsx @@ -0,0 +1,16 @@ +import { createRoot } from 'react-dom/client'; +import '@src/index.css'; +import '@extension/ui/lib/global.css'; +import NewTab from '@src/NewTab'; + +function init() { + const appContainer = document.querySelector('#app-container'); + if (!appContainer) { + throw new Error('Can not find #app-container'); + } + const root = createRoot(appContainer); + + root.render(); +} + +init(); diff --git a/pages/new-tab/tailwind.config.ts b/pages/new-tab/tailwind.config.ts new file mode 100644 index 0000000..ef87645 --- /dev/null +++ b/pages/new-tab/tailwind.config.ts @@ -0,0 +1,7 @@ +import baseConfig from '@extension/tailwindcss-config'; +import { withUI } from '@extension/ui'; + +export default withUI({ + ...baseConfig, + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], +}); diff --git a/pages/new-tab/tsconfig.json b/pages/new-tab/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/new-tab/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/new-tab/vite.config.mts b/pages/new-tab/vite.config.mts new file mode 100644 index 0000000..600a4f7 --- /dev/null +++ b/pages/new-tab/vite.config.mts @@ -0,0 +1,17 @@ +import { resolve } from 'node:path'; +import { withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + outDir: resolve(rootDir, '..', '..', 'dist', 'new-tab'), + }, +}); diff --git a/pages/options/index.html b/pages/options/index.html new file mode 100644 index 0000000..65e1fdd --- /dev/null +++ b/pages/options/index.html @@ -0,0 +1,12 @@ + + + + + Options + + + +
+ + + diff --git a/pages/options/package.json b/pages/options/package.json new file mode 100644 index 0000000..707a1ae --- /dev/null +++ b/pages/options/package.json @@ -0,0 +1,39 @@ +{ + "name": "@extension/options", + "version": "0.3.5", + "description": "chrome extension - options", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*", + "@extension/ui": "workspace:*" + }, + "devDependencies": { + "@extension/tailwindcss-config": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "postcss-load-config": "^6.0.1", + "cross-env": "^7.0.3" + }, + "postcss": { + "plugins": { + "tailwindcss": {}, + "autoprefixer": {} + } + } +} diff --git a/pages/options/public/logo_horizontal.svg b/pages/options/public/logo_horizontal.svg new file mode 100644 index 0000000..232e97b --- /dev/null +++ b/pages/options/public/logo_horizontal.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/options/public/logo_horizontal_dark.svg b/pages/options/public/logo_horizontal_dark.svg new file mode 100644 index 0000000..cf19a3e --- /dev/null +++ b/pages/options/public/logo_horizontal_dark.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/options/src/Options.css b/pages/options/src/Options.css new file mode 100644 index 0000000..6e36d2a --- /dev/null +++ b/pages/options/src/Options.css @@ -0,0 +1,26 @@ +#app-container { + text-align: center; + width: 100vw; + height: 100vh; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +.App { + width: 100vw; + height: 100vh; + font-size: calc(10px + 2vmin); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +code { + background: rgba(148, 163, 184, 0.5); + border-radius: 0.25rem; + padding: 0.2rem 0.5rem; +} diff --git a/pages/options/src/Options.tsx b/pages/options/src/Options.tsx new file mode 100644 index 0000000..4921001 --- /dev/null +++ b/pages/options/src/Options.tsx @@ -0,0 +1,28 @@ +import '@src/Options.css'; +import { useStorage, withErrorBoundary, withSuspense } from '@extension/shared'; +import { exampleThemeStorage } from '@extension/storage'; +import { Button } from '@extension/ui'; + +const Options = () => { + const theme = useStorage(exampleThemeStorage); + const isLight = theme === 'light'; + const logo = isLight ? 'options/logo_horizontal.svg' : 'options/logo_horizontal_dark.svg'; + const goGithubSite = () => + chrome.tabs.create({ url: 'https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite' }); + + return ( +
+ +

+ Edit pages/options/src/Options.tsx +

+ +
+ ); +}; + +export default withErrorBoundary(withSuspense(Options,
Loading ...
),
Error Occur
); diff --git a/pages/options/src/index.css b/pages/options/src/index.css new file mode 100644 index 0000000..1187072 --- /dev/null +++ b/pages/options/src/index.css @@ -0,0 +1,11 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', + 'Droid Sans', 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/pages/options/src/index.tsx b/pages/options/src/index.tsx new file mode 100644 index 0000000..e06e489 --- /dev/null +++ b/pages/options/src/index.tsx @@ -0,0 +1,15 @@ +import { createRoot } from 'react-dom/client'; +import '@src/index.css'; +import '@extension/ui/dist/global.css'; +import Options from '@src/Options'; + +function init() { + const appContainer = document.querySelector('#app-container'); + if (!appContainer) { + throw new Error('Can not find #app-container'); + } + const root = createRoot(appContainer); + root.render(); +} + +init(); diff --git a/pages/options/tailwind.config.ts b/pages/options/tailwind.config.ts new file mode 100644 index 0000000..ef87645 --- /dev/null +++ b/pages/options/tailwind.config.ts @@ -0,0 +1,7 @@ +import baseConfig from '@extension/tailwindcss-config'; +import { withUI } from '@extension/ui'; + +export default withUI({ + ...baseConfig, + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], +}); diff --git a/pages/options/tsconfig.json b/pages/options/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/options/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/options/vite.config.mts b/pages/options/vite.config.mts new file mode 100644 index 0000000..ab85dc1 --- /dev/null +++ b/pages/options/vite.config.mts @@ -0,0 +1,17 @@ +import { resolve } from 'node:path'; +import { withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + outDir: resolve(rootDir, '..', '..', 'dist', 'options'), + }, +}); diff --git a/pages/popup/index.html b/pages/popup/index.html new file mode 100644 index 0000000..f75fabf --- /dev/null +++ b/pages/popup/index.html @@ -0,0 +1,12 @@ + + + + + Popup + + + +
+ + + diff --git a/pages/popup/package.json b/pages/popup/package.json new file mode 100644 index 0000000..a97e379 --- /dev/null +++ b/pages/popup/package.json @@ -0,0 +1,39 @@ +{ + "name": "@extension/popup", + "version": "0.3.5", + "description": "chrome extension - popup", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*", + "@extension/content-runtime-script": "workspace:*" + }, + "devDependencies": { + "@extension/tailwindcss-config": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "postcss-load-config": "^6.0.1", + "cross-env": "^7.0.3" + }, + "postcss": { + "plugins": { + "tailwindcss": {}, + "autoprefixer": {} + } + } +} diff --git a/pages/popup/public/logo_vertical.svg b/pages/popup/public/logo_vertical.svg new file mode 100644 index 0000000..5768b87 --- /dev/null +++ b/pages/popup/public/logo_vertical.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/popup/public/logo_vertical_dark.svg b/pages/popup/public/logo_vertical_dark.svg new file mode 100644 index 0000000..b4089d8 --- /dev/null +++ b/pages/popup/public/logo_vertical_dark.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/popup/src/Popup.css b/pages/popup/src/Popup.css new file mode 100644 index 0000000..e29c75f --- /dev/null +++ b/pages/popup/src/Popup.css @@ -0,0 +1,30 @@ +.App { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + text-align: center; + height: 100%; + padding: 1rem; +} + +.App-logo { + height: 50vmin; + margin-bottom: 1rem; +} + +.App-header { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + font-size: 0.75rem; +} + +code { + background: rgba(148, 163, 184, 0.5); + border-radius: 0.25rem; + padding: 0.2rem 0.5rem; +} diff --git a/pages/popup/src/Popup.tsx b/pages/popup/src/Popup.tsx new file mode 100644 index 0000000..e7235b0 --- /dev/null +++ b/pages/popup/src/Popup.tsx @@ -0,0 +1,79 @@ +import '@src/Popup.css'; +import { useStorage, withErrorBoundary, withSuspense } from '@extension/shared'; +import { exampleThemeStorage } from '@extension/storage'; +import type { ComponentPropsWithoutRef } from 'react'; + +const notificationOptions = { + type: 'basic', + iconUrl: chrome.runtime.getURL('icon-34.png'), + title: 'Injecting content script error', + message: 'You cannot inject script here!', +} as const; + +const Popup = () => { + const theme = useStorage(exampleThemeStorage); + const isLight = theme === 'light'; + const logo = isLight ? 'popup/logo_vertical.svg' : 'popup/logo_vertical_dark.svg'; + const goGithubSite = () => + chrome.tabs.create({ url: 'https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite' }); + + const injectContentScript = async () => { + const [tab] = await chrome.tabs.query({ currentWindow: true, active: true }); + + if (tab.url!.startsWith('about:') || tab.url!.startsWith('chrome:')) { + chrome.notifications.create('inject-error', notificationOptions); + } + + await chrome.scripting + .executeScript({ + target: { tabId: tab.id! }, + files: ['/content-runtime/index.iife.js'], + }) + .catch(err => { + // Handling errors related to other paths + if (err.message.includes('Cannot access a chrome:// URL')) { + chrome.notifications.create('inject-error', notificationOptions); + } + }); + }; + + return ( +
+
+ +

+ Edit pages/popup/src/Popup.tsx +

+ + Toggle theme +
+
+ ); +}; + +const ToggleButton = (props: ComponentPropsWithoutRef<'button'>) => { + const theme = useStorage(exampleThemeStorage); + return ( + + ); +}; + +export default withErrorBoundary(withSuspense(Popup,
Loading ...
),
Error Occur
); diff --git a/pages/popup/src/index.css b/pages/popup/src/index.css new file mode 100644 index 0000000..11e8d16 --- /dev/null +++ b/pages/popup/src/index.css @@ -0,0 +1,19 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + width: 300px; + height: 260px; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', + 'Droid Sans', 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + position: relative; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; +} diff --git a/pages/popup/src/index.tsx b/pages/popup/src/index.tsx new file mode 100644 index 0000000..7859d2b --- /dev/null +++ b/pages/popup/src/index.tsx @@ -0,0 +1,15 @@ +import { createRoot } from 'react-dom/client'; +import '@src/index.css'; +import Popup from '@src/Popup'; + +function init() { + const appContainer = document.querySelector('#app-container'); + if (!appContainer) { + throw new Error('Can not find #app-container'); + } + const root = createRoot(appContainer); + + root.render(); +} + +init(); diff --git a/pages/popup/tailwind.config.ts b/pages/popup/tailwind.config.ts new file mode 100644 index 0000000..3428bbb --- /dev/null +++ b/pages/popup/tailwind.config.ts @@ -0,0 +1,7 @@ +import baseConfig from '@extension/tailwindcss-config'; +import type { Config } from 'tailwindcss/types/config'; + +export default { + ...baseConfig, + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], +} as Config; diff --git a/pages/popup/tsconfig.json b/pages/popup/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/popup/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/popup/vite.config.mts b/pages/popup/vite.config.mts new file mode 100644 index 0000000..74de3ee --- /dev/null +++ b/pages/popup/vite.config.mts @@ -0,0 +1,17 @@ +import { resolve } from 'node:path'; +import { withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + outDir: resolve(rootDir, '..', '..', 'dist', 'popup'), + }, +}); diff --git a/pages/side-panel/index.html b/pages/side-panel/index.html new file mode 100644 index 0000000..27859dc --- /dev/null +++ b/pages/side-panel/index.html @@ -0,0 +1,12 @@ + + + + + Side Panel + + + +
+ + + diff --git a/pages/side-panel/package.json b/pages/side-panel/package.json new file mode 100644 index 0000000..4d816dd --- /dev/null +++ b/pages/side-panel/package.json @@ -0,0 +1,38 @@ +{ + "name": "@extension/sidepanel", + "version": "0.3.5", + "description": "chrome extension - side panel", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules", + "build": "vite build", + "dev": "cross-env __DEV__=true vite build --mode development", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@extension/shared": "workspace:*", + "@extension/storage": "workspace:*" + }, + "devDependencies": { + "@extension/tailwindcss-config": "workspace:*", + "@extension/tsconfig": "workspace:*", + "@extension/vite-config": "workspace:*", + "postcss-load-config": "^6.0.1", + "cross-env": "^7.0.3" + }, + "postcss": { + "plugins": { + "tailwindcss": {}, + "autoprefixer": {} + } + } +} diff --git a/pages/side-panel/public/logo_vertical.svg b/pages/side-panel/public/logo_vertical.svg new file mode 100644 index 0000000..5768b87 --- /dev/null +++ b/pages/side-panel/public/logo_vertical.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/side-panel/public/logo_vertical_dark.svg b/pages/side-panel/public/logo_vertical_dark.svg new file mode 100644 index 0000000..b4089d8 --- /dev/null +++ b/pages/side-panel/public/logo_vertical_dark.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/side-panel/src/SidePanel.css b/pages/side-panel/src/SidePanel.css new file mode 100644 index 0000000..55fb324 --- /dev/null +++ b/pages/side-panel/src/SidePanel.css @@ -0,0 +1,30 @@ +.App { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + text-align: center; + height: 100%; + padding: 1rem; +} + +.App-logo { + height: 50vmin; + margin-bottom: 1rem; +} + +.App-header { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); +} + +code { + background: rgba(148, 163, 184, 0.5); + border-radius: 0.25rem; + padding: 0.2rem 0.5rem; +} diff --git a/pages/side-panel/src/SidePanel.tsx b/pages/side-panel/src/SidePanel.tsx new file mode 100644 index 0000000..a240bc7 --- /dev/null +++ b/pages/side-panel/src/SidePanel.tsx @@ -0,0 +1,44 @@ +import '@src/SidePanel.css'; +import { useStorage, withErrorBoundary, withSuspense } from '@extension/shared'; +import { exampleThemeStorage } from '@extension/storage'; +import type { ComponentPropsWithoutRef } from 'react'; + +const SidePanel = () => { + const theme = useStorage(exampleThemeStorage); + const isLight = theme === 'light'; + const logo = isLight ? 'side-panel/logo_vertical.svg' : 'side-panel/logo_vertical_dark.svg'; + const goGithubSite = () => + chrome.tabs.create({ url: 'https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite' }); + + return ( +
+
+ +

+ Edit pages/side-panel/src/SidePanel.tsx +

+ Toggle theme +
+
+ ); +}; + +const ToggleButton = (props: ComponentPropsWithoutRef<'button'>) => { + const theme = useStorage(exampleThemeStorage); + return ( + + ); +}; + +export default withErrorBoundary(withSuspense(SidePanel,
Loading ...
),
Error Occur
); diff --git a/pages/side-panel/src/index.css b/pages/side-panel/src/index.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/pages/side-panel/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/pages/side-panel/src/index.tsx b/pages/side-panel/src/index.tsx new file mode 100644 index 0000000..992622d --- /dev/null +++ b/pages/side-panel/src/index.tsx @@ -0,0 +1,14 @@ +import { createRoot } from 'react-dom/client'; +import '@src/index.css'; +import SidePanel from '@src/SidePanel'; + +function init() { + const appContainer = document.querySelector('#app-container'); + if (!appContainer) { + throw new Error('Can not find #app-container'); + } + const root = createRoot(appContainer); + root.render(); +} + +init(); diff --git a/pages/side-panel/tailwind.config.ts b/pages/side-panel/tailwind.config.ts new file mode 100644 index 0000000..3428bbb --- /dev/null +++ b/pages/side-panel/tailwind.config.ts @@ -0,0 +1,7 @@ +import baseConfig from '@extension/tailwindcss-config'; +import type { Config } from 'tailwindcss/types/config'; + +export default { + ...baseConfig, + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], +} as Config; diff --git a/pages/side-panel/tsconfig.json b/pages/side-panel/tsconfig.json new file mode 100644 index 0000000..0837c72 --- /dev/null +++ b/pages/side-panel/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@extension/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"] + }, + "types": ["chrome", "../../vite-env.d.ts"] + }, + "include": ["src"] +} diff --git a/pages/side-panel/vite.config.mts b/pages/side-panel/vite.config.mts new file mode 100644 index 0000000..707bd2b --- /dev/null +++ b/pages/side-panel/vite.config.mts @@ -0,0 +1,17 @@ +import { resolve } from 'node:path'; +import { withPageConfig } from '@extension/vite-config'; + +const rootDir = resolve(__dirname); +const srcDir = resolve(rootDir, 'src'); + +export default withPageConfig({ + resolve: { + alias: { + '@src': srcDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + outDir: resolve(rootDir, '..', '..', 'dist', 'side-panel'), + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..684c025 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,8689 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + eslint-plugin-tailwindcss: + specifier: ^3.17.4 + version: 3.17.4(tailwindcss@3.4.14(ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4))) + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) + devDependencies: + '@types/chrome': + specifier: ^0.0.270 + version: 0.0.270 + '@types/node': + specifier: ^22.5.5 + version: 22.7.4 + '@types/react': + specifier: ^18.3.3 + version: 18.3.5 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 + '@typescript-eslint/eslint-plugin': + specifier: ^7.18.0 + version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/parser': + specifier: ^7.18.0 + version: 7.18.0(eslint@8.57.0)(typescript@5.5.4) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.4.47) + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + esbuild: + specifier: ^0.23.0 + version: 0.23.1 + eslint: + specifier: 8.57.0 + version: 8.57.0 + eslint-config-airbnb-typescript: + specifier: 18.0.0 + version: 18.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-prettier: + specifier: 9.1.0 + version: 9.1.0(eslint@8.57.0) + eslint-plugin-import: + specifier: 2.29.1 + version: 2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0) + eslint-plugin-jsx-a11y: + specifier: 6.9.0 + version: 6.9.0(eslint@8.57.0) + eslint-plugin-prettier: + specifier: 5.2.1 + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.3) + eslint-plugin-react: + specifier: 7.35.0 + version: 7.35.0(eslint@8.57.0) + eslint-plugin-react-hooks: + specifier: 4.6.2 + version: 4.6.2(eslint@8.57.0) + husky: + specifier: ^9.1.4 + version: 9.1.5 + lint-staged: + specifier: ^15.2.7 + version: 15.2.10 + postcss: + specifier: ^8.4.47 + version: 8.4.47 + prettier: + specifier: ^3.3.3 + version: 3.3.3 + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + run-script-os: + specifier: ^1.1.6 + version: 1.1.6 + tailwindcss: + specifier: ^3.4.14 + version: 3.4.14(ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4)) + tslib: + specifier: ^2.6.3 + version: 2.7.0 + turbo: + specifier: ^2.3.3 + version: 2.3.3 + typescript: + specifier: 5.5.4 + version: 5.5.4 + vite: + specifier: 6.0.5 + version: 6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1) + + chrome-extension: + dependencies: + '@extension/shared': + specifier: workspace:* + version: link:../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../packages/storage + webextension-polyfill: + specifier: ^0.12.0 + version: 0.12.0 + devDependencies: + '@extension/dev-utils': + specifier: workspace:* + version: link:../packages/dev-utils + '@extension/hmr': + specifier: workspace:* + version: link:../packages/hmr + '@extension/tsconfig': + specifier: workspace:* + version: link:../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../packages/vite-config + '@laynezh/vite-plugin-lib-assets': + specifier: ^0.6.1 + version: 0.6.1(vite@6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1)) + '@types/ws': + specifier: ^8.5.13 + version: 8.5.13 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + deepmerge: + specifier: ^4.3.1 + version: 4.3.1 + magic-string: + specifier: ^0.30.10 + version: 0.30.11 + ts-loader: + specifier: ^9.5.1 + version: 9.5.1(typescript@5.5.4)(webpack@5.94.0(@swc/core@1.9.3)(esbuild@0.23.1)) + + packages/dev-utils: + devDependencies: + '@extension/shared': + specifier: workspace:* + version: link:../shared + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + + packages/hmr: + devDependencies: + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + '@rollup/plugin-sucrase': + specifier: ^5.0.2 + version: 5.0.2(rollup@4.24.0) + '@types/ws': + specifier: ^8.5.13 + version: 8.5.13 + esm: + specifier: ^3.2.25 + version: 3.2.25 + fast-glob: + specifier: ^3.3.2 + version: 3.3.2 + rollup: + specifier: ^4.24.0 + version: 4.24.0 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4) + ws: + specifier: 8.18.0 + version: 8.18.0 + + packages/i18n: + devDependencies: + '@extension/hmr': + specifier: workspace:* + version: link:../hmr + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + + packages/shared: + devDependencies: + '@extension/storage': + specifier: workspace:* + version: link:../storage + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + + packages/storage: + devDependencies: + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + + packages/tailwind-config: {} + + packages/tsconfig: {} + + packages/ui: + dependencies: + clsx: + specifier: ^2.1.1 + version: 2.1.1 + tailwind-merge: + specifier: ^2.4.0 + version: 2.5.2 + devDependencies: + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + deepmerge: + specifier: ^4.3.1 + version: 4.3.1 + tsc-alias: + specifier: ^1.8.10 + version: 1.8.10 + + packages/vite-config: + devDependencies: + '@extension/hmr': + specifier: workspace:* + version: link:../hmr + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + '@vitejs/plugin-react-swc': + specifier: ^3.7.2 + version: 3.7.2(vite@6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1)) + deepmerge: + specifier: ^4.3.1 + version: 4.3.1 + + packages/zipper: + devDependencies: + '@extension/tsconfig': + specifier: workspace:* + version: link:../tsconfig + fast-glob: + specifier: ^3.3.2 + version: 3.3.2 + fflate: + specifier: ^0.8.2 + version: 0.8.2 + tsx: + specifier: ^4.19.2 + version: 4.19.2 + + pages/content: + dependencies: + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../../packages/storage + devDependencies: + '@extension/hmr': + specifier: workspace:* + version: link:../../packages/hmr + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + + pages/content-runtime: + devDependencies: + '@extension/hmr': + specifier: workspace:* + version: link:../../packages/hmr + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + + pages/content-ui: + dependencies: + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../../packages/storage + '@extension/ui': + specifier: workspace:* + version: link:../../packages/ui + devDependencies: + '@extension/hmr': + specifier: workspace:* + version: link:../../packages/hmr + '@extension/tailwindcss-config': + specifier: workspace:* + version: link:../../packages/tailwind-config + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + concurrently: + specifier: ^9.0.1 + version: 9.0.1 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + + pages/devtools: + dependencies: + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + devDependencies: + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + + pages/devtools-panel: + dependencies: + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../../packages/storage + devDependencies: + '@extension/tailwindcss-config': + specifier: workspace:* + version: link:../../packages/tailwind-config + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + postcss-load-config: + specifier: ^6.0.1 + version: 6.0.1(jiti@1.21.6)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.5.1) + + pages/new-tab: + dependencies: + '@extension/i18n': + specifier: workspace:* + version: link:../../packages/i18n + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../../packages/storage + '@extension/ui': + specifier: workspace:* + version: link:../../packages/ui + devDependencies: + '@extension/tailwindcss-config': + specifier: workspace:* + version: link:../../packages/tailwind-config + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + postcss-load-config: + specifier: ^6.0.1 + version: 6.0.1(jiti@1.21.6)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.5.1) + sass: + specifier: 1.79.4 + version: 1.79.4 + + pages/options: + dependencies: + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../../packages/storage + '@extension/ui': + specifier: workspace:* + version: link:../../packages/ui + devDependencies: + '@extension/tailwindcss-config': + specifier: workspace:* + version: link:../../packages/tailwind-config + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + postcss-load-config: + specifier: ^6.0.1 + version: 6.0.1(jiti@1.21.6)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.5.1) + + pages/popup: + dependencies: + '@extension/content-runtime-script': + specifier: workspace:* + version: link:../content-runtime + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../../packages/storage + devDependencies: + '@extension/tailwindcss-config': + specifier: workspace:* + version: link:../../packages/tailwind-config + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + postcss-load-config: + specifier: ^6.0.1 + version: 6.0.1(jiti@1.21.6)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.5.1) + + pages/side-panel: + dependencies: + '@extension/shared': + specifier: workspace:* + version: link:../../packages/shared + '@extension/storage': + specifier: workspace:* + version: link:../../packages/storage + devDependencies: + '@extension/tailwindcss-config': + specifier: workspace:* + version: link:../../packages/tailwind-config + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@extension/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + postcss-load-config: + specifier: ^6.0.1 + version: 6.0.1(jiti@1.21.6)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.5.1) + + tests/e2e: + devDependencies: + '@extension/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@wdio/cli': + specifier: ^9.4.5 + version: 9.4.5 + '@wdio/globals': + specifier: ^9.4.5 + version: 9.4.5(@wdio/logger@9.1.0) + '@wdio/local-runner': + specifier: ^9.1.2 + version: 9.1.2 + '@wdio/mocha-framework': + specifier: ^9.1.2 + version: 9.1.2 + '@wdio/spec-reporter': + specifier: ^9.2.14 + version: 9.2.14 + '@wdio/types': + specifier: ^9.1.2 + version: 9.1.2 + tsx: + specifier: ^4.19.2 + version: 4.19.2 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.24.0': + resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.24.0': + resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.24.0': + resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.24.0': + resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.24.0': + resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.0': + resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.24.0': + resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.0': + resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.24.0': + resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.24.0': + resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.24.0': + resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.24.0': + resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.24.0': + resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.24.0': + resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.0': + resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.24.0': + resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.24.0': + resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.0': + resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.24.0': + resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.0': + resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.24.0': + resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.24.0': + resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.24.0': + resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.24.0': + resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@inquirer/checkbox@3.0.1': + resolution: {integrity: sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@4.0.1': + resolution: {integrity: sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w==} + engines: {node: '>=18'} + + '@inquirer/core@9.2.1': + resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==} + engines: {node: '>=18'} + + '@inquirer/editor@3.0.1': + resolution: {integrity: sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q==} + engines: {node: '>=18'} + + '@inquirer/expand@3.0.1': + resolution: {integrity: sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ==} + engines: {node: '>=18'} + + '@inquirer/figures@1.0.6': + resolution: {integrity: sha512-yfZzps3Cso2UbM7WlxKwZQh2Hs6plrbjs1QnzQDZhK2DgyCo6D8AaHps9olkNcUFlcYERMqU3uJSp1gmy3s/qQ==} + engines: {node: '>=18'} + + '@inquirer/input@3.0.1': + resolution: {integrity: sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg==} + engines: {node: '>=18'} + + '@inquirer/number@2.0.1': + resolution: {integrity: sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ==} + engines: {node: '>=18'} + + '@inquirer/password@3.0.1': + resolution: {integrity: sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ==} + engines: {node: '>=18'} + + '@inquirer/prompts@6.0.1': + resolution: {integrity: sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==} + engines: {node: '>=18'} + + '@inquirer/rawlist@3.0.1': + resolution: {integrity: sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ==} + engines: {node: '>=18'} + + '@inquirer/search@2.0.1': + resolution: {integrity: sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg==} + engines: {node: '>=18'} + + '@inquirer/select@3.0.1': + resolution: {integrity: sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q==} + engines: {node: '>=18'} + + '@inquirer/type@2.0.0': + resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==} + engines: {node: '>=18'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@laynezh/vite-plugin-lib-assets@0.6.1': + resolution: {integrity: sha512-pdIRW/PiJkuM7/OObjGBGfQmsWetmVObeez6uwT3nhP5cu2zT0L5QELq69caWD/v3QlPY3CPXVN0kZrzQzdvsQ==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@promptbook/utils@0.70.0-1': + resolution: {integrity: sha512-qd2lLRRN+sE6UuNMi2tEeUUeb4zmXnxY5EMdfHVXNE+bqBDpUC7/aEfXgA3jnUXEr+xFjQ8PTFQgWvBMaKvw0g==} + + '@puppeteer/browsers@2.4.0': + resolution: {integrity: sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==} + engines: {node: '>=18'} + hasBin: true + + '@rollup/plugin-sucrase@5.0.2': + resolution: {integrity: sha512-4MhIVH9Dy2Hwose1/x5QMs0XF7yn9jDd/yozHqzdIrMWIolgFpGnrnVhQkqTaK1RALY/fpyrEKmwH/04vr1THA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.53.1||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.1.0': + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.24.0': + resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.24.0': + resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.24.0': + resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.24.0': + resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.24.0': + resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.24.0': + resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.24.0': + resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.24.0': + resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.24.0': + resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.24.0': + resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.24.0': + resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.24.0': + resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.24.0': + resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.24.0': + resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} + cpu: [x64] + os: [win32] + + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@swc/core-darwin-arm64@1.9.3': + resolution: {integrity: sha512-hGfl/KTic/QY4tB9DkTbNuxy5cV4IeejpPD4zo+Lzt4iLlDWIeANL4Fkg67FiVceNJboqg48CUX+APhDHO5G1w==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.9.3': + resolution: {integrity: sha512-IaRq05ZLdtgF5h9CzlcgaNHyg4VXuiStnOFpfNEMuI5fm5afP2S0FHq8WdakUz5WppsbddTdplL+vpeApt/WCQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.9.3': + resolution: {integrity: sha512-Pbwe7xYprj/nEnZrNBvZfjnTxlBIcfApAGdz2EROhjpPj+FBqBa3wOogqbsuGGBdCphf8S+KPprL1z+oDWkmSQ==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.9.3': + resolution: {integrity: sha512-AQ5JZiwNGVV/2K2TVulg0mw/3LYfqpjZO6jDPtR2evNbk9Yt57YsVzS+3vHSlUBQDRV9/jqMuZYVU3P13xrk+g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.9.3': + resolution: {integrity: sha512-tzVH480RY6RbMl/QRgh5HK3zn1ZTFsThuxDGo6Iuk1MdwIbdFYUY034heWUTI4u3Db97ArKh0hNL0xhO3+PZdg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.9.3': + resolution: {integrity: sha512-ivXXBRDXDc9k4cdv10R21ccBmGebVOwKXT/UdH1PhxUn9m/h8erAWjz5pcELwjiMf27WokqPgaWVfaclDbgE+w==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.9.3': + resolution: {integrity: sha512-ILsGMgfnOz1HwdDz+ZgEuomIwkP1PHT6maigZxaCIuC6OPEhKE8uYna22uU63XvYcLQvZYDzpR3ms47WQPuNEg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.9.3': + resolution: {integrity: sha512-e+XmltDVIHieUnNJHtspn6B+PCcFOMYXNJB1GqoCcyinkEIQNwC8KtWgMqUucUbEWJkPc35NHy9k8aCXRmw9Kg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.9.3': + resolution: {integrity: sha512-rqpzNfpAooSL4UfQnHhkW8aL+oyjqJniDP0qwZfGnjDoJSbtPysHg2LpcOBEdSnEH+uIZq6J96qf0ZFD8AGfXA==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.9.3': + resolution: {integrity: sha512-3YJJLQ5suIEHEKc1GHtqVq475guiyqisKSoUnoaRtxkDaW5g1yvPt9IoSLOe2mRs7+FFhGGU693RsBUSwOXSdQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.9.3': + resolution: {integrity: sha512-oRj0AFePUhtatX+BscVhnzaAmWjpfAeySpM1TCbxA1rtBDeH/JDhi5yYzAKneDYtVtBvA7ApfeuzhMC9ye4xSg==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.17': + resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} + + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/chrome@0.0.270': + resolution: {integrity: sha512-ADvkowV7YnJfycZZxL2brluZ6STGW+9oKG37B422UePf2PCXuFA/XdERI0T18wtuWPx0tmFeZqq6MOXVk1IC+Q==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/filesystem@0.0.36': + resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==} + + '@types/filewriter@0.0.33': + resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==} + + '@types/har-format@1.2.15': + resolution: {integrity: sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/mocha@10.0.7': + resolution: {integrity: sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==} + + '@types/mute-stream@0.0.4': + resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} + + '@types/node@20.16.10': + resolution: {integrity: sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==} + + '@types/node@22.7.4': + resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + + '@types/prop-types@15.7.12': + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + + '@types/react-dom@18.3.0': + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + + '@types/react@18.3.5': + resolution: {integrity: sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==} + + '@types/sinonjs__fake-timers@8.1.5': + resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/which@2.0.2': + resolution: {integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==} + + '@types/wrap-ansi@3.0.0': + resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} + + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@typescript-eslint/eslint-plugin@7.18.0': + resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@7.18.0': + resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@7.18.0': + resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/type-utils@7.18.0': + resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@7.18.0': + resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/typescript-estree@7.18.0': + resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@7.18.0': + resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + + '@typescript-eslint/visitor-keys@7.18.0': + resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + '@vitejs/plugin-react-swc@3.7.2': + resolution: {integrity: sha512-y0byko2b2tSVVf5Gpng1eEhX1OvPC7x8yns1Fx8jDzlJp4LS6CMkCPfLw47cjyoMrshQDoQw4qcgjsU9VvlCew==} + peerDependencies: + vite: ^4 || ^5 || ^6 + + '@vitest/pretty-format@2.0.5': + resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} + + '@vitest/pretty-format@2.1.8': + resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} + + '@vitest/snapshot@2.0.5': + resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==} + + '@vitest/snapshot@2.1.8': + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + + '@wdio/cli@9.4.5': + resolution: {integrity: sha512-t4LfWunVw+z3VQ/pSVbNit6VyrboENhN0Rxt91PqlZKc3s0NOEMIiXVQIkUhZWDn2YvkHhxQRCJOt7pqe4n++A==} + engines: {node: '>=18.20.0'} + hasBin: true + + '@wdio/config@9.1.2': + resolution: {integrity: sha512-M8jDFgTxOeljv5M75em7oCu2cV16jHWH6HWj5CD3ZNzaMeHf+EkIuHNyREJjt8PCnssehzXD26TF63tGPHdksA==} + engines: {node: '>=18.20.0'} + + '@wdio/config@9.4.4': + resolution: {integrity: sha512-w1Qo6QywLSGxmoglU4BiqDGNmFbwh/L6BRud4AO9nGgTuwKy6UkT7KevzlkIRiCHtdqkkjExR3xUi2OgjMdHAA==} + engines: {node: '>=18.20.0'} + + '@wdio/globals@9.1.2': + resolution: {integrity: sha512-1qqTZgae3WXOboUO7lqzz7Y75q6n7uKq1W9jn2wrvWByOQ9rVUM9PCKQGhmjVoQRcqXBOMAazqNrRK6Xy1cqAg==} + engines: {node: '>=18.20.0'} + + '@wdio/globals@9.4.5': + resolution: {integrity: sha512-zdN/2EGOr2HER59CNAtSfmr/M7BMAH5gQJix4iPkDN5buf8PQZHE16GnfKtqKTIBeNgpkBkUyjyCKoIKSUngjw==} + engines: {node: '>=18.20.0'} + + '@wdio/local-runner@9.1.2': + resolution: {integrity: sha512-kGXNCzMHAax2d/HGx4ViHayi9zO1BZc7q9tnvamaBo4liP40DP1E8S5Kz3omsYMp0geXdZ87ZyaVRZo7tOKujw==} + engines: {node: '>=18.20.0'} + + '@wdio/logger@8.38.0': + resolution: {integrity: sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==} + engines: {node: ^16.13 || >=18} + + '@wdio/logger@9.1.0': + resolution: {integrity: sha512-1Rfg9VCy87I9IrViA1ned1Rqa66JwhCzdEo8rA8T3Ro6lBfOEwDbK1XW8ETKLWcweddzGeFalfVnvUlNgPmFdA==} + engines: {node: '>=18.20.0'} + + '@wdio/logger@9.1.3': + resolution: {integrity: sha512-cumRMK/gE1uedBUw3WmWXOQ7HtB6DR8EyKQioUz2P0IJtRRpglMBdZV7Svr3b++WWawOuzZHMfbTkJQmaVt8Gw==} + engines: {node: '>=18.20.0'} + + '@wdio/logger@9.4.4': + resolution: {integrity: sha512-BXx8RXFUW2M4dcO6t5Le95Hi2ZkTQBRsvBQqLekT2rZ6Xmw8ZKZBPf0FptnoftFGg6dYmwnDidYv/0+4PiHjpQ==} + engines: {node: '>=18.20.0'} + + '@wdio/mocha-framework@9.1.2': + resolution: {integrity: sha512-LG8arSVsSNqV61LvyQddmtDuqjeh+mVWhNPSCUi4AjZ2mBC85DTMBbvsIBSDK59DF9Ijd4NLDpRGnPzzgXjbIA==} + engines: {node: '>=18.20.0'} + + '@wdio/protocols@9.0.8': + resolution: {integrity: sha512-xRH54byFf623/w/KW62xkf/C2mGyigSfMm+UT3tNEAd5ZA9X2VAWQWQBPzdcrsck7Fxk4zlQX8Kb34RSs7Cy4Q==} + + '@wdio/protocols@9.4.4': + resolution: {integrity: sha512-IqbAWe5feY3xOwjbiW/2iwcbDU+nm5CX5Om835mxaNWqEoQiaZuTin4YgtgsPeSEBcSFtQ+2ooswr/6vIZdxSw==} + + '@wdio/repl@9.0.8': + resolution: {integrity: sha512-3iubjl4JX5zD21aFxZwQghqC3lgu+mSs8c3NaiYYNCC+IT5cI/8QuKlgh9s59bu+N3gG988jqMJeCYlKuUv/iw==} + engines: {node: '>=18.20.0'} + + '@wdio/repl@9.4.4': + resolution: {integrity: sha512-kchPRhoG/pCn4KhHGiL/ocNhdpR8OkD2e6sANlSUZ4TGBVi86YSIEjc2yXUwLacHknC/EnQk/SFnqd4MsNjGGg==} + engines: {node: '>=18.20.0'} + + '@wdio/reporter@9.2.14': + resolution: {integrity: sha512-njOqa9+w5zc9AY4fsUmW46EhZ2nzMFRXZPCmwnGZuYk81L3slVfAFhKk1wSTRhSbghjYAZndt9Yo3c4wFLh6Lg==} + engines: {node: '>=18.20.0'} + + '@wdio/runner@9.1.2': + resolution: {integrity: sha512-Hs/sPEzm1y9BehdQzK9vS6t6PS07gcigM42lfZSmai4xIAXDB0VZCvwWAZuq0okx2EcBTb9bIfPtx/6zqAoiXg==} + engines: {node: '>=18.20.0'} + + '@wdio/spec-reporter@9.2.14': + resolution: {integrity: sha512-/0QI/Lfld2gKscVAOTxgy1KyshxreDEu2F0FsiNQUUMQXuV8bN85lGgH6K3F+xZ0p17J/tg8UnWQCv2IaXTycw==} + engines: {node: '>=18.20.0'} + + '@wdio/types@9.1.2': + resolution: {integrity: sha512-mROY3xSBBNujSH0Opo3Sfi1QUm3l7HbVQ8/bDmPCwHXOeYlx0q14rLyyZI3LrN5uJ0KPpuNrVgE36NFaG8+xxw==} + engines: {node: '>=18.20.0'} + + '@wdio/types@9.2.2': + resolution: {integrity: sha512-nHZ9Ne9iRQFJ1TOYKUn4Fza69IshTTzk6RYmSZ51ImGs9uMZu0+S0Jm9REdly+VLN3FzxG6g2QSe0/F3uNVPdw==} + engines: {node: '>=18.20.0'} + + '@wdio/types@9.4.4': + resolution: {integrity: sha512-Z2TAVMZiz4wCfP7ZdHqUXlYfF4qj5bBOV25A7tHxFbbdWPvFb8sSW3SU2+fxSwu02n5sV1mgfRYOsloypOXBnw==} + engines: {node: '>=18.20.0'} + + '@wdio/utils@9.1.2': + resolution: {integrity: sha512-8APCnvJjHkG/6KwXtrPhEYR29Ph+vs1Gx2mGRnbYXNgbworfPEIZETpienHXhDEbINdqSb7EY5LkapIjP7nKbg==} + engines: {node: '>=18.20.0'} + + '@wdio/utils@9.4.4': + resolution: {integrity: sha512-CH2uHziYKZrm6xvI2Drfha+CBAK3cCHTFqhxfjP2dhz5kcCQfCEn22Bj12t2jYTILNvnxKFCxZyk+VEcQNMIKg==} + engines: {node: '>=18.20.0'} + + '@webassemblyjs/ast@1.12.1': + resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} + + '@webassemblyjs/floating-point-hex-parser@1.11.6': + resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} + + '@webassemblyjs/helper-api-error@1.11.6': + resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} + + '@webassemblyjs/helper-buffer@1.12.1': + resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} + + '@webassemblyjs/helper-numbers@1.11.6': + resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} + + '@webassemblyjs/helper-wasm-bytecode@1.11.6': + resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} + + '@webassemblyjs/helper-wasm-section@1.12.1': + resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} + + '@webassemblyjs/ieee754@1.11.6': + resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} + + '@webassemblyjs/leb128@1.11.6': + resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} + + '@webassemblyjs/utf8@1.11.6': + resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} + + '@webassemblyjs/wasm-edit@1.12.1': + resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} + + '@webassemblyjs/wasm-gen@1.12.1': + resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} + + '@webassemblyjs/wasm-opt@1.12.1': + resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} + + '@webassemblyjs/wasm-parser@1.12.1': + resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} + + '@webassemblyjs/wast-printer@1.12.1': + resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + '@zip.js/zip.js@2.7.52': + resolution: {integrity: sha512-+5g7FQswvrCHwYKNMd/KFxZSObctLSsQOgqBSi0LzwHo3li9Eh1w5cF5ndjQw9Zbr3ajVnd2+XyiX85gAetx1Q==} + engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} + + '@zip.js/zip.js@2.7.54': + resolution: {integrity: sha512-qMrJVg2hoEsZJjMJez9yI2+nZlBUxgYzGV3mqcb2B/6T1ihXp0fWBDYlVHlHquuorgNUQP5a8qSmX6HF5rFJNg==} + engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + + async-exit-hook@2.0.1: + resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} + engines: {node: '>=0.12.0'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.10.0: + resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} + engines: {node: '>=4'} + + axobject-query@3.1.1: + resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} + + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bare-events@2.5.0: + resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + + bare-fs@2.3.5: + resolution: {integrity: sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==} + + bare-os@2.4.4: + resolution: {integrity: sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==} + + bare-path@2.1.3: + resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} + + bare-stream@2.3.0: + resolution: {integrity: sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + browserslist@4.24.0: + resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001667: + resolution: {integrity: sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.0.0: + resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} + engines: {node: '>=18.17'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concurrently@9.0.1: + resolution: {integrity: sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg==} + engines: {node: '>=18'} + hasBin: true + + confusing-browser-globals@1.0.11: + resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + + css-shorthand-properties@1.1.2: + resolution: {integrity: sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==} + + css-value@0.0.1: + resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + decamelize@6.0.0: + resolution: {integrity: sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + deep-equal@2.2.3: + resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} + engines: {node: '>= 0.4'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge-ts@7.1.1: + resolution: {integrity: sha512-M27OAbyR/XgJujhAd6ZlYvZGzejbzvGPSZWwuzezPCdKLT9VMtK0kpRNDc5LeUDYqFN3e254gWG1yKpjidCtow==} + engines: {node: '>=16.0.0'} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + diff@7.0.0: + resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} + engines: {node: '>=0.3.1'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + easy-table@1.2.0: + resolution: {integrity: sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==} + + edge-paths@3.0.5: + resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} + engines: {node: '>=14.0.0'} + + edgedriver@5.6.1: + resolution: {integrity: sha512-3Ve9cd5ziLByUdigw6zovVeWJjVs8QHVmqOB0sJ0WNeVPcwf4p18GnxMmVvlFmYRloUwf5suNuorea4QzwBIOA==} + hasBin: true + + edgedriver@6.1.1: + resolution: {integrity: sha512-/dM/PoBf22Xg3yypMWkmRQrBKEnSyNaZ7wHGCT9+qqT14izwtFT+QvdR89rjNkMfXwW+bSFoqOfbcvM+2Cyc7w==} + engines: {node: '>=18.0.0'} + hasBin: true + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.32: + resolution: {integrity: sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encoding-sniffer@0.2.0: + resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-get-iterator@1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + + es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.5.4: + resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.24.0: + resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + eslint-config-airbnb-base@15.0.0: + resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.2 + + eslint-config-airbnb-typescript@18.0.0: + resolution: {integrity: sha512-oc+Lxzgzsu8FQyFVa4QFaVKiitTYiiW3frB9KYW5OWdPrqFc7FzxgB20hP4cHMlr+MBzGcLl3jnCOVOydL9mIg==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^7.0.0 + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + + eslint-config-prettier@9.1.0: + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.11.0: + resolution: {integrity: sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.29.1: + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.9.0: + resolution: {integrity: sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + + eslint-plugin-prettier@5.2.1: + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-react-hooks@4.6.2: + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + + eslint-plugin-react@7.35.0: + resolution: {integrity: sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-plugin-tailwindcss@3.17.4: + resolution: {integrity: sha512-gJAEHmCq2XFfUP/+vwEfEJ9igrPeZFg+skeMtsxquSQdxba9XRk5bn0Bp9jxG1VV9/wwPKi1g3ZjItu6MIjhNg==} + engines: {node: '>=18.12.0'} + peerDependencies: + tailwindcss: ^3.4.0 + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + esm@3.2.25: + resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} + engines: {node: '>=6'} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + execa@9.3.1: + resolution: {integrity: sha512-gdhefCCNy/8tpH/2+ajP9IQc14vXchNdd0weyzSJEFURhRMGncQ+zKFxwjAufIewPEJm9BPOaJnvg2UtlH2gPQ==} + engines: {node: ^18.19.0 || >=20.5.0} + + expect-webdriverio@5.0.2: + resolution: {integrity: sha512-vkUwoUvURH25pRClX1I5oCIObju8cT9kN5jQH4RN5QxKXK7hdowYd8dbDXD5JKOE/OutdYx67YtCl8vpZq/uSg==} + engines: {node: '>=18 || >=20 || >=22'} + peerDependencies: + '@wdio/globals': ^9.0.0 + '@wdio/logger': ^9.0.0 + webdriverio: ^9.0.0 + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + fast-deep-equal@2.0.1: + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-xml-parser@4.5.0: + resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} + hasBin: true + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gaze@1.1.3: + resolution: {integrity: sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==} + engines: {node: '>= 4.0.0'} + + geckodriver@4.5.0: + resolution: {integrity: sha512-EnBCT9kJ5oEoP3DaJKjzxAhm7bbNNK6k2q7oCkCT58OIOOiE6Hsr+nVDHflsNaR68HMGtBKOLSZ+YvCDHecScw==} + engines: {node: ^16.13 || >=18 || >=20} + hasBin: true + + geckodriver@5.0.0: + resolution: {integrity: sha512-vn7TtQ3b9VMJtVXsyWtQQl1fyBVFhQy7UvJF96kPuuJ0or5THH496AD3eUyaDD11+EqCxH9t6V+EP9soZQk4YQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-port@7.1.0: + resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + engines: {node: '>=16'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.8.0: + resolution: {integrity: sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==} + + get-uri@6.0.3: + resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} + engines: {node: '>= 14'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true + + glob@7.1.7: + resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globule@1.3.4: + resolution: {integrity: sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==} + engines: {node: '>= 0.10'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + + htmlfy@0.2.1: + resolution: {integrity: sha512-HoomFHQ3av1uhq+7FxJTq4Ns0clAD+tGbQNrSd0WFY3UAjjUk6G3LaWEqdgmIXYkY4pexZiyZ3ykZJhQlM0J5A==} + + htmlfy@0.3.2: + resolution: {integrity: sha512-FsxzfpeDYRqn1emox9VpxMPfGjADoUmmup8D604q497R0VNxiXs4ZZTN2QzkaMA5C9aHGUoe1iQRVSm+HK9xuA==} + + htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.5: + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + engines: {node: '>= 14'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + human-signals@8.0.0: + resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==} + engines: {node: '>=18.18.0'} + + husky@9.1.5: + resolution: {integrity: sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==} + engines: {node: '>=18'} + hasBin: true + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + inquirer@11.1.0: + resolution: {integrity: sha512-CmLAZT65GG/v30c+D2Fk8+ceP6pxD6RL+hIUOWAltCmeyEqWYwqu9v76q03OvjyZ3AB0C1Ala2stn1z/rMqGEw==} + engines: {node: '>=18'} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + + is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + + iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.0.1: + resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} + engines: {node: 20 || >=22} + + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + jiti@1.21.6: + resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-parse-even-better-errors@3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lines-and-columns@2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lint-staged@15.2.10: + resolution: {integrity: sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==} + engines: {node: '>=18.12.0'} + hasBin: true + + listr2@8.2.4: + resolution: {integrity: sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==} + engines: {node: '>=18.0.0'} + + loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + loader-utils@3.3.1: + resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} + engines: {node: '>= 12.13.0'} + + locate-app@2.4.43: + resolution: {integrity: sha512-BX6NEdECUGcDQw8aqqg02qLyF9rF8V+dAfyAnBzL2AofIlIvf4Q6EGXnzVWpWot9uBE+x/o8CjXHo7Zlegu91Q==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + + lodash.flattendeep@4.4.0: + resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.pickby@4.6.0: + resolution: {integrity: sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + lodash.zip@4.2.0: + resolution: {integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + loglevel-plugin-prefix@0.8.4: + resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} + + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.0.1: + resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==} + engines: {node: 20 || >=22} + + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + + minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + mocha@10.7.3: + resolution: {integrity: sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==} + engines: {node: '>= 14.0.0'} + hasBin: true + + mrmime@1.0.1: + resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + mylas@2.1.13: + resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==} + engines: {node: '>=12.0.0'} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + normalize-package-data@6.0.2: + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + pac-proxy-agent@7.0.2: + resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + + parse5-htmlparser2-tree-adapter@7.0.0: + resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + plimit-lit@1.6.1: + resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==} + engines: {node: '>=12'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + pretty-ms@9.1.0: + resolution: {integrity: sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw==} + engines: {node: '>=18'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + proxy-agent@6.4.0: + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} + engines: {node: '>= 14'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + + queue-lit@1.5.2: + resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==} + engines: {node: '>=12'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + read-pkg-up@10.1.0: + resolution: {integrity: sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==} + engines: {node: '>=16'} + + read-pkg@8.1.0: + resolution: {integrity: sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==} + engines: {node: '>=16'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + + recursive-readdir@2.2.3: + resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} + engines: {node: '>=6.0.0'} + + reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + resq@1.11.0: + resolution: {integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==} + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rgb2hex@0.2.5: + resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + + rollup@4.24.0: + resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + run-script-os@1.1.6: + resolution: {integrity: sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==} + hasBin: true + + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + safaridriver@0.1.2: + resolution: {integrity: sha512-4R309+gWflJktzPXBQCobbWEHlzC4aK3a+Ov3tz2Ib2aBxiwd11phkdIBH1l0EO22x24CJMUQkpKFumRriCSRg==} + + safaridriver@1.0.0: + resolution: {integrity: sha512-J92IFbskyo7OYB3Dt4aTdyhag1GlInrfbPCmMteb7aBK7PwlnGz1HI0+oyNN97j7pV9DqUAVoVgkNRMrfY47mQ==} + engines: {node: '>=18.0.0'} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sass@1.79.4: + resolution: {integrity: sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==} + engines: {node: '>=14.0.0'} + hasBin: true + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + serialize-error@11.0.3: + resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==} + engines: {node: '>=14.16'} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + socks-proxy-agent@8.0.4: + resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} + engines: {node: '>= 14'} + + socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + spacetrim@0.11.39: + resolution: {integrity: sha512-S/baW29azJ7py5ausQRE2S6uEDQnlxgMHOEEq4V770ooBDD1/9kZnxRcco/tjZYuDuqYXblCk/r3N13ZmvHZ2g==} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stop-iteration-iterator@1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} + + stream-buffers@3.0.3: + resolution: {integrity: sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==} + engines: {node: '>= 0.10.0'} + + streamx@2.20.1: + resolution: {integrity: sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string.prototype.includes@2.0.0: + resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} + + string.prototype.matchall@4.0.11: + resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} + engines: {node: ^14.18.0 || >=16.0.0} + + tailwind-merge@2.5.2: + resolution: {integrity: sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==} + + tailwindcss@3.4.14: + resolution: {integrity: sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==} + engines: {node: '>=14.0.0'} + hasBin: true + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + tar-fs@3.0.6: + resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + terser-webpack-plugin@5.3.10: + resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.34.1: + resolution: {integrity: sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==} + engines: {node: '>=10'} + hasBin: true + + text-decoder@1.2.0: + resolution: {integrity: sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + ts-loader@9.5.1: + resolution: {integrity: sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==} + engines: {node: '>=12.0.0'} + peerDependencies: + typescript: '*' + webpack: ^5.0.0 + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tsc-alias@1.8.10: + resolution: {integrity: sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==} + hasBin: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + engines: {node: '>=18.0.0'} + hasBin: true + + turbo-darwin-64@2.3.3: + resolution: {integrity: sha512-bxX82xe6du/3rPmm4aCC5RdEilIN99VUld4HkFQuw+mvFg6darNBuQxyWSHZTtc25XgYjQrjsV05888w1grpaA==} + cpu: [x64] + os: [darwin] + + turbo-darwin-arm64@2.3.3: + resolution: {integrity: sha512-DYbQwa3NsAuWkCUYVzfOUBbSUBVQzH5HWUFy2Kgi3fGjIWVZOFk86ss+xsWu//rlEAfYwEmopigsPYSmW4X15A==} + cpu: [arm64] + os: [darwin] + + turbo-linux-64@2.3.3: + resolution: {integrity: sha512-eHj9OIB0dFaP6BxB88jSuaCLsOQSYWBgmhy2ErCu6D2GG6xW3b6e2UWHl/1Ho9FsTg4uVgo4DB9wGsKa5erjUA==} + cpu: [x64] + os: [linux] + + turbo-linux-arm64@2.3.3: + resolution: {integrity: sha512-NmDE/NjZoDj1UWBhMtOPmqFLEBKhzGS61KObfrDEbXvU3lekwHeoPvAMfcovzswzch+kN2DrtbNIlz+/rp8OCg==} + cpu: [arm64] + os: [linux] + + turbo-windows-64@2.3.3: + resolution: {integrity: sha512-O2+BS4QqjK3dOERscXqv7N2GXNcqHr9hXumkMxDj/oGx9oCatIwnnwx34UmzodloSnJpgSqjl8iRWiY65SmYoQ==} + cpu: [x64] + os: [win32] + + turbo-windows-arm64@2.3.3: + resolution: {integrity: sha512-dW4ZK1r6XLPNYLIKjC4o87HxYidtRRcBeo/hZ9Wng2XM/MqqYkAyzJXJGgRMsc0MMEN9z4+ZIfnSNBrA0b08ag==} + cpu: [arm64] + os: [win32] + + turbo@2.3.3: + resolution: {integrity: sha512-DUHWQAcC8BTiUZDRzAYGvpSpGLiaOQPfYXlCieQbwUvmml/LRGIe3raKdrOPOoiX0DYlzxs2nH6BoWJoZrj8hA==} + hasBin: true + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@2.13.0: + resolution: {integrity: sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==} + engines: {node: '>=12.20'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + + type-fest@4.26.1: + resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} + engines: {node: '>=16'} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + undici@6.21.0: + resolution: {integrity: sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==} + engines: {node: '>=18.17'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + urlpattern-polyfill@10.0.0: + resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} + + userhome@1.0.0: + resolution: {integrity: sha512-ayFKY3H+Pwfy4W98yPdtH1VqH4psDeyW8lYYFzfecR9d6hqLpqhecktvYR3SEEXt7vG0S1JEpciI3g94pMErig==} + engines: {node: '>= 0.8.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + vite@6.0.5: + resolution: {integrity: sha512-akD5IAH/ID5imgue2DYhzsEwCi0/4VKY31uhMLEYJwPP4TiUp8pL5PIK+Wo7H8qT8JY9i+pVfPydcFPYD1EL7g==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + wait-port@1.1.0: + resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} + engines: {node: '>=10'} + hasBin: true + + watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + engines: {node: '>=10.13.0'} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + webdriver@9.1.2: + resolution: {integrity: sha512-NjeYVTCSMwQrd+EDpSSB8YnSNzYeEPU2IoJhvjaXUwTEhoaIvz6x6fM4UqCbm/ph8lZ1uWux43fqIcfDzFQl5Q==} + engines: {node: '>=18.20.0'} + + webdriver@9.4.4: + resolution: {integrity: sha512-F/QxX3TNfkBWzYC0Ywz0oRRUtvUEFUM59pob19gs+lZ2seXKKCJ8vVLzIWcT9XBU8dFAWN6Mzqi5FypHWeBgfw==} + engines: {node: '>=18.20.0'} + + webdriverio@9.1.2: + resolution: {integrity: sha512-Yk/OmxUmse6YVBMr+iM5zH3LKiy07cJQsq19qL2Zj29+2I3b8kK8uGxx8+DhqYF/A/MVwHUFxACzQDYsdW6pjw==} + engines: {node: '>=18.20.0'} + peerDependencies: + puppeteer-core: ^22.3.0 + peerDependenciesMeta: + puppeteer-core: + optional: true + + webdriverio@9.4.5: + resolution: {integrity: sha512-tc22NSwKbXNROhafzktoQnhfkx0bhvh9a+XVaVu3mLhaiOmymIGDcS2NyRoOn3Sq4JxWJuOUwTO6f6jNkFJ5bQ==} + engines: {node: '>=18.20.0'} + peerDependencies: + puppeteer-core: ^22.3.0 + peerDependenciesMeta: + puppeteer-core: + optional: true + + webextension-polyfill@0.12.0: + resolution: {integrity: sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==} + + webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + + webpack@5.94.0: + resolution: {integrity: sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-builtin-type@1.1.4: + resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + 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 + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml@2.5.1: + resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} + engines: {node: '>= 14'} + hasBin: true + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.1.1: + resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} + engines: {node: '>=12.20'} + + yoctocolors-cjs@2.1.2: + resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + engines: {node: '>=18'} + + yoctocolors@2.1.1: + resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} + engines: {node: '>=18'} + + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.24.7': + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.1.0 + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.0 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@esbuild/aix-ppc64@0.23.1': + optional: true + + '@esbuild/aix-ppc64@0.24.0': + optional: true + + '@esbuild/android-arm64@0.23.1': + optional: true + + '@esbuild/android-arm64@0.24.0': + optional: true + + '@esbuild/android-arm@0.23.1': + optional: true + + '@esbuild/android-arm@0.24.0': + optional: true + + '@esbuild/android-x64@0.23.1': + optional: true + + '@esbuild/android-x64@0.24.0': + optional: true + + '@esbuild/darwin-arm64@0.23.1': + optional: true + + '@esbuild/darwin-arm64@0.24.0': + optional: true + + '@esbuild/darwin-x64@0.23.1': + optional: true + + '@esbuild/darwin-x64@0.24.0': + optional: true + + '@esbuild/freebsd-arm64@0.23.1': + optional: true + + '@esbuild/freebsd-arm64@0.24.0': + optional: true + + '@esbuild/freebsd-x64@0.23.1': + optional: true + + '@esbuild/freebsd-x64@0.24.0': + optional: true + + '@esbuild/linux-arm64@0.23.1': + optional: true + + '@esbuild/linux-arm64@0.24.0': + optional: true + + '@esbuild/linux-arm@0.23.1': + optional: true + + '@esbuild/linux-arm@0.24.0': + optional: true + + '@esbuild/linux-ia32@0.23.1': + optional: true + + '@esbuild/linux-ia32@0.24.0': + optional: true + + '@esbuild/linux-loong64@0.23.1': + optional: true + + '@esbuild/linux-loong64@0.24.0': + optional: true + + '@esbuild/linux-mips64el@0.23.1': + optional: true + + '@esbuild/linux-mips64el@0.24.0': + optional: true + + '@esbuild/linux-ppc64@0.23.1': + optional: true + + '@esbuild/linux-ppc64@0.24.0': + optional: true + + '@esbuild/linux-riscv64@0.23.1': + optional: true + + '@esbuild/linux-riscv64@0.24.0': + optional: true + + '@esbuild/linux-s390x@0.23.1': + optional: true + + '@esbuild/linux-s390x@0.24.0': + optional: true + + '@esbuild/linux-x64@0.23.1': + optional: true + + '@esbuild/linux-x64@0.24.0': + optional: true + + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.24.0': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.24.0': + optional: true + + '@esbuild/openbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-x64@0.24.0': + optional: true + + '@esbuild/sunos-x64@0.23.1': + optional: true + + '@esbuild/sunos-x64@0.24.0': + optional: true + + '@esbuild/win32-arm64@0.23.1': + optional: true + + '@esbuild/win32-arm64@0.24.0': + optional: true + + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-ia32@0.24.0': + optional: true + + '@esbuild/win32-x64@0.23.1': + optional: true + + '@esbuild/win32-x64@0.24.0': + optional: true + + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.11.0': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.3.7(supports-color@8.1.1) + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.0': {} + + '@humanwhocodes/config-array@0.11.14': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.7(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@inquirer/checkbox@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.6 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.2 + + '@inquirer/confirm@4.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/core@9.2.1': + dependencies: + '@inquirer/figures': 1.0.6 + '@inquirer/type': 2.0.0 + '@types/mute-stream': 0.0.4 + '@types/node': 22.7.4 + '@types/wrap-ansi': 3.0.0 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 1.0.0 + signal-exit: 4.1.0 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + + '@inquirer/editor@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + external-editor: 3.1.0 + + '@inquirer/expand@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.2 + + '@inquirer/figures@1.0.6': {} + + '@inquirer/input@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/number@2.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/password@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + + '@inquirer/prompts@6.0.1': + dependencies: + '@inquirer/checkbox': 3.0.1 + '@inquirer/confirm': 4.0.1 + '@inquirer/editor': 3.0.1 + '@inquirer/expand': 3.0.1 + '@inquirer/input': 3.0.1 + '@inquirer/number': 2.0.1 + '@inquirer/password': 3.0.1 + '@inquirer/rawlist': 3.0.1 + '@inquirer/search': 2.0.1 + '@inquirer/select': 3.0.1 + + '@inquirer/rawlist@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.2 + + '@inquirer/search@2.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.6 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.2 + + '@inquirer/select@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.6 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.2 + + '@inquirer/type@2.0.0': + dependencies: + mute-stream: 1.0.0 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.7.4 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@laynezh/vite-plugin-lib-assets@0.6.1(vite@6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1))': + dependencies: + escape-string-regexp: 4.0.0 + loader-utils: 3.3.1 + mrmime: 1.0.1 + semver: 7.6.3 + vite: 6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1) + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.1.1': {} + + '@promptbook/utils@0.70.0-1': + dependencies: + spacetrim: 0.11.39 + + '@puppeteer/browsers@2.4.0': + dependencies: + debug: 4.3.7(supports-color@8.1.1) + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.4.0 + semver: 7.6.3 + tar-fs: 3.0.6 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + '@rollup/plugin-sucrase@5.0.2(rollup@4.24.0)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.24.0) + sucrase: 3.35.0 + optionalDependencies: + rollup: 4.24.0 + + '@rollup/pluginutils@5.1.0(rollup@4.24.0)': + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 4.24.0 + + '@rollup/rollup-android-arm-eabi@4.24.0': + optional: true + + '@rollup/rollup-android-arm64@4.24.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.24.0': + optional: true + + '@rollup/rollup-darwin-x64@4.24.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.24.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.24.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.24.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.24.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.24.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.24.0': + optional: true + + '@sec-ant/readable-stream@0.4.1': {} + + '@sinclair/typebox@0.27.8': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@swc/core-darwin-arm64@1.9.3': + optional: true + + '@swc/core-darwin-x64@1.9.3': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.9.3': + optional: true + + '@swc/core-linux-arm64-gnu@1.9.3': + optional: true + + '@swc/core-linux-arm64-musl@1.9.3': + optional: true + + '@swc/core-linux-x64-gnu@1.9.3': + optional: true + + '@swc/core-linux-x64-musl@1.9.3': + optional: true + + '@swc/core-win32-arm64-msvc@1.9.3': + optional: true + + '@swc/core-win32-ia32-msvc@1.9.3': + optional: true + + '@swc/core-win32-x64-msvc@1.9.3': + optional: true + + '@swc/core@1.9.3': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.17 + optionalDependencies: + '@swc/core-darwin-arm64': 1.9.3 + '@swc/core-darwin-x64': 1.9.3 + '@swc/core-linux-arm-gnueabihf': 1.9.3 + '@swc/core-linux-arm64-gnu': 1.9.3 + '@swc/core-linux-arm64-musl': 1.9.3 + '@swc/core-linux-x64-gnu': 1.9.3 + '@swc/core-linux-x64-musl': 1.9.3 + '@swc/core-win32-arm64-msvc': 1.9.3 + '@swc/core-win32-ia32-msvc': 1.9.3 + '@swc/core-win32-x64-msvc': 1.9.3 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.17': + dependencies: + '@swc/counter': 0.1.3 + + '@tootallnate/quickjs-emscripten@0.23.0': {} + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/chrome@0.0.270': + dependencies: + '@types/filesystem': 0.0.36 + '@types/har-format': 1.2.15 + + '@types/estree@1.0.6': {} + + '@types/filesystem@0.0.36': + dependencies: + '@types/filewriter': 0.0.33 + + '@types/filewriter@0.0.33': {} + + '@types/har-format@1.2.15': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/mocha@10.0.7': {} + + '@types/mute-stream@0.0.4': + dependencies: + '@types/node': 22.7.4 + + '@types/node@20.16.10': + dependencies: + undici-types: 6.19.8 + + '@types/node@22.7.4': + dependencies: + undici-types: 6.19.8 + + '@types/normalize-package-data@2.4.4': {} + + '@types/prop-types@15.7.12': {} + + '@types/react-dom@18.3.0': + dependencies: + '@types/react': 18.3.5 + + '@types/react@18.3.5': + dependencies: + '@types/prop-types': 15.7.12 + csstype: 3.1.3 + + '@types/sinonjs__fake-timers@8.1.5': {} + + '@types/stack-utils@2.0.3': {} + + '@types/which@2.0.2': {} + + '@types/wrap-ansi@3.0.0': {} + + '@types/ws@8.5.13': + dependencies: + '@types/node': 20.16.10 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 22.7.4 + optional: true + + '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 7.18.0 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.7(supports-color@8.1.1) + eslint: 8.57.0 + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@7.18.0': + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + + '@typescript-eslint/type-utils@7.18.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + debug: 4.3.7(supports-color@8.1.1) + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@7.18.0': {} + + '@typescript-eslint/typescript-estree@7.18.0(typescript@5.5.4)': + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.7(supports-color@8.1.1) + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@7.18.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@7.18.0': + dependencies: + '@typescript-eslint/types': 7.18.0 + eslint-visitor-keys: 3.4.3 + + '@ungap/structured-clone@1.2.0': {} + + '@vitejs/plugin-react-swc@3.7.2(vite@6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1))': + dependencies: + '@swc/core': 1.9.3 + vite: 6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1) + transitivePeerDependencies: + - '@swc/helpers' + + '@vitest/pretty-format@2.0.5': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/pretty-format@2.1.8': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/snapshot@2.0.5': + dependencies: + '@vitest/pretty-format': 2.0.5 + magic-string: 0.30.11 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.17 + pathe: 1.1.2 + + '@wdio/cli@9.4.5': + dependencies: + '@types/node': 20.16.10 + '@vitest/snapshot': 2.1.8 + '@wdio/config': 9.4.4 + '@wdio/globals': 9.4.5(@wdio/logger@9.4.4) + '@wdio/logger': 9.4.4 + '@wdio/protocols': 9.4.4 + '@wdio/types': 9.4.4 + '@wdio/utils': 9.4.4 + async-exit-hook: 2.0.1 + chalk: 5.3.0 + chokidar: 4.0.1 + dotenv: 16.4.5 + ejs: 3.1.10 + execa: 9.3.1 + import-meta-resolve: 4.1.0 + inquirer: 11.1.0 + lodash.flattendeep: 4.4.0 + lodash.pickby: 4.6.0 + lodash.union: 4.6.0 + read-pkg-up: 10.1.0 + recursive-readdir: 2.2.3 + tsx: 4.19.2 + webdriverio: 9.4.5 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - puppeteer-core + - supports-color + - utf-8-validate + + '@wdio/config@9.1.2': + dependencies: + '@wdio/logger': 9.1.0 + '@wdio/types': 9.1.2 + '@wdio/utils': 9.1.2 + decamelize: 6.0.0 + deepmerge-ts: 7.1.1 + glob: 10.4.5 + import-meta-resolve: 4.1.0 + transitivePeerDependencies: + - supports-color + + '@wdio/config@9.4.4': + dependencies: + '@wdio/logger': 9.4.4 + '@wdio/types': 9.4.4 + '@wdio/utils': 9.4.4 + deepmerge-ts: 7.1.1 + glob: 10.4.5 + import-meta-resolve: 4.1.0 + transitivePeerDependencies: + - supports-color + + '@wdio/globals@9.1.2(@wdio/logger@9.1.0)': + optionalDependencies: + expect-webdriverio: 5.0.2(@wdio/globals@9.1.2(@wdio/logger@9.1.0))(@wdio/logger@9.1.0)(webdriverio@9.1.2) + webdriverio: 9.1.2 + transitivePeerDependencies: + - '@wdio/logger' + - bufferutil + - puppeteer-core + - supports-color + - utf-8-validate + + '@wdio/globals@9.4.5(@wdio/logger@9.1.0)': + optionalDependencies: + expect-webdriverio: 5.0.2(@wdio/globals@9.4.5(@wdio/logger@9.1.0))(@wdio/logger@9.1.0)(webdriverio@9.4.5) + webdriverio: 9.4.5 + transitivePeerDependencies: + - '@wdio/logger' + - bufferutil + - puppeteer-core + - supports-color + - utf-8-validate + + '@wdio/globals@9.4.5(@wdio/logger@9.4.4)': + optionalDependencies: + expect-webdriverio: 5.0.2(@wdio/globals@9.4.5(@wdio/logger@9.1.0))(@wdio/logger@9.4.4)(webdriverio@9.4.5) + webdriverio: 9.4.5 + transitivePeerDependencies: + - '@wdio/logger' + - bufferutil + - puppeteer-core + - supports-color + - utf-8-validate + + '@wdio/local-runner@9.1.2': + dependencies: + '@types/node': 20.16.10 + '@wdio/logger': 9.1.0 + '@wdio/repl': 9.0.8 + '@wdio/runner': 9.1.2 + '@wdio/types': 9.1.2 + async-exit-hook: 2.0.1 + split2: 4.2.0 + stream-buffers: 3.0.3 + transitivePeerDependencies: + - bufferutil + - puppeteer-core + - supports-color + - utf-8-validate + + '@wdio/logger@8.38.0': + dependencies: + chalk: 5.3.0 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/logger@9.1.0': + dependencies: + chalk: 5.3.0 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/logger@9.1.3': + dependencies: + chalk: 5.3.0 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/logger@9.4.4': + dependencies: + chalk: 5.3.0 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/mocha-framework@9.1.2': + dependencies: + '@types/mocha': 10.0.7 + '@types/node': 20.16.10 + '@wdio/logger': 9.1.0 + '@wdio/types': 9.1.2 + '@wdio/utils': 9.1.2 + mocha: 10.7.3 + transitivePeerDependencies: + - supports-color + + '@wdio/protocols@9.0.8': {} + + '@wdio/protocols@9.4.4': {} + + '@wdio/repl@9.0.8': + dependencies: + '@types/node': 20.16.10 + + '@wdio/repl@9.4.4': + dependencies: + '@types/node': 20.16.10 + + '@wdio/reporter@9.2.14': + dependencies: + '@types/node': 20.16.10 + '@wdio/logger': 9.1.3 + '@wdio/types': 9.2.2 + diff: 7.0.0 + object-inspect: 1.13.2 + + '@wdio/runner@9.1.2': + dependencies: + '@types/node': 20.16.10 + '@wdio/config': 9.1.2 + '@wdio/globals': 9.1.2(@wdio/logger@9.1.0) + '@wdio/logger': 9.1.0 + '@wdio/types': 9.1.2 + '@wdio/utils': 9.1.2 + deepmerge-ts: 7.1.1 + expect-webdriverio: 5.0.2(@wdio/globals@9.1.2(@wdio/logger@9.1.0))(@wdio/logger@9.1.0)(webdriverio@9.1.2) + gaze: 1.1.3 + webdriver: 9.1.2 + webdriverio: 9.1.2 + transitivePeerDependencies: + - bufferutil + - puppeteer-core + - supports-color + - utf-8-validate + + '@wdio/spec-reporter@9.2.14': + dependencies: + '@wdio/reporter': 9.2.14 + '@wdio/types': 9.2.2 + chalk: 5.3.0 + easy-table: 1.2.0 + pretty-ms: 9.1.0 + + '@wdio/types@9.1.2': + dependencies: + '@types/node': 20.16.10 + + '@wdio/types@9.2.2': + dependencies: + '@types/node': 20.16.10 + + '@wdio/types@9.4.4': + dependencies: + '@types/node': 20.16.10 + + '@wdio/utils@9.1.2': + dependencies: + '@puppeteer/browsers': 2.4.0 + '@wdio/logger': 9.1.0 + '@wdio/types': 9.1.2 + decamelize: 6.0.0 + deepmerge-ts: 7.1.1 + edgedriver: 5.6.1 + geckodriver: 4.5.0 + get-port: 7.1.0 + import-meta-resolve: 4.1.0 + locate-app: 2.4.43 + safaridriver: 0.1.2 + split2: 4.2.0 + wait-port: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@wdio/utils@9.4.4': + dependencies: + '@puppeteer/browsers': 2.4.0 + '@wdio/logger': 9.4.4 + '@wdio/types': 9.4.4 + decamelize: 6.0.0 + deepmerge-ts: 7.1.1 + edgedriver: 6.1.1 + geckodriver: 5.0.0 + get-port: 7.1.0 + import-meta-resolve: 4.1.0 + locate-app: 2.4.43 + safaridriver: 1.0.0 + split2: 4.2.0 + wait-port: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@webassemblyjs/ast@1.12.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + + '@webassemblyjs/floating-point-hex-parser@1.11.6': {} + + '@webassemblyjs/helper-api-error@1.11.6': {} + + '@webassemblyjs/helper-buffer@1.12.1': {} + + '@webassemblyjs/helper-numbers@1.11.6': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.11.6 + '@webassemblyjs/helper-api-error': 1.11.6 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.11.6': {} + + '@webassemblyjs/helper-wasm-section@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/wasm-gen': 1.12.1 + + '@webassemblyjs/ieee754@1.11.6': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.11.6': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.11.6': {} + + '@webassemblyjs/wasm-edit@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/helper-wasm-section': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-opt': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/wast-printer': 1.12.1 + + '@webassemblyjs/wasm-gen@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + + '@webassemblyjs/wasm-opt@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + + '@webassemblyjs/wasm-parser@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-api-error': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + + '@webassemblyjs/wast-printer@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + '@zip.js/zip.js@2.7.52': {} + + '@zip.js/zip.js@2.7.54': {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-import-attributes@1.9.5(acorn@8.12.1): + dependencies: + acorn: 8.12.1 + + acorn-jsx@5.3.2(acorn@8.12.1): + dependencies: + acorn: 8.12.1 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.12.1 + + acorn@8.12.1: {} + + agent-base@7.1.1: + dependencies: + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + ajv-keywords@3.5.2(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-colors@4.1.3: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + archiver-utils@5.0.2: + dependencies: + glob: 10.4.5 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 4.5.2 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.5.2 + readdir-glob: 1.1.3 + tar-stream: 3.1.7 + zip-stream: 6.0.1 + + arg@4.1.3: {} + + arg@5.0.2: {} + + argparse@2.0.1: {} + + aria-query@5.1.3: + dependencies: + deep-equal: 2.2.3 + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + + array-union@2.1.0: {} + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.tosorted@1.1.4: + 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 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + ast-types-flow@0.0.8: {} + + ast-types@0.13.4: + dependencies: + tslib: 2.7.0 + + async-exit-hook@2.0.1: {} + + async@3.2.6: {} + + autoprefixer@10.4.20(postcss@8.4.47): + dependencies: + browserslist: 4.24.0 + caniuse-lite: 1.0.30001667 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.0 + postcss: 8.4.47 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + axe-core@4.10.0: {} + + axobject-query@3.1.1: + dependencies: + deep-equal: 2.2.3 + + b4a@1.6.7: {} + + balanced-match@1.0.2: {} + + bare-events@2.5.0: + optional: true + + bare-fs@2.3.5: + dependencies: + bare-events: 2.5.0 + bare-path: 2.1.3 + bare-stream: 2.3.0 + optional: true + + bare-os@2.4.4: + optional: true + + bare-path@2.1.3: + dependencies: + bare-os: 2.4.4 + optional: true + + bare-stream@2.3.0: + dependencies: + b4a: 1.6.7 + streamx: 2.20.1 + optional: true + + base64-js@1.5.1: {} + + basic-ftp@5.0.5: {} + + binary-extensions@2.3.0: {} + + boolbase@1.0.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browser-stdout@1.3.1: {} + + browserslist@4.24.0: + dependencies: + caniuse-lite: 1.0.30001667 + electron-to-chromium: 1.5.32 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.0) + + buffer-crc32@0.2.13: {} + + buffer-crc32@1.0.0: {} + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + call-bind@1.0.7: + 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.2 + + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001667: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.3.0: {} + + chardet@0.7.0: {} + + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + + cheerio@1.0.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.1.0 + encoding-sniffer: 0.2.0 + htmlparser2: 9.1.0 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 + parse5-parser-stream: 7.1.2 + undici: 6.21.0 + whatwg-mimetype: 4.0.0 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + + chrome-trace-event@1.0.4: {} + + ci-info@3.9.0: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + + cli-width@4.1.0: {} + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@1.0.4: + optional: true + + clsx@2.1.1: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + commander@12.1.0: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + commander@9.5.0: {} + + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.5.2 + + concat-map@0.0.1: {} + + concurrently@9.0.1: + dependencies: + chalk: 4.1.2 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.1 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + confusing-browser-globals@1.0.11: {} + + core-util-is@1.0.3: {} + + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.5.2 + + create-require@1.1.1: {} + + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.3 + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.1.0 + nth-check: 2.1.1 + + css-shorthand-properties@1.1.2: {} + + css-value@0.0.1: {} + + css-what@6.1.0: {} + + cssesc@3.0.0: {} + + csstype@3.1.3: {} + + damerau-levenshtein@1.0.8: {} + + data-uri-to-buffer@4.0.1: {} + + data-uri-to-buffer@6.0.2: {} + + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.7(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + decamelize@4.0.0: {} + + decamelize@6.0.0: {} + + deep-equal@2.2.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + es-get-iterator: 1.1.3 + get-intrinsic: 1.2.4 + is-arguments: 1.1.1 + is-array-buffer: 3.0.4 + is-date-object: 1.0.5 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + isarray: 2.0.5 + object-is: 1.1.6 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + side-channel: 1.0.6 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + + deep-is@0.1.4: {} + + deepmerge-ts@7.1.1: {} + + deepmerge@4.3.1: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + optional: true + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + + didyoumean@1.2.2: {} + + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + + diff@5.2.0: {} + + diff@7.0.0: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dlv@1.1.3: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.1.0: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dotenv@16.4.5: {} + + eastasianwidth@0.2.0: {} + + easy-table@1.2.0: + dependencies: + ansi-regex: 5.0.1 + optionalDependencies: + wcwidth: 1.0.1 + + edge-paths@3.0.5: + dependencies: + '@types/which': 2.0.2 + which: 2.0.2 + + edgedriver@5.6.1: + dependencies: + '@wdio/logger': 8.38.0 + '@zip.js/zip.js': 2.7.52 + decamelize: 6.0.0 + edge-paths: 3.0.5 + fast-xml-parser: 4.5.0 + node-fetch: 3.3.2 + which: 4.0.0 + + edgedriver@6.1.1: + dependencies: + '@wdio/logger': 9.4.4 + '@zip.js/zip.js': 2.7.54 + decamelize: 6.0.0 + edge-paths: 3.0.5 + fast-xml-parser: 4.5.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + node-fetch: 3.3.2 + which: 5.0.0 + transitivePeerDependencies: + - supports-color + + ejs@3.1.10: + dependencies: + jake: 10.9.2 + + electron-to-chromium@1.5.32: {} + + emoji-regex@10.4.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encoding-sniffer@0.2.0: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + enhanced-resolve@5.17.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + entities@4.5.0: {} + + environment@1.1.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.23.3: + 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.4 + 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.2 + 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 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es-get-iterator@1.1.3: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + is-arguments: 1.1.1 + is-map: 2.0.3 + is-set: 2.0.3 + is-string: 1.0.7 + isarray: 2.0.5 + stop-iteration-iterator: 1.0.0 + + es-iterator-helpers@1.0.19: + 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.2 + safe-array-concat: 1.1.2 + + es-module-lexer@1.5.4: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + + esbuild@0.24.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0): + dependencies: + confusing-browser-globals: 1.0.11 + eslint: 8.57.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0) + object.assign: 4.1.5 + object.entries: 1.1.8 + semver: 6.3.1 + + eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0): + dependencies: + '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + eslint: 8.57.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) + transitivePeerDependencies: + - eslint-plugin-import + + eslint-config-prettier@9.1.0(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.15.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.11.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0): + dependencies: + 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: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.11.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.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 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0): + dependencies: + aria-query: 5.1.3 + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.2 + ast-types-flow: 0.0.8 + axe-core: 4.10.0 + axobject-query: 3.1.1 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + es-iterator-helpers: 1.0.19 + eslint: 8.57.0 + 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.0 + + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.3): + dependencies: + eslint: 8.57.0 + prettier: 3.3.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.1 + optionalDependencies: + eslint-config-prettier: 9.1.0(eslint@8.57.0) + + eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + + eslint-plugin-react@7.35.0(eslint@8.57.0): + 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.0.19 + eslint: 8.57.0 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + 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 + + eslint-plugin-tailwindcss@3.17.4(tailwindcss@3.4.14(ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4))): + dependencies: + fast-glob: 3.3.2 + postcss: 8.4.47 + tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4)) + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint@8.57.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.7(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + esm@3.2.25: {} + + espree@9.6.1: + dependencies: + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) + eslint-visitor-keys: 3.4.3 + + esprima@4.0.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + event-target-shim@5.0.1: {} + + eventemitter3@5.0.1: {} + + events@3.3.0: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + execa@9.3.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.3 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.0 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 5.3.0 + pretty-ms: 9.1.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.1 + + expect-webdriverio@5.0.2(@wdio/globals@9.1.2(@wdio/logger@9.1.0))(@wdio/logger@9.1.0)(webdriverio@9.1.2): + dependencies: + '@vitest/snapshot': 2.0.5 + '@wdio/globals': 9.1.2(@wdio/logger@9.1.0) + '@wdio/logger': 9.1.0 + expect: 29.7.0 + jest-matcher-utils: 29.7.0 + lodash.isequal: 4.5.0 + webdriverio: 9.1.2 + + expect-webdriverio@5.0.2(@wdio/globals@9.4.5(@wdio/logger@9.1.0))(@wdio/logger@9.1.0)(webdriverio@9.4.5): + dependencies: + '@vitest/snapshot': 2.0.5 + '@wdio/globals': 9.4.5(@wdio/logger@9.1.0) + '@wdio/logger': 9.1.0 + expect: 29.7.0 + jest-matcher-utils: 29.7.0 + lodash.isequal: 4.5.0 + webdriverio: 9.4.5 + optional: true + + expect-webdriverio@5.0.2(@wdio/globals@9.4.5(@wdio/logger@9.1.0))(@wdio/logger@9.4.4)(webdriverio@9.4.5): + dependencies: + '@vitest/snapshot': 2.0.5 + '@wdio/globals': 9.4.5(@wdio/logger@9.1.0) + '@wdio/logger': 9.4.4 + expect: 29.7.0 + jest-matcher-utils: 29.7.0 + lodash.isequal: 4.5.0 + webdriverio: 9.4.5 + optional: true + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + + extract-zip@2.0.1: + dependencies: + debug: 4.3.7(supports-color@8.1.1) + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@2.0.1: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-xml-parser@4.5.0: + dependencies: + strnum: 1.0.5 + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + fflate@0.8.2: {} + + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-up@6.3.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + + flat@5.0.2: {} + + flatted@3.3.1: {} + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + fraction.js@4.3.7: {} + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functions-have-names@1.2.3: {} + + gaze@1.1.3: + dependencies: + globule: 1.3.4 + + geckodriver@4.5.0: + dependencies: + '@wdio/logger': 9.1.3 + '@zip.js/zip.js': 2.7.52 + decamelize: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + node-fetch: 3.3.2 + tar-fs: 3.0.6 + which: 4.0.0 + transitivePeerDependencies: + - supports-color + + geckodriver@5.0.0: + dependencies: + '@wdio/logger': 9.4.4 + '@zip.js/zip.js': 2.7.54 + decamelize: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + node-fetch: 3.3.2 + tar-fs: 3.0.6 + which: 5.0.0 + transitivePeerDependencies: + - supports-color + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.2.0: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-port@7.1.0: {} + + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + + get-stream@8.0.1: {} + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + get-tsconfig@4.8.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + get-uri@6.0.3: + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.3.7(supports-color@8.1.1) + fs-extra: 11.2.0 + transitivePeerDependencies: + - supports-color + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-to-regexp@0.4.1: {} + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + + glob@11.0.0: + dependencies: + foreground-child: 3.3.0 + jackspeak: 4.0.1 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 2.0.0 + + glob@7.1.7: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + globule@1.3.4: + dependencies: + glob: 7.1.7 + lodash: 4.17.21 + minimatch: 3.0.8 + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + graceful-fs@4.2.11: {} + + grapheme-splitter@1.0.4: {} + + graphemer@1.4.0: {} + + has-bigints@1.0.2: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + + htmlfy@0.2.1: {} + + htmlfy@0.3.2: {} + + htmlparser2@9.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.5: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + human-signals@5.0.0: {} + + human-signals@8.0.0: {} + + husky@9.1.5: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + immediate@3.0.6: {} + + immutable@4.3.7: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-meta-resolve@4.1.0: {} + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + inquirer@11.1.0: + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/prompts': 6.0.1 + '@inquirer/type': 2.0.0 + '@types/mute-stream': 0.0.4 + ansi-escapes: 4.3.2 + mute-stream: 1.0.0 + run-async: 3.0.0 + rxjs: 7.8.1 + + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + + ip-address@9.0.5: + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + + is-arguments@1.1.1: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-arrayish@0.2.1: {} + + is-async-function@2.0.0: + dependencies: + has-tostringtag: 1.0.2 + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.1.2: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.2.0 + + is-generator-function@1.0.10: + dependencies: + has-tostringtag: 1.0.2 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-plain-obj@2.1.0: {} + + is-plain-obj@4.1.0: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-stream@4.0.1: {} + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-unicode-supported@0.1.0: {} + + is-unicode-supported@2.1.0: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-weakset@2.0.3: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isexe@3.1.1: {} + + iterator.prototype@1.1.2: + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.0.1: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.24.7 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.7.4 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-worker@27.5.1: + dependencies: + '@types/node': 22.7.4 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jiti@1.21.6: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsbn@1.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-parse-even-better-errors@3.0.2: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.8 + array.prototype.flat: 1.3.2 + object.assign: 4.1.5 + object.values: 1.2.0 + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lilconfig@2.1.0: {} + + lilconfig@3.1.2: {} + + lines-and-columns@1.2.4: {} + + lines-and-columns@2.0.4: {} + + lint-staged@15.2.10: + dependencies: + chalk: 5.3.0 + commander: 12.1.0 + debug: 4.3.7(supports-color@8.1.1) + execa: 8.0.1 + lilconfig: 3.1.2 + listr2: 8.2.4 + micromatch: 4.0.8 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.5.1 + transitivePeerDependencies: + - supports-color + + listr2@8.2.4: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + + loader-runner@4.3.0: {} + + loader-utils@3.3.1: {} + + locate-app@2.4.43: + dependencies: + '@promptbook/utils': 0.70.0-1 + type-fest: 2.13.0 + userhome: 1.0.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + lodash.clonedeep@4.5.0: {} + + lodash.flattendeep@4.4.0: {} + + lodash.isequal@4.5.0: {} + + lodash.merge@4.6.2: {} + + lodash.pickby@4.6.0: {} + + lodash.union@4.6.0: {} + + lodash.zip@4.2.0: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + loglevel-plugin-prefix@0.8.4: {} + + loglevel@1.9.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@10.4.3: {} + + lru-cache@11.0.1: {} + + lru-cache@7.18.3: {} + + magic-string@0.30.11: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + make-error@1.3.6: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@3.0.8: + dependencies: + brace-expansion: 1.1.11 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + mocha@10.7.3: + dependencies: + ansi-colors: 4.1.3 + browser-stdout: 1.3.1 + chokidar: 3.6.0 + debug: 4.3.7(supports-color@8.1.1) + diff: 5.2.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.1.6 + ms: 2.1.3 + serialize-javascript: 6.0.2 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.5.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + yargs-unparser: 2.0.0 + + mrmime@1.0.1: {} + + ms@2.1.3: {} + + mute-stream@1.0.0: {} + + mylas@2.1.13: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.7: {} + + natural-compare@1.4.0: {} + + neo-async@2.6.2: {} + + netmask@2.0.2: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + node-releases@2.0.18: {} + + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.6.3 + validate-npm-package-license: 3.0.4 + + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + object-inspect@1.13.2: {} + + object-is@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.entries@1.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + os-tmpdir@1.0.2: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.1.1 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + pac-proxy-agent@7.0.2: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.1 + debug: 4.3.7(supports-color@8.1.1) + get-uri: 6.0.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + + package-json-from-dist@1.0.0: {} + + pako@1.0.11: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@7.1.1: + dependencies: + '@babel/code-frame': 7.24.7 + error-ex: 1.3.2 + json-parse-even-better-errors: 3.0.2 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + + parse-ms@4.0.0: {} + + parse5-htmlparser2-tree-adapter@7.0.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.1.2 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.1.2 + + parse5@7.1.2: + dependencies: + entities: 4.5.0 + + path-exists@4.0.0: {} + + path-exists@5.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.0.1 + minipass: 7.1.2 + + path-type@4.0.0: {} + + pathe@1.1.2: {} + + pend@1.2.0: {} + + picocolors@1.1.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pidtree@0.6.0: {} + + pify@2.3.0: {} + + pirates@4.0.6: {} + + plimit-lit@1.6.1: + dependencies: + queue-lit: 1.5.2 + + possible-typed-array-names@1.0.0: {} + + postcss-import@15.1.0(postcss@8.4.47): + dependencies: + postcss: 8.4.47 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + postcss-js@4.0.1(postcss@8.4.47): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.47 + + postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4)): + dependencies: + lilconfig: 3.1.2 + yaml: 2.5.1 + optionalDependencies: + postcss: 8.4.47 + ts-node: 10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4) + + postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.5.1): + dependencies: + lilconfig: 3.1.2 + optionalDependencies: + jiti: 1.21.6 + postcss: 8.4.49 + tsx: 4.19.2 + yaml: 2.5.1 + + postcss-nested@6.2.0(postcss@8.4.47): + dependencies: + postcss: 8.4.47 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.47: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.0 + source-map-js: 1.2.1 + + postcss@8.4.49: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.3.3: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + pretty-ms@9.1.0: + dependencies: + parse-ms: 4.0.0 + + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + progress@2.0.3: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + proxy-agent@6.4.0: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7(supports-color@8.1.1) + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.2 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color + + proxy-from-env@1.1.0: {} + + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + punycode@2.3.1: {} + + query-selector-shadow-dom@1.0.1: {} + + queue-lit@1.5.2: {} + + queue-microtask@1.2.3: {} + + queue-tick@1.0.1: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react-is@16.13.1: {} + + react-is@18.3.1: {} + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + read-pkg-up@10.1.0: + dependencies: + find-up: 6.3.0 + read-pkg: 8.1.0 + type-fest: 4.26.1 + + read-pkg@8.1.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 6.0.2 + parse-json: 7.1.1 + type-fest: 4.26.1 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@4.5.2: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.0.2: {} + + recursive-readdir@2.2.3: + dependencies: + minimatch: 3.1.2 + + reflect.getprototypeof@1.0.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + which-builtin-type: 1.1.4 + + regexp.prototype.flags@1.5.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + require-directory@2.1.1: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resq@1.11.0: + dependencies: + fast-deep-equal: 2.0.1 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.0.4: {} + + rfdc@1.4.1: {} + + rgb2hex@0.2.5: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rimraf@6.0.1: + dependencies: + glob: 11.0.0 + package-json-from-dist: 1.0.0 + + rollup@4.24.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.24.0 + '@rollup/rollup-android-arm64': 4.24.0 + '@rollup/rollup-darwin-arm64': 4.24.0 + '@rollup/rollup-darwin-x64': 4.24.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 + '@rollup/rollup-linux-arm-musleabihf': 4.24.0 + '@rollup/rollup-linux-arm64-gnu': 4.24.0 + '@rollup/rollup-linux-arm64-musl': 4.24.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 + '@rollup/rollup-linux-riscv64-gnu': 4.24.0 + '@rollup/rollup-linux-s390x-gnu': 4.24.0 + '@rollup/rollup-linux-x64-gnu': 4.24.0 + '@rollup/rollup-linux-x64-musl': 4.24.0 + '@rollup/rollup-win32-arm64-msvc': 4.24.0 + '@rollup/rollup-win32-ia32-msvc': 4.24.0 + '@rollup/rollup-win32-x64-msvc': 4.24.0 + fsevents: 2.3.3 + + run-async@3.0.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + run-script-os@1.1.6: {} + + rxjs@7.8.1: + dependencies: + tslib: 2.7.0 + + safaridriver@0.1.2: {} + + safaridriver@1.0.0: {} + + safe-array-concat@1.1.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-regex-test@1.0.3: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + safer-buffer@2.1.2: {} + + sass@1.79.4: + dependencies: + chokidar: 4.0.1 + immutable: 4.3.7 + source-map-js: 1.2.1 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + schema-utils@3.3.0: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + semver@6.3.1: {} + + semver@7.6.3: {} + + serialize-error@11.0.3: + dependencies: + type-fest: 2.19.0 + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + set-function-length@1.2.2: + 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 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + setimmediate@1.0.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.1: {} + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + smart-buffer@4.2.0: {} + + socks-proxy-agent@8.0.4: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7(supports-color@8.1.1) + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + + socks@2.8.3: + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.4: {} + + spacetrim@0.11.39: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.20 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.20 + + spdx-license-ids@3.0.20: {} + + split2@4.2.0: {} + + sprintf-js@1.1.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stop-iteration-iterator@1.0.0: + dependencies: + internal-slot: 1.0.7 + + stream-buffers@3.0.3: {} + + streamx@2.20.1: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.0 + optionalDependencies: + bare-events: 2.5.0 + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + + string.prototype.includes@2.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + + string.prototype.matchall@4.0.11: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + 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 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom@3.0.0: {} + + strip-final-newline@3.0.0: {} + + strip-final-newline@4.0.0: {} + + strip-json-comments@3.1.1: {} + + strnum@1.0.5: {} + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.9.1: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.7.0 + + tailwind-merge@2.5.2: {} + + tailwindcss@3.4.14(ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4)): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.0 + postcss: 8.4.47 + postcss-import: 15.1.0(postcss@8.4.47) + postcss-js: 4.0.1(postcss@8.4.47) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4)) + postcss-nested: 6.2.0(postcss@8.4.47) + postcss-selector-parser: 6.1.2 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + tapable@2.2.1: {} + + tar-fs@3.0.6: + dependencies: + pump: 3.0.2 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.3.5 + bare-path: 2.1.3 + + tar-stream@3.1.7: + dependencies: + b4a: 1.6.7 + fast-fifo: 1.3.2 + streamx: 2.20.1 + + terser-webpack-plugin@5.3.10(@swc/core@1.9.3)(esbuild@0.23.1)(webpack@5.94.0(@swc/core@1.9.3)(esbuild@0.23.1)): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.34.1 + webpack: 5.94.0(@swc/core@1.9.3)(esbuild@0.23.1) + optionalDependencies: + '@swc/core': 1.9.3 + esbuild: 0.23.1 + + terser@5.34.1: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.12.1 + commander: 2.20.3 + source-map-support: 0.5.21 + + text-decoder@1.2.0: + dependencies: + b4a: 1.6.7 + + text-table@0.2.0: {} + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + through@2.3.8: {} + + tinyrainbow@1.2.0: {} + + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tree-kill@1.2.2: {} + + ts-api-utils@1.3.0(typescript@5.5.4): + dependencies: + typescript: 5.5.4 + + ts-interface-checker@0.1.13: {} + + ts-loader@9.5.1(typescript@5.5.4)(webpack@5.94.0(@swc/core@1.9.3)(esbuild@0.23.1)): + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.17.1 + micromatch: 4.0.8 + semver: 7.6.3 + source-map: 0.7.4 + typescript: 5.5.4 + webpack: 5.94.0(@swc/core@1.9.3)(esbuild@0.23.1) + + ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.7.4)(typescript@5.5.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.7.4 + acorn: 8.12.1 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.9.3 + + tsc-alias@1.8.10: + dependencies: + chokidar: 3.6.0 + commander: 9.5.0 + globby: 11.1.0 + mylas: 2.1.13 + normalize-path: 3.0.0 + plimit-lit: 1.6.1 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.7.0: {} + + tsx@4.19.2: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.0 + optionalDependencies: + fsevents: 2.3.3 + + turbo-darwin-64@2.3.3: + optional: true + + turbo-darwin-arm64@2.3.3: + optional: true + + turbo-linux-64@2.3.3: + optional: true + + turbo-linux-arm64@2.3.3: + optional: true + + turbo-windows-64@2.3.3: + optional: true + + turbo-windows-arm64@2.3.3: + optional: true + + turbo@2.3.3: + optionalDependencies: + turbo-darwin-64: 2.3.3 + turbo-darwin-arm64: 2.3.3 + turbo-linux-64: 2.3.3 + turbo-linux-arm64: 2.3.3 + turbo-windows-64: 2.3.3 + turbo-windows-arm64: 2.3.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + type-fest@0.21.3: {} + + type-fest@2.13.0: {} + + type-fest@2.19.0: {} + + type-fest@3.13.1: {} + + type-fest@4.26.1: {} + + typed-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + 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 + + typed-array-byte-offset@1.0.2: + 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 + + typed-array-length@1.0.6: + 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 + + typescript@5.5.4: {} + + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + + unbzip2-stream@1.4.3: + dependencies: + buffer: 5.7.1 + through: 2.3.8 + + undici-types@6.19.8: {} + + undici@6.21.0: {} + + universalify@2.0.1: {} + + update-browserslist-db@1.1.1(browserslist@4.24.0): + dependencies: + browserslist: 4.24.0 + escalade: 3.2.0 + picocolors: 1.1.0 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + urlpattern-polyfill@10.0.0: {} + + userhome@1.0.0: {} + + util-deprecate@1.0.2: {} + + v8-compile-cache-lib@3.0.1: {} + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + vite@6.0.5(@types/node@22.7.4)(jiti@1.21.6)(sass@1.79.4)(terser@5.34.1)(tsx@4.19.2)(yaml@2.5.1): + dependencies: + esbuild: 0.24.0 + postcss: 8.4.49 + rollup: 4.24.0 + optionalDependencies: + '@types/node': 22.7.4 + fsevents: 2.3.3 + jiti: 1.21.6 + sass: 1.79.4 + terser: 5.34.1 + tsx: 4.19.2 + yaml: 2.5.1 + + wait-port@1.1.0: + dependencies: + chalk: 4.1.2 + commander: 9.5.0 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + watchpack@2.4.2: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + optional: true + + web-streams-polyfill@3.3.3: {} + + webdriver@9.1.2: + dependencies: + '@types/node': 20.16.10 + '@types/ws': 8.5.13 + '@wdio/config': 9.1.2 + '@wdio/logger': 9.1.0 + '@wdio/protocols': 9.0.8 + '@wdio/types': 9.1.2 + '@wdio/utils': 9.1.2 + deepmerge-ts: 7.1.1 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + webdriver@9.4.4: + dependencies: + '@types/node': 20.16.10 + '@types/ws': 8.5.13 + '@wdio/config': 9.4.4 + '@wdio/logger': 9.4.4 + '@wdio/protocols': 9.4.4 + '@wdio/types': 9.4.4 + '@wdio/utils': 9.4.4 + deepmerge-ts: 7.1.1 + undici: 6.21.0 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + webdriverio@9.1.2: + dependencies: + '@types/node': 20.16.10 + '@types/sinonjs__fake-timers': 8.1.5 + '@wdio/config': 9.1.2 + '@wdio/logger': 9.1.0 + '@wdio/protocols': 9.0.8 + '@wdio/repl': 9.0.8 + '@wdio/types': 9.1.2 + '@wdio/utils': 9.1.2 + archiver: 7.0.1 + aria-query: 5.3.2 + cheerio: 1.0.0 + css-shorthand-properties: 1.1.2 + css-value: 0.0.1 + grapheme-splitter: 1.0.4 + htmlfy: 0.2.1 + import-meta-resolve: 4.1.0 + is-plain-obj: 4.1.0 + jszip: 3.10.1 + lodash.clonedeep: 4.5.0 + lodash.zip: 4.2.0 + minimatch: 9.0.5 + query-selector-shadow-dom: 1.0.1 + resq: 1.11.0 + rgb2hex: 0.2.5 + serialize-error: 11.0.3 + urlpattern-polyfill: 10.0.0 + webdriver: 9.1.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + webdriverio@9.4.5: + dependencies: + '@types/node': 20.16.10 + '@types/sinonjs__fake-timers': 8.1.5 + '@wdio/config': 9.4.4 + '@wdio/logger': 9.4.4 + '@wdio/protocols': 9.4.4 + '@wdio/repl': 9.4.4 + '@wdio/types': 9.4.4 + '@wdio/utils': 9.4.4 + archiver: 7.0.1 + aria-query: 5.3.2 + cheerio: 1.0.0 + css-shorthand-properties: 1.1.2 + css-value: 0.0.1 + grapheme-splitter: 1.0.4 + htmlfy: 0.3.2 + import-meta-resolve: 4.1.0 + is-plain-obj: 4.1.0 + jszip: 3.10.1 + lodash.clonedeep: 4.5.0 + lodash.zip: 4.2.0 + minimatch: 9.0.5 + query-selector-shadow-dom: 1.0.1 + resq: 1.11.0 + rgb2hex: 0.2.5 + serialize-error: 11.0.3 + urlpattern-polyfill: 10.0.0 + webdriver: 9.4.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + webextension-polyfill@0.12.0: {} + + webpack-sources@3.2.3: {} + + webpack@5.94.0(@swc/core@1.9.3)(esbuild@0.23.1): + dependencies: + '@types/estree': 1.0.6 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.12.1 + acorn-import-attributes: 1.9.5(acorn@8.12.1) + browserslist: 4.24.0 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.5.4 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(@swc/core@1.9.3)(esbuild@0.23.1)(webpack@5.94.0(@swc/core@1.9.3)(esbuild@0.23.1)) + watchpack: 2.4.2 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-builtin-type@1.1.4: + 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 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 + + which-typed-array@1.1.15: + 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 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + which@4.0.0: + dependencies: + isexe: 3.1.1 + + which@5.0.0: + dependencies: + isexe: 3.1.1 + + word-wrap@1.2.5: {} + + workerpool@6.5.1: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + ws@8.18.0: {} + + y18n@5.0.8: {} + + yaml@2.5.1: {} + + yargs-parser@20.2.9: {} + + yargs-parser@21.1.1: {} + + yargs-unparser@2.0.0: + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + yocto-queue@1.1.1: {} + + yoctocolors-cjs@2.1.2: {} + + yoctocolors@2.1.1: {} + + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.5.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..86894b4 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +packages: + - "chrome-extension" + - "pages/*" + - "packages/*" + - "tests/*" diff --git a/tests/e2e/config/wdio.browser.conf.ts b/tests/e2e/config/wdio.browser.conf.ts new file mode 100644 index 0000000..dee58cd --- /dev/null +++ b/tests/e2e/config/wdio.browser.conf.ts @@ -0,0 +1,64 @@ +import { config as baseConfig } from './wdio.conf'; +import path from 'node:path'; +import url from 'node:url'; +import fs from 'node:fs/promises'; +import { getChromeExtensionPath, getFirefoxExtensionPath } from '../utils/extension-path'; + +const isFirefox = process.env.__FIREFOX__ === 'true'; +const isCI = process.env.CI === 'true'; +const extName = isFirefox ? '.xpi' : '.zip'; +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +const extensions = await fs.readdir(path.join(__dirname, '../../../dist-zip')); +const latestExtension = extensions + .filter(file => path.extname(file) === extName) + .sort() + .reverse()[0]; +const extPath = path.join(__dirname, `../../../dist-zip/${latestExtension}`); +const bundledExtension = (await fs.readFile(extPath)).toString('base64'); + +const chromeCapabilities = { + browserName: 'chrome', + acceptInsecureCerts: true, + 'goog:chromeOptions': { + args: [ + '--disable-web-security', + '--disable-gpu', + '--no-sandbox', + '--disable-dev-shm-usage', + ...(isCI ? ['--headless'] : []), + ], + prefs: { 'extensions.ui.developer_mode': true }, + extensions: [bundledExtension], + }, +}; + +const firefoxCapabilities = { + browserName: 'firefox', + acceptInsecureCerts: true, + 'moz:firefoxOptions': { + args: [...(isCI ? ['--headless'] : [])], + }, +}; + +export const config: WebdriverIO.Config = { + ...baseConfig, + capabilities: isFirefox ? [firefoxCapabilities] : [chromeCapabilities], + + maxInstances: isCI ? 10 : 1, + logLevel: 'error', + execArgv: isCI ? [] : ['--inspect'], + before: async ({ browserName }: WebdriverIO.Capabilities, _specs, browser: WebdriverIO.Browser) => { + if (browserName === 'firefox') { + await browser.installAddOn(bundledExtension, true); + + browser.addCommand('getExtensionPath', async () => getFirefoxExtensionPath(browser)); + } else if (browserName === 'chrome') { + browser.addCommand('getExtensionPath', async () => getChromeExtensionPath(browser)); + } + }, + afterTest: async () => { + if (!isCI) { + await browser.pause(500); + } + }, +}; diff --git a/tests/e2e/config/wdio.conf.ts b/tests/e2e/config/wdio.conf.ts new file mode 100644 index 0000000..2567bb6 --- /dev/null +++ b/tests/e2e/config/wdio.conf.ts @@ -0,0 +1,97 @@ +/** + * WebdriverIO v9 configuration file + * https://webdriver.io/docs/configurationfile + */ +export const config: WebdriverIO.Config = { + runner: 'local', + tsConfigPath: '../tsconfig.json', + + // + // ================== + // Specify Test Files + // ================== + // Define which test specs should run. The pattern is relative to the directory + // of the configuration file being run. + // + // The specs are defined as an array of spec files (optionally using wildcards + // that will be expanded). The test for each spec file will be run in a separate + // worker process. In order to have a group of spec files run in the same worker + // process simply enclose them in an array within the specs array. + // + // The path of the spec files will be resolved relative from the directory + // of the config file unless it's absolute. + specs: ['../specs/**/*.ts'], + // Patterns to exclude. + exclude: [], + // + // ============ + // Capabilities + // ============ + // Define your capabilities here. WebdriverIO can run multiple capabilities at the same + // time. Depending on the number of capabilities, WebdriverIO launches several test + // sessions. Within your capabilities you can overwrite the spec and exclude options in + // order to group specific specs to a specific capability. + // + // First, you can define how many instances should be started at the same time. Let's + // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have + // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec + // files and you set maxInstances to 10, all spec files will get tested at the same time + // and 30 processes will get spawned. The property handles how many capabilities + // from the same test should run tests. + // + maxInstances: 10, + // + // If you have trouble getting all important capabilities together, check out the + // Sauce Labs platform configurator - a great tool to configure your capabilities: + // https://saucelabs.com/platform/platform-configurator + // + capabilities: [], + + // + // =================== + // Test Configurations + // =================== + // Define all options that are relevant for the WebdriverIO instance here + // + // Level of logging verbosity: trace | debug | info | warn | error | silent + logLevel: 'info', + + // + // If you only want to run your tests until a specific amount of tests have failed use + // bail (default is 0 - don't bail, run all tests). + bail: 0, + // + // Default timeout for all waitFor* commands. + waitforTimeout: 10000, + + // + // Default timeout in milliseconds for request + // if browser driver or grid doesn't send response + connectionRetryTimeout: 120000, + + // + // Default request retries count + connectionRetryCount: 3, + + // + // Framework you want to run your specs with. + // The following are supported: Mocha, Jasmine, and Cucumber + // see also: https://webdriver.io/docs/frameworks + // + // Make sure you have the wdio adapter package for the specific framework installed + // before running any tests. + framework: 'mocha', + + // + // Test reporter for stdout. + // The only one supported by default is 'dot' + // see also: https://webdriver.io/docs/dot-reporter + reporters: ['spec'], + + // Options to be passed to Mocha. + // See the full list at http://mochajs.org/ + mochaOpts: { + ui: 'bdd', + timeout: 60000, + }, +}; diff --git a/tests/e2e/config/wdio.d.ts b/tests/e2e/config/wdio.d.ts new file mode 100644 index 0000000..8dbebe4 --- /dev/null +++ b/tests/e2e/config/wdio.d.ts @@ -0,0 +1,7 @@ +declare namespace WebdriverIO { + interface Browser extends WebdriverIO.Browser { + getExtensionPath: () => Promise; + installAddOn: (extension: string, temporary: boolean) => Promise; + addCommand: (name: string, func: () => Promise) => void; + } +} diff --git a/tests/e2e/helpers/theme.ts b/tests/e2e/helpers/theme.ts new file mode 100644 index 0000000..9dfd6c1 --- /dev/null +++ b/tests/e2e/helpers/theme.ts @@ -0,0 +1,26 @@ +/** + * Helper method to check if user can click on theme button and toggle theme color + */ +export const canSwitchTheme = async () => { + const LIGHT_THEME_CLASS = 'bg-slate-50'; + const DARK_THEME_CLASS = 'bg-gray-800'; + const TOGGLE_BUTTON_TEXT = 'Toggle theme'; + + const app = await $('.App').getElement(); + const toggleThemeButton = await $(`button=${TOGGLE_BUTTON_TEXT}`).getElement(); + + await expect(app).toBeExisting(); + await expect(toggleThemeButton).toBeExisting(); + + const appClasses = await app.getAttribute('class'); + const initialThemeClass = appClasses.includes(LIGHT_THEME_CLASS) ? LIGHT_THEME_CLASS : DARK_THEME_CLASS; + const afterClickThemeClass = appClasses.includes(LIGHT_THEME_CLASS) ? DARK_THEME_CLASS : LIGHT_THEME_CLASS; + + // Toggle theme + await toggleThemeButton.click(); + await expect(app).toHaveElementClass(afterClickThemeClass); + + // Toggle back to initial theme + await toggleThemeButton.click(); + await expect(app).toHaveElementClass(initialThemeClass); +}; diff --git a/tests/e2e/package.json b/tests/e2e/package.json new file mode 100644 index 0000000..232f203 --- /dev/null +++ b/tests/e2e/package.json @@ -0,0 +1,23 @@ +{ + "name": "@extension/e2e", + "version": "0.3.5", + "description": "E2e tests configuration boilerplate", + "private": true, + "type": "module", + "scripts": { + "e2e": "wdio run ./config/wdio.browser.conf.ts", + "clean:node_modules": "pnpx rimraf node_modules", + "clean:turbo": "pnpx rimraf .turbo", + "clean": "pnpm clean:turbo && pnpm clean:node_modules" + }, + "devDependencies": { + "@extension/tsconfig": "workspace:*", + "@wdio/cli": "^9.4.5", + "@wdio/globals": "^9.4.5", + "@wdio/local-runner": "^9.1.2", + "@wdio/mocha-framework": "^9.1.2", + "@wdio/spec-reporter": "^9.2.14", + "@wdio/types": "^9.1.2", + "tsx": "^4.19.2" + } +} diff --git a/tests/e2e/specs/page-content-runtime.test.ts b/tests/e2e/specs/page-content-runtime.test.ts new file mode 100644 index 0000000..7706751 --- /dev/null +++ b/tests/e2e/specs/page-content-runtime.test.ts @@ -0,0 +1,28 @@ +describe('Webextension Content Runtime Script', () => { + before(function () { + if ((browser.capabilities as WebdriverIO.Capabilities).browserName === 'chrome') { + // Chrome doesn't allow content scripts on the extension pages + this.skip(); + } + }); + + it('should create runtime element on the page', async () => { + // Open the popup + const extensionPath = await browser.getExtensionPath(); + const popupUrl = `${extensionPath}/popup/index.html`; + await browser.url(popupUrl); + + await expect(browser).toHaveTitle('Popup'); + + // Trigger the content script on the popup + // button contains "Content Script" text + const contentScriptButton = await $('button*=Content Script').getElement(); + + await contentScriptButton.click(); + + // Check if id chrome-extension-boilerplate-react-vite-runtime-content-view-root exists on page + const runtimeElement = await $('#chrome-extension-boilerplate-react-vite-runtime-content-view-root').getElement(); + + await expect(runtimeElement).toBeExisting(); + }); +}); diff --git a/tests/e2e/specs/page-content-ui.test.ts b/tests/e2e/specs/page-content-ui.test.ts new file mode 100644 index 0000000..50fbb13 --- /dev/null +++ b/tests/e2e/specs/page-content-ui.test.ts @@ -0,0 +1,8 @@ +describe('Content UI Injection', () => { + it('should locate the injected content UI div', async () => { + await browser.url('https://www.example.com'); + + const contentDiv = await $('#chrome-extension-boilerplate-react-vite-content-view-root').getElement(); + await expect(contentDiv).toBeDisplayed(); + }); +}); diff --git a/tests/e2e/specs/page-content.test.ts b/tests/e2e/specs/page-content.test.ts new file mode 100644 index 0000000..3fda55d --- /dev/null +++ b/tests/e2e/specs/page-content.test.ts @@ -0,0 +1,17 @@ +describe('Webextension Content Script', () => { + it('should log "content script loaded" in console', async () => { + await browser.sessionSubscribe({ events: ['log.entryAdded'] }); + const logs: (string | null)[] = []; + + browser.on('log.entryAdded', logEntry => { + logs.push(logEntry.text); + }); + + await browser.url('https://www.example.com'); + + const EXPECTED_LOG_MESSAGE = 'content script loaded'; + await browser.waitUntil(() => logs.includes(EXPECTED_LOG_MESSAGE)); + + expect(logs).toContain(EXPECTED_LOG_MESSAGE); + }); +}); diff --git a/tests/e2e/specs/page-dev-tools.test.ts b/tests/e2e/specs/page-dev-tools.test.ts new file mode 100644 index 0000000..1fe29e6 --- /dev/null +++ b/tests/e2e/specs/page-dev-tools.test.ts @@ -0,0 +1,12 @@ +import { canSwitchTheme } from '../helpers/theme'; + +describe('Webextension DevTools Panel', () => { + it('should make DevTools panel available', async () => { + const extensionPath = await browser.getExtensionPath(); + const devtoolsPanelUrl = `${extensionPath}/devtools-panel/index.html`; + + await browser.url(devtoolsPanelUrl); + await expect(browser).toHaveTitle('Devtools Panel'); + await canSwitchTheme(); + }); +}); diff --git a/tests/e2e/specs/page-new-tab.test.ts b/tests/e2e/specs/page-new-tab.test.ts new file mode 100644 index 0000000..a7ab69c --- /dev/null +++ b/tests/e2e/specs/page-new-tab.test.ts @@ -0,0 +1,14 @@ +import { canSwitchTheme } from '../helpers/theme'; + +describe('Webextension New Tab', () => { + it('should open the extension page when a new tab is opened', async () => { + const extensionPath = await browser.getExtensionPath(); + const newTabUrl = process.env.__FIREFOX__ === 'true' ? `${extensionPath}/new-tab/index.html` : 'chrome://newtab'; + + await browser.url(newTabUrl); + + const appDiv = await $('.App').getElement(); + await expect(appDiv).toBeExisting(); + await canSwitchTheme(); + }); +}); diff --git a/tests/e2e/specs/page-options.test.ts b/tests/e2e/specs/page-options.test.ts new file mode 100644 index 0000000..16f1497 --- /dev/null +++ b/tests/e2e/specs/page-options.test.ts @@ -0,0 +1,13 @@ +import { canSwitchTheme } from '../helpers/theme'; + +describe('Webextension Options Page', () => { + it('should make options page accessible', async () => { + const extensionPath = await browser.getExtensionPath(); + const optionsUrl = `${extensionPath}/options/index.html`; + + await browser.url(optionsUrl); + + await expect(browser).toHaveTitle('Options'); + await canSwitchTheme(); + }); +}); diff --git a/tests/e2e/specs/page-popup.test.ts b/tests/e2e/specs/page-popup.test.ts new file mode 100644 index 0000000..9128db1 --- /dev/null +++ b/tests/e2e/specs/page-popup.test.ts @@ -0,0 +1,12 @@ +import { canSwitchTheme } from '../helpers/theme'; + +describe('Webextension Popup', () => { + it('should open the popup successfully', async () => { + const extensionPath = await browser.getExtensionPath(); + const popupUrl = `${extensionPath}/popup/index.html`; + await browser.url(popupUrl); + + await expect(browser).toHaveTitle('Popup'); + await canSwitchTheme(); + }); +}); diff --git a/tests/e2e/specs/page-side-panel.test.ts b/tests/e2e/specs/page-side-panel.test.ts new file mode 100644 index 0000000..0f33ac5 --- /dev/null +++ b/tests/e2e/specs/page-side-panel.test.ts @@ -0,0 +1,12 @@ +import { canSwitchTheme } from '../helpers/theme'; + +describe('Webextension Side Panel', () => { + it('should make side panel accessible', async () => { + const extensionPath = await browser.getExtensionPath(); + const sidePanelUrl = `${extensionPath}/side-panel/index.html`; + + await browser.url(sidePanelUrl); + await expect(browser).toHaveTitle('Side Panel'); + await canSwitchTheme(); + }); +}); diff --git a/tests/e2e/specs/smoke.test.ts b/tests/e2e/specs/smoke.test.ts new file mode 100644 index 0000000..ba2d9ac --- /dev/null +++ b/tests/e2e/specs/smoke.test.ts @@ -0,0 +1,7 @@ +describe('The example page can be loaded', () => { + it('should be able to go to example page', async () => { + await browser.url('https://www.example.com'); + + await expect(browser).toHaveTitle('Example Domain'); + }); +}); diff --git a/tests/e2e/tsconfig.json b/tests/e2e/tsconfig.json new file mode 100644 index 0000000..1778b50 --- /dev/null +++ b/tests/e2e/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "@extension/tsconfig/utils", + "compilerOptions": { + "moduleResolution": "node", + "module": "ESNext", + "target": "es2022", + "lib": ["es2022", "dom"], + "types": ["node", "@wdio/globals/types", "@wdio/mocha-framework"], + "resolveJsonModule": true, + "isolatedModules": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["specs", "config", "helpers"] +} diff --git a/tests/e2e/utils/extension-path.ts b/tests/e2e/utils/extension-path.ts new file mode 100644 index 0000000..47af370 --- /dev/null +++ b/tests/e2e/utils/extension-path.ts @@ -0,0 +1,49 @@ +/** + * Returns the Chrome extension path. + * @param browser + * @returns path to the Chrome extension + */ +export const getChromeExtensionPath = async (browser: WebdriverIO.Browser) => { + await browser.url('chrome://extensions/'); + /** + * https://webdriver.io/docs/extension-testing/web-extensions/#test-popup-modal-in-chrome + * ```ts + * const extensionItem = await $('extensions-item').getElement(); + * ``` + * The above code is not working. I guess it's because the shadow root is not accessible. + * So I used the following code to access the shadow root manually. + * + * @url https://github.com/webdriverio/webdriverio/issues/13521 + * @url https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/786 + */ + const extensionItem = await (async () => { + const extensionsManager = await $('extensions-manager').getElement(); + const itemList = await extensionsManager.shadow$('#container > #viewManager > extensions-item-list'); + return await itemList.shadow$('extensions-item'); + })(); + + const extensionId = await extensionItem.getAttribute('id'); + + if (!extensionId) { + throw new Error('Extension ID not found'); + } + + return `chrome-extension://${extensionId}`; +}; + +/** + * Returns the Firefox extension path. + * @param browser + * @returns path to the Firefox extension + */ +export const getFirefoxExtensionPath = async (browser: WebdriverIO.Browser) => { + await browser.url('about:debugging#/runtime/this-firefox'); + const uuidElement = await browser.$('//dt[contains(text(), "Internal UUID")]/following-sibling::dd').getElement(); + const internalUUID = await uuidElement.getText(); + + if (!internalUUID) { + throw new Error('Internal UUID not found'); + } + + return `moz-extension://${internalUUID}`; +}; diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..6a346bd --- /dev/null +++ b/turbo.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://turbo.build/schema.json", + "ui": "tui", + "globalEnv": ["__FIREFOX__"], + "daemon": false, + "tasks": { + "ready": { + "dependsOn": ["^ready"], + "outputs": ["dist/**", "build/**"] + }, + "dev": { + "dependsOn": ["ready"], + "outputs": ["dist/**", "build/**", "i18n/locales/**"], + "cache": false, + "persistent": true + }, + "build": { + "dependsOn": ["^build"], + "outputs": ["../../dist/**", "dist/**", "build/**"], + "cache": false + }, + "e2e": { + "cache": false + }, + "type-check": { + "cache": false + }, + "lint": { + "cache": false + }, + "lint:fix": { + "cache": false + }, + "prettier": { + "cache": false + }, + "clean:node_modules": { + "dependsOn": ["^clean:node_modules"], + "cache": false + }, + "clean:turbo": { + "dependsOn": ["^clean:turbo"], + "cache": false + }, + "clean:bundle": { + "dependsOn": ["^clean:bundle"], + "cache": false + }, + "clean": { + "dependsOn": ["^clean"], + "cache": false + } + } +} diff --git a/update_version.sh b/update_version.sh new file mode 100755 index 0000000..3bee333 --- /dev/null +++ b/update_version.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Usage: ./update_version.sh +# FORMAT IS <0.0.0> + +if [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + find . -name 'package.json' -not -path '*/node_modules/*' -exec bash -c ' + # Parse the version from package.json + current_version=$(grep -o "\"version\": \"[^\"]*" "$0" | cut -d"\"" -f4) + + # Update the version + perl -i -pe"s/$current_version/'$1'/" "$0" + ' {} \; + + echo "Updated versions to $1"; +else + echo "Version format <$1> isn't correct, proper format is <0.0.0>"; +fi diff --git a/vite-env.d.ts b/vite-env.d.ts new file mode 100644 index 0000000..1a43b1b --- /dev/null +++ b/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +interface ImportMetaEnv { + readonly VITE_EXAMPLE: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +}