From ac4b4a8e6fe7bc94e8a0016473f2d8bae9a5dba9 Mon Sep 17 00:00:00 2001 From: Nexmoe <16796652+nexmoe@users.noreply.github.com> Date: Thu, 23 Oct 2025 21:31:54 +0800 Subject: [PATCH] chore: add initial project configuration and structure --- .editorconfig | 10 + .gitattributes | 6 +- .github/workflows/ci.yml | 37 + .github/workflows/release.yml | 91 + .gitignore | 7 + .npmrc | 4 + .vscode/extensions.json | 3 + .vscode/settings.json | 29 + AGENTS.md | 5 + biome.json | 49 + components.json | 21 + dev-app-update.yml | 3 + electron-builder.yml | 40 + electron.vite.config.ts | 40 + entitlements.mac.plist | 12 + icon.icns | Bin 0 -> 85649 bytes icon.ico | Bin 0 -> 10827 bytes icon.png | Bin 0 -> 14607 bytes package.json | 87 + pnpm-lock.yaml | 6621 +++++++++++++++++ resources/.gitignore | 9 + resources/README.md | 55 + resources/icon.png | Bin 0 -> 14607 bytes src/main/assets.d.ts | 36 + src/main/download-engine.ts | 1091 +++ src/main/index.ts | 230 + src/main/ipc/index.ts | 24 + src/main/ipc/services/app-service.ts | 37 + src/main/ipc/services/download-service.ts | 53 + src/main/ipc/services/file-system-service.ts | 176 + src/main/ipc/services/history-service.ts | 315 + src/main/ipc/services/settings-service.ts | 43 + src/main/ipc/services/thumbnail-service.ts | 20 + src/main/ipc/services/update-service.ts | 57 + src/main/ipc/services/window-service.ts | 42 + src/main/lib/download-queue.ts | 145 + src/main/lib/history-manager.ts | 116 + src/main/lib/thumbnail-cache.ts | 137 + src/main/lib/ytdlp-manager.ts | 121 + src/main/settings.ts | 51 + src/main/tray.ts | 138 + src/preload/index.d.ts | 13 + src/preload/index.ts | 45 + src/renderer/index.html | 16 + src/renderer/public/app-icon.png | Bin 0 -> 14607 bytes src/renderer/src/App.tsx | 65 + src/renderer/src/assets/app-icon.png | Bin 0 -> 14607 bytes src/renderer/src/assets/global.css | 12 + src/renderer/src/assets/main.css | 23 + src/renderer/src/assets/theme.css | 160 + src/renderer/src/assets/title-bar.css | 10 + .../src/components/download/DownloadItem.tsx | 418 ++ .../download/UnifiedDownloadHistory.tsx | 114 + src/renderer/src/components/ui/accordion.tsx | 61 + src/renderer/src/components/ui/badge.tsx | 36 + src/renderer/src/components/ui/button.tsx | 48 + src/renderer/src/components/ui/card.tsx | 54 + src/renderer/src/components/ui/checkbox.tsx | 26 + src/renderer/src/components/ui/dialog.tsx | 101 + .../src/components/ui/dropdown-menu.tsx | 225 + .../components/ui/image-with-placeholder.tsx | 67 + src/renderer/src/components/ui/input.tsx | 21 + src/renderer/src/components/ui/item.tsx | 182 + src/renderer/src/components/ui/label.tsx | 18 + src/renderer/src/components/ui/progress.tsx | 25 + .../src/components/ui/scroll-area.tsx | 53 + src/renderer/src/components/ui/select.tsx | 149 + src/renderer/src/components/ui/separator.tsx | 25 + src/renderer/src/components/ui/sidebar.tsx | 207 + src/renderer/src/components/ui/sonner.tsx | 27 + src/renderer/src/components/ui/switch.tsx | 26 + src/renderer/src/components/ui/tabs.tsx | 53 + src/renderer/src/components/ui/textarea.tsx | 17 + src/renderer/src/components/ui/title-bar.tsx | 79 + src/renderer/src/components/ui/tooltip.tsx | 56 + .../src/components/video/AdvancedOptions.tsx | 100 + .../src/components/video/AudioExtractor.tsx | 87 + .../src/components/video/FormatSelector.tsx | 225 + .../src/components/video/VideoInfoCard.tsx | 231 + src/renderer/src/data/popularSites.ts | 98 + src/renderer/src/env.d.ts | 2 + .../src/hooks/use-cached-thumbnail.ts | 41 + src/renderer/src/hooks/use-history-sync.ts | 36 + src/renderer/src/hooks/use-ipc-example.ts | 129 + src/renderer/src/i18n.ts | 18 + src/renderer/src/lib/ipc.ts | 45 + src/renderer/src/lib/utils.ts | 6 + src/renderer/src/locales/en.json | 293 + src/renderer/src/locales/zh.json | 282 + src/renderer/src/main.tsx | 17 + src/renderer/src/pages/About.tsx | 285 + src/renderer/src/pages/Home.tsx | 662 ++ src/renderer/src/pages/Settings.tsx | 341 + src/renderer/src/pages/SupportedSites.tsx | 58 + src/renderer/src/store/downloads.ts | 177 + src/renderer/src/store/settings.ts | 45 + src/renderer/src/store/video.ts | 35 + src/shared/types/index.ts | 175 + src/shared/types/ipc.ts | 2 + tsconfig.json | 13 + tsconfig.node.json | 15 + tsconfig.web.json | 23 + 102 files changed, 15832 insertions(+), 2 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 AGENTS.md create mode 100644 biome.json create mode 100644 components.json create mode 100644 dev-app-update.yml create mode 100644 electron-builder.yml create mode 100644 electron.vite.config.ts create mode 100644 entitlements.mac.plist create mode 100644 icon.icns create mode 100644 icon.ico create mode 100644 icon.png create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 resources/.gitignore create mode 100644 resources/README.md create mode 100644 resources/icon.png create mode 100644 src/main/assets.d.ts create mode 100644 src/main/download-engine.ts create mode 100644 src/main/index.ts create mode 100644 src/main/ipc/index.ts create mode 100644 src/main/ipc/services/app-service.ts create mode 100644 src/main/ipc/services/download-service.ts create mode 100644 src/main/ipc/services/file-system-service.ts create mode 100644 src/main/ipc/services/history-service.ts create mode 100644 src/main/ipc/services/settings-service.ts create mode 100644 src/main/ipc/services/thumbnail-service.ts create mode 100644 src/main/ipc/services/update-service.ts create mode 100644 src/main/ipc/services/window-service.ts create mode 100644 src/main/lib/download-queue.ts create mode 100644 src/main/lib/history-manager.ts create mode 100644 src/main/lib/thumbnail-cache.ts create mode 100644 src/main/lib/ytdlp-manager.ts create mode 100644 src/main/settings.ts create mode 100644 src/main/tray.ts create mode 100644 src/preload/index.d.ts create mode 100644 src/preload/index.ts create mode 100644 src/renderer/index.html create mode 100644 src/renderer/public/app-icon.png create mode 100644 src/renderer/src/App.tsx create mode 100644 src/renderer/src/assets/app-icon.png create mode 100644 src/renderer/src/assets/global.css create mode 100644 src/renderer/src/assets/main.css create mode 100644 src/renderer/src/assets/theme.css create mode 100644 src/renderer/src/assets/title-bar.css create mode 100644 src/renderer/src/components/download/DownloadItem.tsx create mode 100644 src/renderer/src/components/download/UnifiedDownloadHistory.tsx create mode 100644 src/renderer/src/components/ui/accordion.tsx create mode 100644 src/renderer/src/components/ui/badge.tsx create mode 100644 src/renderer/src/components/ui/button.tsx create mode 100644 src/renderer/src/components/ui/card.tsx create mode 100644 src/renderer/src/components/ui/checkbox.tsx create mode 100644 src/renderer/src/components/ui/dialog.tsx create mode 100644 src/renderer/src/components/ui/dropdown-menu.tsx create mode 100644 src/renderer/src/components/ui/image-with-placeholder.tsx create mode 100644 src/renderer/src/components/ui/input.tsx create mode 100644 src/renderer/src/components/ui/item.tsx create mode 100644 src/renderer/src/components/ui/label.tsx create mode 100644 src/renderer/src/components/ui/progress.tsx create mode 100644 src/renderer/src/components/ui/scroll-area.tsx create mode 100644 src/renderer/src/components/ui/select.tsx create mode 100644 src/renderer/src/components/ui/separator.tsx create mode 100644 src/renderer/src/components/ui/sidebar.tsx create mode 100644 src/renderer/src/components/ui/sonner.tsx create mode 100644 src/renderer/src/components/ui/switch.tsx create mode 100644 src/renderer/src/components/ui/tabs.tsx create mode 100644 src/renderer/src/components/ui/textarea.tsx create mode 100644 src/renderer/src/components/ui/title-bar.tsx create mode 100644 src/renderer/src/components/ui/tooltip.tsx create mode 100644 src/renderer/src/components/video/AdvancedOptions.tsx create mode 100644 src/renderer/src/components/video/AudioExtractor.tsx create mode 100644 src/renderer/src/components/video/FormatSelector.tsx create mode 100644 src/renderer/src/components/video/VideoInfoCard.tsx create mode 100644 src/renderer/src/data/popularSites.ts create mode 100644 src/renderer/src/env.d.ts create mode 100644 src/renderer/src/hooks/use-cached-thumbnail.ts create mode 100644 src/renderer/src/hooks/use-history-sync.ts create mode 100644 src/renderer/src/hooks/use-ipc-example.ts create mode 100644 src/renderer/src/i18n.ts create mode 100644 src/renderer/src/lib/ipc.ts create mode 100644 src/renderer/src/lib/utils.ts create mode 100644 src/renderer/src/locales/en.json create mode 100644 src/renderer/src/locales/zh.json create mode 100644 src/renderer/src/main.tsx create mode 100644 src/renderer/src/pages/About.tsx create mode 100644 src/renderer/src/pages/Home.tsx create mode 100644 src/renderer/src/pages/Settings.tsx create mode 100644 src/renderer/src/pages/SupportedSites.tsx create mode 100644 src/renderer/src/store/downloads.ts create mode 100644 src/renderer/src/store/settings.ts create mode 100644 src/renderer/src/store/video.ts create mode 100644 src/shared/types/index.ts create mode 100644 src/shared/types/ipc.ts create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 tsconfig.web.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5e3dca4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + diff --git a/.gitattributes b/.gitattributes index dfe0770..a136674 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ -# Auto detect text files and perform LF normalization -* text=auto +* text=auto eol=lf +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..dcad9ba --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + + - name: Install Dependencies + run: pnpm install + + - name: Type check + run: pnpm run typecheck + + - name: Lint and format check + run: pnpm run check + + - name: Build check + run: pnpm run build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6932a5c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,91 @@ +name: Build and Release Electron App + +on: + push: + tags: + - v*.*.* + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + + - name: Install Dependencies + run: pnpm install + + - name: Type check + run: pnpm run typecheck + + - name: Lint and format check + run: pnpm run check + + - name: Build Electron app + run: | + if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then + pnpm run build:linux + elif [ "${{ matrix.os }}" == "macos-latest" ]; then + pnpm run build:mac + elif [ "${{ matrix.os }}" == "windows-latest" ]; then + pnpm run build:win + fi + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: dist-${{ matrix.os }} + path: dist/ + + release: + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: dist/ + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + draft: false + prerelease: false + generate_release_notes: true + files: | + dist-ubuntu-latest/*.AppImage + dist-ubuntu-latest/*.snap + dist-ubuntu-latest/*.deb + dist-ubuntu-latest/*.rpm + dist-ubuntu-latest/*.tar.gz + dist-ubuntu-latest/*.yml + dist-ubuntu-latest/*.blockmap + dist-macos-latest/*.dmg + dist-macos-latest/*.zip + dist-macos-latest/*.yml + dist-macos-latest/*.blockmap + dist-windows-latest/*.exe + dist-windows-latest/*.zip + dist-windows-latest/*.yml + dist-windows-latest/*.blockmap diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52fdc63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules +dist +out +.DS_Store +.eslintcache +*.log* + diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..e16e2b8 --- /dev/null +++ b/.npmrc @@ -0,0 +1,4 @@ +electron_mirror=https://npmmirror.com/mirrors/electron/ +electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/ +shamefully-hoist=true + diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..d81f6d9 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["biomejs.biome", "bradlc.vscode-tailwindcss"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..419c9f3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,29 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "biomejs.biome", + "editor.codeActionsOnSave": { + "source.fixAll.biome": "explicit" + }, + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "typescript.tsdk": "node_modules/typescript/lib", + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], + ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] + ], + "i18n-ally.localesPaths": ["src/renderer/src/locales"], + "i18n-ally.keystyle": "nested" +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..daaec16 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,5 @@ +1. use pnpm instead of npm +2. use pnpm run check after tasks to check code +3. Support i18n, only translate the English version of en.json +4. use English for comments&console +5. Follow the ✅ KISS (Keep It Simple, Stupid) & ✅ YAGNI (You Aren't Gonna Need It) principles diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..bc68ee5 --- /dev/null +++ b/biome.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "useExhaustiveDependencies": "warn" + }, + "suspicious": { + "noExplicitAny": "warn" + }, + "style": { + "useConst": "error" + }, + "complexity": { + "noForEach": "off" + } + } + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 100, + "lineEnding": "lf" + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "semicolons": "asNeeded", + "trailingCommas": "none", + "bracketSpacing": true, + "bracketSameLine": false, + "arrowParentheses": "always", + "quoteProperties": "asNeeded" + } + }, + "files": { + "ignoreUnknown": false, + "includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.json"] + }, + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + } +} diff --git a/components.json b/components.json new file mode 100644 index 0000000..7881819 --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/renderer/src/assets/global.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@renderer/components", + "utils": "@renderer/lib/utils", + "ui": "@renderer/components/ui", + "lib": "@renderer/lib", + "hooks": "@renderer/hooks" + }, + "iconLibrary": "lucide" +} diff --git a/dev-app-update.yml b/dev-app-update.yml new file mode 100644 index 0000000..b1e17ed --- /dev/null +++ b/dev-app-update.yml @@ -0,0 +1,3 @@ +provider: generic +url: https://github.com/nexmoe/vidbee/releases/latest/download +updaterCacheDirName: vidbee-updater diff --git a/electron-builder.yml b/electron-builder.yml new file mode 100644 index 0000000..e998472 --- /dev/null +++ b/electron-builder.yml @@ -0,0 +1,40 @@ +appId: com.vidbee +productName: VidBee +directories: + buildResources: build +files: + - '!**/.vscode/*' + - '!src/*' + - '!electron.vite.config.{js,ts,mjs,cjs}' + - '!{.eslintcache,eslint.config.mjs,dev-app-update.yml,CHANGELOG.md}' + - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' + - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' +asarUnpack: + - resources/** +win: + executableName: vidbee +nsis: + artifactName: ${name}-${version}-setup.${ext} + shortcutName: ${productName} + uninstallDisplayName: ${productName} + createDesktopShortcut: always +mac: + entitlementsInherit: build/entitlements.mac.plist + notarize: false +dmg: + artifactName: ${name}-${version}.${ext} +linux: + target: + - AppImage + - snap + - deb + maintainer: yourname@example.com + category: Utility +appImage: + artifactName: ${name}-${version}.${ext} +npmRebuild: false +publish: + provider: generic + url: https://github.com/nexmoe/vidbee/releases/latest/download +electronDownload: + mirror: https://npmmirror.com/mirrors/electron/ diff --git a/electron.vite.config.ts b/electron.vite.config.ts new file mode 100644 index 0000000..5bf6f42 --- /dev/null +++ b/electron.vite.config.ts @@ -0,0 +1,40 @@ +import { resolve } from 'node:path' +import tailwindcss from '@tailwindcss/vite' +import react from '@vitejs/plugin-react' +import { defineConfig, externalizeDepsPlugin } from 'electron-vite' +import Icons from 'unplugin-icons/vite' + +export default defineConfig({ + main: { + plugins: [externalizeDepsPlugin()], + resolve: { + alias: { + '@main': resolve('src/main'), + '@shared': resolve('src/shared') + } + }, + assetsInclude: ['**/*.png', '**/*.ico', '**/*.icns'], + publicDir: 'build' + }, + preload: { + plugins: [externalizeDepsPlugin()] + }, + renderer: { + base: './', + resolve: { + alias: { + '@main': resolve('src/main'), + '@renderer': resolve('src/renderer/src'), + '@shared': resolve('src/shared') + } + }, + plugins: [ + react(), + Icons({ + compiler: 'jsx', + jsx: 'react' + }), + tailwindcss() + ] + } +}) diff --git a/entitlements.mac.plist b/entitlements.mac.plist new file mode 100644 index 0000000..38c887b --- /dev/null +++ b/entitlements.mac.plist @@ -0,0 +1,12 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.allow-dyld-environment-variables + + + diff --git a/icon.icns b/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..28644aa9d97942c50008d03bc0f93505f7824737 GIT binary patch literal 85649 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

-KY5Dg)0#~?~rEbJH_9`n*G*i+1Ec#;TIAa-b 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 literal 0 HcmV?d00001 diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..1a28eb3bea10742433362548a904b5450a3f9f1c GIT binary patch literal 10827 zcmX9^2{e@7`+sL+>|@{eHA@H)#n`e`maHXP_OkE7EcU3crASmLLS(Oq%viD{St7d` zQr4J}Wn#?y{m%cr=RNnn=RWtj%X#nfeD3GD0025o|9e1y1fZn|0DPzA`!-f)Y|KK; zr$sgkbCc`;tNq^#XE@Dng;)9h?<*wS${sZGGNuRs&g@v27~03q{&~(6Ywu9dFJAnz zwI%bybCZ!xIKf6*LzMM?zJ_zGEStD9UpF(a->P8;@TutIH} z{9sT1h#r9<7Wtx8E*n@YCJ{e{WI!->eB14ox)DsFcTXKQK5MAk`f1M8$=L1PgxONN zFZMQ5UklnBTwt1=UoKWi$j1)rc+pl@jeEjAz}=fd@nV+4tZy`)QTyaT`8kPJTtY$wV}ZyBQFM=fE?S z{+PNQ@}POsf~x;|R#c@H0iJJ|KfrPqWuF5j7Kreyc9{6pQHO!`mj#XN% z-!I_+mhfCee&W@5c&C1)hS9Vv^T}LZ7V=Ea(6EFyRlSsD4zctft5jShGCMPMqLI&ivJFxXjsS`T{%Y8n4V!>HVD)3}XvWr`st)M-~8 zXYks7DPHG^X{teL1m84t&*#F@LhM7lt6I64WQ{%_MX~Xts?%O2DAkf*-~FVTR4Hdg z{?pq*^6LV0!?>prrU8b>Z;#5xt83vGMyx-~vzCVhWN#%q- zuI|ezu{sV&GM1pi-~SjjTvRNNB=+_0xc#f4*e>K$B9U_wiV3=;SAwM2T?GVvm|8A5 z2@OV410=T}#Y>KK`C(^2XZI)Gt=_a&s$?gC$%Jm<^Z{tyrLDtfix4t>_)xy(6vUTw@hQ7wy2CEj+=_Cq{R`x^$G%!gEdYMs@i7r~zsimFVu;Gu(${EMjlzb1^ z4bXQ!5swVnXOc#VP;9S23_95P?A70Pdn!H&=cN-|pp@o|Gk}6<6=AMq`$b=|*!b|m zN{@+=*r93CKA(;O2wm6j$k?3cEg@U@-1+WuvICEsw+cX}-=Bh;f`y=qb7B7yh5r!a;aTK2OX+w0(RBJY1qVYntl8gvu&4nRr8Jl^-zcsp`2`k zy8uCs%ABga0P5yg`Z++h0;`Bg*BwM2RisCP%9IhdR32Kq0kyvaCkv@+DV`*)4l;7b zrtm`zHtR1z@DV5Z0STB&!K(ikoB_gnrpa0=W&owxX|N=Kvk*W0LO8R z+8@i*c4W6tIJTcHt_MAq5uTigumwSfT#|EV11Qy)e4O&+1Sc!;?ZL;itRnQp;J?5O zaFGQ>@%r!`jRjRn=GKvjuxgSu&1w2izchvp`Y%HfwRmhjY|yEWt+nag$(}>)*U$@( zYe@gWo~i0!g9Lj+B*&5U2K7gTt?mzWUA{HF`(e1jznki^0z& z#X7m?FD%deRpp)m9^c#J@A2Z{n3Ut`*DMI!kl6B+ymg{u(Y{&SOsKieGech{5@*oc2+2C*^Q!d=+ON&Fh@?%PL z%OSctR~K{Jm*drUMk)e$fdh;3-X`N-bztDQ;%{|AAHja?bA8JRni^7#bNw-KMpsjX zt5k|2a+P=%wNME6gHnE!bQ}>_5^7)&oAEodHz7L445d7ZSmdG@^#lQWPs=lkBXgv1 zLhbLLMOEz6r`|6EY_9?SssIa%-sbtyZ$^;}j-F)I;R&W*&dStD_p^ZFW@@+VeP51| zX%!jW&sq$rCk1ApJJyi-CAu+wC{(!?}Koc`_6JbCA*>pt< z-FM^N0+S7@HrlZHyHDxyCdFjy4|GIOlW>mk>(x2zoj~Sr>tjPmtm9s?fn^X#4yq&3 zQeD#9WHb=~OhzwKHB6Oi3?2f~9bYeJ0NeQch8r5dMT*yldFJkc(M%ALPvX~93jZ0O zwk7m$KS+~p-_(N1s`$&lw#yom`&-R=NQDtHC(!V4v!pf?^;EY^QRV# zMQg>3gMLkq=+uR;X4mrXvUXq~*^r;`vq_}02{}Vn?#lz?b-DT?NpDKiR*N~1y zrk+|oc@0%%Aaek;q5Qy(;Q$ynlB)}zmz3DHe3;8TUQ+8q#?FDH8=w@J4ovNBleE)NACqZlXo(RHReXL_*pA9KpI|PdHrgh(#+6hyc0DQ`HY>dRJemAC&67c z-n6#a%qS(6p6_P$a<~oH0;CI}45S zlcNis8s?@J*y~~8#Hb8|AJ%;6X9N|}1wjSrM(w7f{(p_qr*79Wi=noU$DC0tQnsj- z>6V?04T5bsn`}%bu&Vx>!v}E1|D-mhgrkjeZ-IYcnW$-I;7zKF@WJsQ1IgE)5q_M0 zy_0bDm$**Lxg59iMs0FHE=GDVl%pKVl|W#IWE}Q?N~}FN?z-Z3)hMLMHH+$On}>DN zG#Z=$@0@}Q7+dKL?y3*{*$*!fat4b1cA9{DU2v^XFe^T#8reLToX{T9*~#58zXN(= zzA`~EhW9vm0EZX4pduE1a*k-h`Aq{$sgMg))z_pF8>gPpR<8Kc6?4|$Zh&t?uX|O5 zD|YjMwq7A+-xtGPvjkFx^MUq{sGE*-bo!HcZKe(%_Urp4HsY&T$+N|_inSqt-tVR}jH>=2R2 zaW5Cnt1+1$n49@1G8mHaivhu)8pFoa@#_SwOEs=~=JTx_|IO;I%?S_E09+-Tt38rU zo}gW+dcm5mRaM+$2Vaq=-=@mt;azNjTP851(SE{4i_kW{Omd&igX?s9(cj4gVFom6 z+VuYDNR#XIR+G?9WG?8|2uNZU)XLd_O5%Q{o^OP5+Zti7gUd)uKx`O~okp4Pn=n6l z4{isq2;NcWLFfQb1#`Ax=4MOy91`5hd=fYa*oQ(3-NrYU023>fY^T4K3K&-8AOjMD ztmof)5%@1d>rX=tNP&tNwbg}2x^B7fAzf;{0qx7E2QPwLMvG52U%5RCSv~Zf^NI{g zV9s$H-BbjOHd4;;{IA_Degl)u=_k$c4G%S5_?1{a>8dxNH!vOtd(IW&tv0|NWuMR@ zWsA4cWlf#Dfrm*oRDOxbY?5$OoFhjtB4~`^su#XaT+=$R{Eh&V$C~wD-a(*fr8w?W z5f3iCe)XU{0#LjUwb?o@URr=-pfX?JKa1;bs)XoS!k%19g`;&wnbn&RR9H zpXWWA$!CyoXFJc{Y67k_lK6EpY^}ye%$vTIJ{fxatETIA6auv7mSQk*flFr?HcEv@ zP|$PJCou4Sii}>6p|)O7R19SK5B{D3#n|D0zae8rg)U~m1IrN;4@EKRHx0KsD86U- zaRqdHj}9tHl_C9T^gE*kWxDh^HV&C3{nbGT_M`iYL3aR4LG)*Xv%*OIasV$%Vw^Ky z4o)-xDnMW}5Q+Z2TJm)v_zlHon(4_fNhFP)&V8?y&7;h1Hh+KxE1uI@@2Qu=&cGA` zZe2+C&DH|(=x?)EQOzmmpG;1F+P)JS423CEDTZgCjJ1iV#-i(On25NZ12L6AXZZ{!-mtx>Mn^8x*s!<4YY!gLNT+Fu5 zEPMHD2_y47*ZW-`T5G$;9jpyo+!om%{8(U7J&@yyQOd$ja3ibADU3>JRm$VrPbVnN zUS*5lc?AFwd8{1|65azg%UhRYtfkdKBYraAUjfSSv!hXI{PBFDxzNQgHvu*l*~dd4 za*hpH&A;_^(@!<(#u$$7pkmuJEQl@A$f_bK_{qsF$7K6JEsMAJn0=4qqhU0->f!lQ zvv&mc_fRNPvoxgIR**eKpWW}udsQ)s`vxrUh0EYwQlhMLnOZva8gkyln0$y}GKZoY zY}q<#)Sx$hxt$;+!5e2sb=qT6uJwbeAL(KImNu)A?4hI2r6vIWA_4U@T(r7@ zqkFOV_Z5QlS0W;iYdriK9`;yf=&_uzPTggiF74y$PDC5p)z~v$C6u#uVownD^F}Fi zDA-*uu+N|J0O&Hv(LA(ZVnv3N69@|bsBPWwoQh8kZlS^?Jqm4yw3`m;!8k1)Ti{cu z{wJ}BUSR{(gOcWu8_12aeC%9y9kZ@mp@6+hAy2OfY%ayRPNUIoop0FYkz~X@ni5YRrEM<^ zCF>?x?DFC=cF4lz(Q(XtM;0&^>Lr!lC?s6j5U%{If2}-XrtI*=mxdI)cr<5@`*Ytj zpf}hofcxqH&ctW5pEX{@&V)X-+mxO`%>f0XmmZtq^ol;6kGm*L-jF#TyXXA_-OIyw zVM~h-Wb%=mu)sl^&3Yx*TvmVeHn*IWhj^z}+S_A)ogw!N8PCmkl<2IN=wgj1)Dw&b zp2mfVDwgZdA z*2@;~DmFe-v&cOqBr@!u3Q9RtrkgvgOMXZO(jW$RuI=q#Xx2CJUn*f-qCeKjQ7Kl> zdnl%t%Q7uZ>2#C&auP44Y8jsqD2_*3gUmR%M`*t2WtH)Jk$+EN@^GiSve?^>$CztYTo}T2< zMwcb7mSeYE2gt{4A;rA7cl$|9-2KfX%jpdfvl$Ex9y;8;XqWcOV21$T>T|QLgU67#;JsV=?y-d}*ksCNXzmy=XYKdL07iS}`n(cISi)3BeL^YP*dO+26!poAgh$MYP|iy=PUZ>G4{=o zp{bxlYULxMZ~$$P)%G1F>&Jmty|rNFz}rsY8Bsjna!3Ii-zDa0hUJ}YJ4n@ICHlgW z58-kWzY@K_15MtueZz5F{DzSVdGJ=oVeLl<$h?gBrtS7eTASTOt% zlK}v)pzYQPx>M19jo@q;Ix&4eup|gGV2eC^>V^^#wBm~07LWO3catRknv)niD&liye?Z0sMjd=)XavCcj*wa0qby=apm^?^wLq$|MeD7)mL$ z2&`|l#fKH}ANZA+01g7QIhB~6AsQPK?asG44hNrYdVNK5>hxb+fr7{9uer77wT-?S zdAPOWLRbMQjAHvg{n(k9T;k_x5dI6D8c^?ld%r#e_$hbQ!%Cflb&^yjsjq?2{Cg6) zTOanVCWsMmLv7`Y|JyJbuBGi4CzE2EF$|%6tfk_DKoIEt7odrseeyAB^APqmc_5tw zAqhFfaLa-~!awp>M?p9JC;(p=#%=OU7|AdidnH_xgF17e6bUo)is*T17MX{Hu_-su$#f0T;s7#@&yl+0npu$KC~ z(UAT}yn0O-P_yrN?{N+|hbj1rzIdYTGafrE4DcB?3jA*&+3p~^L3*;0Ae^6SBWvcq4Nqkysez4@?rAc7KXn;lUo?>ynJqaUk6Tm|)v14pmC#}HTaVm;CIs#3bjn&j$9Mxzoaj+mUPLnf(wUpCRvLi&14ezcRgrL=g zD+_c`ZV0_#%4nBJ`bGB!7SCgi8^(9)-UW;1$d#o%~Dl7!p^&L=!Lcnv;; zj8gp-N$-S#MHW()qb{hC1(B6l$0JQw4nZ8$oZJglIe-i-(V@|iQRt8S#93Ahfi;pN z0d?hso;1$^2TymH3m<}iaL|7)@*kk^iUs_9#Nr{tKc{woGC{9nP1t-Z=>a1nMCYm4 zXWGA6o#A=5j6b+`F2>Az+8%-ec=tpvpxU?kHXBYfR{g$ftx|U=Qem;+RqCX{!KbmU zg!c^}AmX>%JaK>TgC74X{KaDQUHPZQ+U*KZ?8Q^i`B`5irH0<1Zd6Yj@bds-jChEN z5QPy8kHj#z8dIU&vBoPC9Tv=FWSG#oCaW(YZRr8Q|K&*fO%v1i&NfhJ6cHD|++svR z)aXKPd*bF>w_SPN9`O#|mbl2*sDY3!{vR0V);ckDJF$lNveFZM0p4og^-9xE>THyp zl*Rds282Tt?A}XEPt9>N6ZdB!zDy-LaqQ6yf0jE}+%Gd`=U_@QW~I5Zd%F%YtwLv1 zJqqKB*O*GJX%NUrU^3$T^QD1T!z?qFJJeX;LmYM#ykCC>GXC|tX;GU}$I75gBsLQp zd=~lNgP7lJ0_vvwa+ut&548J9QkD2JgK(Z$BX)XE;$7f|kM2k?Qk5uh-?c%(BRL_= zeCzm?1A(0GHNsx8$L~rFC#$M9Ne^Y^B+!V#NZxYrWcBZ}q`VR7vJX74lY$J?-A>pC&(YuAHIjp{Zi@5j2yysWp(EFo^|xH@sdMSNRhq# zUU@j7v`k@e_d4oonq|<@=hb3;})iCmu(R2ueY=AeWTT4|$Cn~lv6;?FW64?<7o?jccXn<&#cYH%#^INS|#V%}u~bgvpSUTWfPX z1}TK_^4uJ{gj(LOw8bwyw2@;aW9k#(loj(*A%pKl|RPSUj^%@>4^E`AJC z{_qz^U|KV$^SrS7(`?m#Fu_qx81-l*EmS3gE|bG_Tf6buXmFr$$|(b$NZ8oSUoI7a zk*WaJGP{a}-BVli6QfL23w<+&xFJ396!~694&xz)5^?lZ=6n5B@SA?&ks|-j5JJ@B zZrDo06eY?#_Zp^0m)w+>>m}c$?Jho4Fd{Ih@2;6bAoORGGgVIEd6quz%2^Or(&U_PUiDk==6iH)tsb}4a@UQ zKkp{p$ah^-H2 zSF(9AX}I|Yh_m^+_i=c{KYHoBu4}G-&gkDxRNu+*kBpuR<`4shToq+sQ@7y`vmdo<&j_eR`$1k=xo5IOh7(aikU>Bjrd#OuTJFw{_V@A^}|uHuYQ zR+Dn5!nHQmBKKUaLS8x7K2Mh4XoC77!ETwhdTTkH7;8y-we`K~tn%k+&JVk4^{an6 z6po(R{MW$oLSDgLwYYmQ>eMcMMqM|2fHEg31$O!ghTHr97#S{|0dI;;!y2- zq25}%TD9Zwhn*UZBUAhz3w*io$0^bgkJePrFey93N)MGSuDD%;GvT=S&jY|;lE?^Y z@dXU}jvJR{Aoq>*?6Dw9PvuGrERWI#GTAKu^Y>m9*swQX7(m_J8p(X?4G7)V7Qh<= zOoYD)jr*cZy%N9rHyCMrwZoh><(UKn#qzsIIC(dZlY~2`vBZ%L-+rTu`q_v<;0A zD_RPSW0C|G#0>>L-&DsWD-8mg-Lf7XEIsIR7`{!QxSAyg@gTf%m~=6XZt4wO(}J$A z_)9n%xF|7%>R>+tTHWkK{V#MEH6TV*g6lNig@l_J-B)SI8salC3VF|miNZK9cuC|) zodb*zXTe?~?>*K{n1kr=1Yp32WTgHn4uY0__0iBzhT**iC+LI@kn+TpcCI)f5=an` zgwNe_{P_uB>d<0Lo^J;wB4r%BffT^xiSuz}Ih8K70eAp7P%hPE4wLew8q|F&hpy3Q zKL7R)BSrFcj2~i<>kf2WF4pLJj$Iy3=WQ3q&jZ3zikQsykBbBseeU|hgX`d33v8$z^l67NH^Dj`+tLN1+#qJO z)TF&u-t{wcs%~-&7lKF030LHqddh6wonzlpk!An$z!rZTDdL>aAdsn*`x<3sP!kb8 z{=xYq=H|mZrLLnuq}0B_VcP!*Fkwox!v^5^VmOQpMtUU ze|P<53R{U^I`8JXXBjBfvQ@2(L_sOseDqru-oVuUR>oL-CRWZi9_+7BRm$L@)mI>M zoxIbRiKT`jR@q}g;U=0u0{LAqa1rLLXn#uLgwx$xkDm0VKgtOifWC}R0+EW7k1|_i z3&mgg5meTOIX!BIluYq`(ZGh8rQ(sGtnng&*BGrxTL|SDb+Lln-izt>dk24B_g@!_v>e5^@ktQGr`b~SUiw0&&sDDSE}Omo z`X}yR9X|G>lFjG0`1CH|1>OrM@ASP(e5VL`^yr1L(Fn$dc~XJ)M_u>eM)IWiKdy05 zEt5@r!<%Z@;&ju2QFgiX|+#I$y{$KXJH7JYy8hgf5fN>}vaPC4PYy|z=H>mF3hywbn64YKvA z3R6PBZ~?zrE>g`xCBE8E0~ONPI%wO7A7~>E$0C=8W$@EezNDDL^eFG#T@3qlDdL375G`<9Pm_ zSjT=>O&hp3yEG%VP;3U$`wd(AK~x|iY> zN*SkcrJm=NC=kVS;xUPy_SCTae0RM-9QG8bXPjp?x>?#MC%FN#fe|hQrO~?_2#tAt z31?a?GIm&N?Q58bk^+_xp25S0U4zv4lg~MS_42CbtmEVmJ3IQiwVQR0+;|PL;&Y7B zM@mVrbf@!P#OP!3R3SW7?0VO@L^jj>Pb)@yC+_L?2hotnk@Y1VyN@W7USI*HTXjrV z?dD|4T*;`S5=1#dKP_?#r@kdmu6ZYic-vFm?KOG+=CiY`0Z!i_=l!mejCCfOGkWWN zxks<){T9^4SHe=>UAfj{bcWfVUlALV^|r5_?7TAu)dUnN)%UUx#i`M^`#oy6N4DFN z-c1OaYj(R;PU?($vV3GRLRXJ&o4F)PU7S|W2DM=wJ;G|mh#b0UV*kG9{eD1xMySP zao4XyINgL^c5gQ3cZ(4r2%483_dUyw8ddee)#JUkknP4 zQ0{MRWxPPUB0)(%klWNNC0bDSZn>LaE+f+IGWJ`eDDfTw@G#L(s1D(*sbQ3B!TQ~^ zZKgOuiae>M=gwN1%e{opm6sCl1-D*S`z|A#q^CI0{}-ly)KA>(!gG1(+59LN16>9S zSuwuBLhv^|q%uwfD?ez3gH}N*w+Cn7Q}7&N;7h=G=2$&*$@X<|$a7kYWlyr*DAQu>SZDVZ!$`jf5T$lh* zdugbvZ4nC1kJg= zYl)d+Lh?}d)PcJnI8;_oq@?bj)-?3G<{0sMTGBW+p1t=;BY$rO2kJ!R5gm7C<7Bn{ zK`&Yt{Ws=<4C*RAwuh)!H*~>PWod@@3_B9tiyH<;!bKo9|J9ZcMd7OQk?M-CJI^{O_?aSV665g(Hzg_#*m$(CBp8q8oC(ngUKrt2>= zY#s}9Zmptr7_8~u+>hKgqYSG~`*kaMoZ=f(3{M5 z^wGujmQ5)yH%?!V`6CW_kRF#Rb?CP!)G*E4c-}B2@}w~!n}Equ@3+IXoxo+t0HE>; z>1qPiJ*vWMQ%vY*Yus}#lfsvyZ!EuL?+DJqhkbjsA>~quPqXy7`t~3@DXysYM!Cn+ z$jLf!AxRKD^rIB_L~1GV4w^`cF7iA~?RFLl9l2$KCiaD7Z3h!^64^eVdd_bJ0p^c6 z1Q7b`);(%2ju|E;yTy~X`{Xk*KMp}l99oP$&l&u~t;?XLtmQt57&?0^hU&zD*x45+ zvu?#=sOY-H@nW;m^UX@Xj-W>wB-HdqlgTFUDzx5`TG~?4h0C|0Q~-8&3X$##4#^jm zNG)k9M*Hi3j~}qx=xU^jTEvG6XI!nHz&QlJUQpMT zvZkZO$Wms)Pwz-|^U+fpYn#%DL2GYu4QnhU?hb*~Ie9_M?Zc4lBj4rG0~?R|EbfTF zpi4#2Ozj$A3*0othYTtWII!S@o_)fBwH7 zJngmm9dyE3lo{Y;Sk65s``0b`Nfj}m#ILnpRJ)B)O1Nc`JTEC{<`x43?~vEHF-?~* z&7aJ~+^{Z;AeSo zvZOdp5~z!B4VugUndHR8ONt9>9{Q}iR4Q|w?#%=UWCK*oIg|=>3^5XMAbKeobN{wf z&)vY0+-S%VTU?0@Ij`tE?Fl~V^gL}rOJ0;(yQ{pIaNGfS%?iwO;Vf4XQbTC zJlU;QUfUEO-Hcdbv_^?jp-z2iT=3Tm(kOEBz}3Rt6N0RqcQDQbjq075PiJ!Gom>^I z7`Z+H8~ASLY)sBgLuwt(tnWMvEe8JHncj$jv%RI>zx>Ja*mh>)l3-!g_*!lor#-Krl*y*@CNeMy$dHbwX_AiBmUgGwUN#qgD$r} zt)q~0Yg|^5aQoW0OiN!SviBKg0aTY%MNMzgEc27a=ta z9~|Yfh@X{XXDBUg#wo0Jbyi%x=S5W;_|(?>r?<3(P3%MO3eY%9lt(E~S5nf9FY3Qw zh8+?Q`WZd8Q~cayMuS2x&%1VY<20K-;R^~iO2)@=u2jFVN{kSXXnW3uic+Kr^8nn% zaRs(WVyUD8NqVE~+dpgK<6EabM`|75wZh*%Q9l$bFquKBKN=HUEIAGhnzWH6Zax zDuZ^Q4K9$s4o%z^CUD))$%sES$g(I74JD5)>5q?Vge`JU5>IG9{i6GBII~9mh6t84 zm&O=gT$E~qJ?^PVfBS0eDGBrQnf)au5B?st%2?#z9&vCBvH{pWvt<3e+I|?qO0{-S!H_x(jGC+fcQ6}}# z+@29z*DJa{)EC-hw}_(2(mr&kZj;C@O3!>7tIBvp9`3FWFCQsk+{O(o2J4^RXI5yR z_{76}UT&byCn(qF7t)cjyu*@T;LPU`O`e~r!>)>1S)wJp-S@BzsjTa>1ZN2+n`$Q~ zwJAn^fck%*rR@zXjM>4{T1r2D#b5l%f$pm=cm5W)S2{3Rr!srmb6#eFB~RvHCeba3OBlMpKdus-Z7>2yX@T?8#K0_W$c>wQzlgYJ;ygcZ7>@yI+bGZ9*1nUARIGT;G5P z2H2<($Shj3w7ALEQqdOQ6w6*FxZ1Hi)Dpe2l&OE{4=kRGWrz7h);Q zYt0*v@M|HLjCg@&(Z0(hTJ9^2LO36zO@@hOF0rr@U4C(F{#r2_Xb77zv7UkMnr8`a z&{?!Y;BWBw_#OGF&Cjf~osdOePNJn2PZ_Nca2DkI&pOE--hgoi;f&uSLvt6Iz{b6~ z7>vR+#(B4cXbC@~0Wv)(e8##EcGyu292F-Wls@h4r+^7}ix?6B-jDXUS+P{c>4rVa zc@8uRry@T;A%(Rl!xDmL62I)gtQe&9;mCq&-zG1>Id=r`7C7^PD#q>GV?-e5f4a|w z>WnM&p|i8IfP)HMZLF8~JL7JyJ;%tlVrU!Q?5AthWmuUt0N1H+ZHt4}i>zQtTm$z@ z#W{&GZ+W5HPBr^(`b^W>xUoi@qE&Q*SZUsT6x!F>K(m*IeSOun?5`vEoG8`nuovypRj zZmvSODd&-=TXclA?GFCddqwb&$67?Z07Gbpkz#Hv)j9COuWx*O$BwISoo{@iyYftb zq{AAZv4xyG7AV3t{sJbyX@>HKuUGL_NAWbb$aF8Y)M<4n{*<5s6wCgGlV_;UbS-BA zB3R!wZSJMP)`f}#$i6$b8^SbAF&aB%(9LqLVvM=wFvRM^OzmWkIm_-GC_McRYKm72 zf9&%aLv&X7Spmfu0^i0u73DfBKJ9PTdhbzY68UF6(U??FbNQFL_6_8WEy%JlOzGt% zIrD-}1~=a-5qQbG)#k`yNd{M~VE+wb(zF%2;2+8Rbl7(k>u-f?qW3X?Bq*H{@as?_AJ9-{6<)@XaC@2p-R&6KpF;N4=OM??z^tM7 zOcnJ00yx~Y>4*X`$K(zDZ8d+pp`1CY;gb*x1TCGr+F8fSVtW$$1^pehm znB~ovs%R0EmJUEB4^Bi}C;8vDW0cYm+> z&F?)yGcS}QyluRmuVBR4cMSi|blifQ~@4uZI&@<~KfWkAY9M5Vk|6=QB0+Bu( zaNUoCf2k@NMza|MOU87Tpj2hT0uj5rbyLz324!)btZTpW6W%cMue=<4I%ir^N9_`5 z6hfkG5Nds~pY)xNl-}NzlcDQdv#2RUC4FbN7t`oOhP2^!)w3{QYA+WBf=ojDrs!xYk3BC>-tvQ+@{p@y z{oALM40`mwnKq|HIuqdV?8qV|^O5FAxi71Ax^TZ~EqEXlYlNx_3+cT7R>S$_eroX2 zB1LcMbIpjMZ$JU))+{;LZSv45W8eLaHRG_%;i<%%GwBo#7@~&WPY!_B@Ml(2I6S8@ z;vzf0|HDr>Ki8YV0e}CSLr=H=Z~_FlD^hLb2hzV3AgU+g@IX7RF8)Lep)MXwBlD< ze&Ufkt&iT}-=8KRfA8%!QQwX+q4Gu_yA9)LsK(2)Q0LHI4=N1HqMP$$KY ziJbcqap5il4=g^mevisWo!ccAKif;RpW#BBI(coRH-I~8j)Wo26I-nkFaXH)&V1%p zoZB=7_iyQtMD;!rLBR$7yx2-W(wqU}0ss^|th`3WP_xw`{|_5@P>?a^?v86e#{UpG z%FT+cJ0!THkRA87D+_XHaGPG^e~5J6XL^{>R0DV}|6RK@Ji9SwCr9tQh8q<#IeF~c zy)nCwhUp%nynz4VA%cZoEPeigZwAn8wf%d>_g&Xmt+Kz*vE(d6v3L(I$9Y+MT`Ulo zUN3$hQk}}Qqy2qs&g~0T;<%#YI}c3uJ6V1-sUW6gFAmG7KLOPQmC6(NmIBW`vo?6f zrmD}1+{6wI&0={@BfZ^gl1rP9%7+=`@qz{44XMiCk=*1317Ifm3*S~X!%Mp9xlRb- z0EZ+X!ZQvnkmeEo7N1LfGPnuN-a|(CoQZTSXm>k(K0MMEu!>*-+oxc;t+r!m5;Yl+ z%{~&-j&#NF&CCDy5CaG*D?aKs|6|hmY$SU73Nvu)xg4(XWvcvD2nHPbElZ1;chq_A z{xCmW>Cm^;Wf{BV3SOl{(8|l`@bB0t`jbBP7*bL);MbM8yY92R0A(fxhM(HaIpZNc zT7JRwzuFPd{3yYlnimq}ak%tnY^2 zea`mo_kR%`*zSbfFRWNlKo>s4AJFXyPwh!Vfe&d{IMq-PcYNt8n=oR34BRl z!oX@ZWHB)+{;o9SV1h&YKYIrdpvA4}`l2}Y^Fvd!N*!0TskY<{#^;9rCLS7zi)nST zVOnFEVRISjx7y!#pPVS{p4Xzu_~+*O)1x9?g#?YyqLN+|cWxDi7>if1b)T2*1h>9< zQ5UMtG)$TX0Mwc6hq9@uj`)M&>y!k$R?;tz_*@z{;)?Xwqt~X=4FI^ogMjpx>W-ox z4oU*j^JLIxW^lIk$S?=!}nu4^w5rg8n_MJiMG<@eI4zngU_VmAvCt2ip=@B-E|M8P;= z=wEC6y45Q)##bLdi3)}c^WE_`u!i!ddV&oG4t^^b;8TXjm{gw zugD0exvq;cd+w7rUZ!Dy9N7e|qnNuod6EE_8A$?J{(sM;%)h4xxicGwEX=>_h5(R# zk(FE%mCXjoj>tDPTf`iXn2Y`!1NRgl-w0znOj4P--(?xH`?1%Txckvu>zBQ$M*rFF zwU50u+Htwt{~?X_vcx=%5n4(9Oz53nTpQcfsvV!fuc_0Y41RP?Bzod-EU#-Q&l?^D6bd{$m@P4UWGi+ z+HLN-V)yLmOTr!^pU8rw|?>7i?tFey7-nOlj%;Z>l!b=Pc2G2P5yFa6^=F^wN$HEE^AvHEda zVH2%wBXN|i`AGR4q%FjokaTsxfBO`msdE0wH@R?CG1`(>%VJ+QaUhCPvg7V|C_uw4}BFkEKtRtstApK*UDqsmuYc-Rx-TvOpm-gf#6o zi(`)g;!X`)Jr|vhnW1>r!>j@y5lE=-qjOjwj*Bf~^b@euEcW)lN|4&I$KYIfy%Y~f ziiIp;FPibt=sPgSN;q180@SUdlbOsm^unJeE;B7t2UvCYRiJL<9)y6(>A^SfZNbKJ zwdqXmbZ~VLlV5={<0wYmPy*n73la*(ZSOqma?x5%S1n~N2K(jdHxj|GY6+Im#-Uo;xGfp+;^TR z9O~R_3bB$pDM61z#eIt=D6yeP50r@ z17E(iS>>uvUAk9@n)oOrA(L47QeY~j5JjT2%x&Xk2lKs7@pV7Qy_z7t^1PU2w^`SL z1|Dkl@B0(FCIt2_mk5v?IBt0N0*qf-fhg z8&fwsm_oeRox2UbdKqmTd-ZZgAlOZVIfW5$ zWlnw5X{rL86~_V^u3j|DV{Z zg|E}A$431rxe8VX);8Z-vMZ+b@Nz(mxMX?q>tF?sS0N50r~3XVnBL$k zxmdF)ve3}TIolU#dS>FsD?85(M)Sgay#DExgoW#`^kR4l*5}r2T?amHj3+lL7*Qx* zPnDzCC|*s{K-Ev7qc#Ute|#-}pVyLmISJfT7>gmbg%L z#Zw9cC(X1m{OqZNWH>fNCXcH^ha68Wt*dq-M#QpdFWndOsJ{A7nZX>soB!u40)Hf2 zJ8PL}0Uyp&F4~r?;SFc-2EuFOjBn+0^J5QoxNmv!E4`sntdzCc81$%iY2O93d-Hd8?C_VxKCyW)@4Q*W8O#j zdlB)okM%acc?;sVz(JBUbXwsqIPlJT5NfhL zqZhJ6_rvP1|AOXrHxn{;odOyd(wVy~d2wuXMrni5NpXWe_X;ugN!hO*P=uw=E`clf zht~ALCmTDJ-{DOBX=$MxOLXH}`KAyrM{>G1!sI{A6n@>Gnnp`(*7e<|eq0-_Sy=O7 zz#D_OSA+OFrgg!{+_GNynnD_p1R7efz@e?*z=vLlcUXqw?Y7NVaJf||MzbINxMDP| zFaMy~#i&ocv9UvPLTN$6vrk{Il#$PS2c2GuVE)$g@0h-b@ykpl(HC8sn(!EBLQoIHFN`c?!_3-%&dI(-xXbjSYH~47t;2$@Ck$=rhm+l(Uo+1c0c|OVVhz* zvgv+#CbOMLcliTFxIce)DW%8pNJ&n(3F%Nbs^DSC&Vij(ZhWYyAX|=6N2H5imQHl_c&+e#0%={v4k1l_Ujj9sj*k8YmvY&)?d9vAJWlypX|qeYH_mBx9_3tg3+YssAILqEC!U90x=(ST zqs9IX-#TKgUdknrH}9=0Q~=Tvp|@qz!<^&K*l5b$XOx)akyB#^UbSeVTGOp!`-!0y zoYby9^H*B~w|*v$)N~;ZH*Zi@Jd>Q4lr?Rc$ZviZtB1Qj>&7|$#F9=*0wFFeVcVJ> zXGE;(K!vt1Vh9RYaOW&ci6~+;w`j6v_4{E6LwOd<&w}&OM)xb&v!F>32EE{2Z|-1&eWW zhan(*SG?QamVOBO?=VCtUW!p*nS`&oa)EnOinF(mP(REx;YAs}J{BZ00x9G_!oSLQ zSOkD9FCe>wZk?S11EB{`h#`)|a)L=(6Zg7=Bg+GQ6ga`5h!|-nA(7E_!D4=p*l>sEU0?B1656J@vL=|glA{BCyrW}Liweg$CDV+Y|+eyw+VAkDTFhmR>NanF_% z^6t%TWV{S6qnd0f??>k3|3w)n)Qr~0?E!(U2Jm5@m~hayD> zhRvAC!z`Y^$m72~`oO)9_qglVDybZVcSypCc=N`JK3y!*2xazCrT{pzlpU+)sEmgazw`k}=5dPLj~O7^T0<<$p|knS!Vo zRBwO~H~Qy)?eUT<{nv~-dr-1z8BxPrLq2KnGXro#(ir^1aUA{^&2o7OKV{)lqkfu= zhmh7E^4HSv$JH4ETITa=yN>!UGK6IVkZn|m-`hiKswBDcHNu7rwn@Wyd9&$z4ZF7!+op^%q^Pt~BvhR+$pf!c4n+a$`? z$Fas(Cja6Ct^-U$PyqPUODnw${#y*7bi5eSILAhRCh!zkKmNh%j5*Ch5Fm$U14M~@ z%oTBLZ|a#rlq{3nGbV9w)ct}%8AvvpnRuu9L(A;Axx}=nLaZVIV6vOg^zeTrkJ792oDl}4M%;Mf9&qh;A-n;T-})yguqu9EpGY3;T$Fy4 zPATle&|b=WTiZDX$1Zs+<+GV7HRwO3U2+oMgMa(c-*uS1#*%E(c+;~%!HEn#s0I1m zBC^2^D}q+!jO*gJP44DwB$eZmU@HQi!c@U!a6eX#aPmaA=CXml87}+L&GZ1-HV1lP z4Y7{8Mr@|hU4*8K2R;2!Df*G3i^gt zk@esTOXs64VM;^{Kr4K8nLY&G1Nv=7-w z3kL-)&Zd&!oi%*!4(&g<8o2e)fwPx{ruIsvHr&Ir|`_U5Zm zU9uw_H$2Drdvq*#yU@Osf4_X;zhF06xImAIFav3OUdmV6rf^dQ*3067_6( zI@$>SbonwXqsb=Kq%sn2@T#`=Pbc-37h-DgZ|_sPZOfCt1S=E_n5yz_n-bRpR!YJX ze@+)ih0Pw0dH3op@$x2p^Nm|Wnk4xB=wCLWm-%(Xo*zK{WG z-%{+h@lN@)Qm;`JH)+H=>#o!lG4g%}W6W?HiT?FY(s&T0y@6HTx!tPNZfP1zoF5sj zjM7QLI9mws2FZ2{rI6~J2}>?TJLpW~T?!+mFHO+&vt6m8{Y~x_L~{BN%$vljPKccL zK_CQi`-N-I)zgyON2+HB(-9BEYx^4;5Ii@3ukVp+V$0)F<(!0%_AiA=F1kuPT^Ek= zTdNXRe|v7HF5*X8tH30K+FvnF!Ici2voRtoCzJ@^up~j{$H|R9g401U>xo1Ah8jLj zoz2M>dJ|M$wV!2=qpkgyY(L;gkR<;=@J>Bb)Y8Js|Ngr~G`|`fH5F;SzBm~alBNrq z#jypHu>+7X>!~`1@8lkGq6~j)t(%ouitAuvG}<4_y>;D2lmBBVe>`AL_dv2)4sfiI zs#pT8yEEUAN;Xc?ylL)l@PSb*3?SVh>h;$+h>Q-dUhGoGNSo8 zTqcYUzCK1C-8wzswq(nfK(QDQay|`yQHBeoSJ=xW3>+PAt=q zDj~*NQt_R-ltHmZ<}LH%MYCu7?{%~vPyIqkTQnD33U4^MnZJHotl#d$Y%aI;_U!Q~ z$&|vFmTjwdF4wiuOWLnQ@Y`G4WmfCW&JC;NsP_sUIs2~z@f*SEG+0}6UF^o641kK2e;dFnB@?p_Fwo<1@;&u82ztsu--^& z6Nz%-?uOIdAh30h0Ut5|T;*EGaVZ{X0Z1w~BQX%SKr&rL36F-D049zBlaR~6Kka@>#}T=&Qok~oAPLSsE5d;F z3?+7E9hAy{77DRaz|1wiygeowY5dSzA4P~HYzHq1QoaU+{WEt)q)4v^44B6N+;JP` zL^3C?e*DhEaUbJs@cK|QhIIO#@nU#PG%}DQv)RaW^(CaA+<}`9K|(!Q?BkP;02CZ( zcDa650us{pnh!z@?!;d;RN?0(?Xx~+j6jUtCmJ2@obecE%*|5D1rc$M0b7XHFe%fe zym~>57fWTW5mOUAvW#1Lx-Y<3`!8m<>ZD92$DgYsMz;oe2L>wI)4?#yDSaZ`}LyHeAYIn)F#{;)A2=V(?Yb z5Y^q`Zt;7chT-25P-}DoE(c3HDmE~bN8h{2r&BEF$qq67{gjDuJp{FC_x*Kn5$bmG zlp~yDfoInuZ;0Q4{RyZf^c{$fEWP?Vdc<4p;=@aIa$L>CZE>g-+e~60!e{-;{o(f| zY#)}K5Pi!3trkbC*}cS2vlj?dz2|b@hJPXkBW^lyEbZ5!D%6$CqbZLiJC`53Jhr0; ztT;s>HFO22rVVGXplYVP@zz}l2}D9~eeANOY$XY9y_;!Am3Bkal6XsnTOLxHw(Ly< z6#Helufti&@TW_buVPdyn5Z95rCEZN0+i_EiKmtC56BN%)29+JWLC@8OWr2j5lAj# z*TabZ>c=7V!#@>oT}Q`KkWKHZ=y9bjZ+4*Wx}K}yn8#$Z-Ry4py}mcb_8T>qY3BzE znvRgy(xao3P9-6?pU&XhKAq|1TOPt<#4?H*PFsI&X_th45co909%EZu-Jgn3=G;ug z$`GEUzYa$yQ<{de2F&Dd#SpcNir(!gGh+$bL;K8>!!G}A`P20I-9pHI660VB=}%8I zHTCnzqSYO)=V;XnqfKTY&UQd z6_n2=6`PTdL^jLKSt7UyH}5|RKsX{%TcG#1Wvcc_+3B%EB_YP#Tc^jQTjzZVU({A9 zHzWa*M!-)EZ>5qOYG!(;>SI|JnoTg@XWwe^$eIhU=L+)Q!;mo-OG9oqN5A18m;5D+aRiJ&P8#!EN*w5%TwTn3y&GEgF^XyDZeC; z`clOtTrXKrES3*Y>AioWhBvIZco8)|g`ESFp&z&Ll_zz#t`#qfRhdIjwsYozJ$Y^{ zAwE#t?9u{O*8JGSr0)~-HRcgS&^0^JYwVGpaTi0ris(zP#JtKCWIs(L4c2e;(&fP| z2R?S1_zcr|c=9k*fO1EtolCs=;Eq~XB*g(8_G{GQF$Ty!bYN_c?;bbVlRtnZFuk=T zxmgixOfGOn-7ggrPCKKrOuUkP{73W$YnvBqPMo}?dpX-HP6~OaCP`%8X*b2=e6gi8 zjc_jdxB9X5FlX?|d6sfob6AdleJ4Sb$Ks)isBQ&+>WdVCaM8YU z-t85m5XoYHHiyt5Pu<1HqUL<@Ihq40Un~Qi50i0zpGGs`?oAf9iT(I7$G5Tt9N~|> zoF@x&Lk$lH*qF&R$QoGfj;s!9Q|7)h!Ls#qzr(xkfT`@QZ`ksI^Kkz!tQ8+|w~`nx zb?jS0jBWSsc)pA*jMk%NkB5<&%=m^iNvxSpeVA$(`cyVxe|T#UEkF{ssondcZn)!D zo7{%vo`Io~TsgHz z0A7DOa1kMwF9m3u)fW3Yfe8Zl?#w4s{H>_?PsR_DkVM3+(umD$yBL2@vrh{lkIxUsG9IrO3gXefs~@t~YttNhXO1uMxMabsA1qRys)?cJVI9k0ilNd4cco6gB zITO#_^wOwbQt=&b+RvnIlRG*qm^_M}Bt)u>juR~a>gFGLKgXLh-w)6y`T4IEK0c3k zGZN2kE8*R1)<*Fp&B?iJwj1)ADO`iPbzfI1`vvjE5D6X-#$$42&nNq1LUOz#KmV`3 zcx=2xRAe{*3{&SiH@9gSsW@VuFX2jup7z44k@B2JzF3|UR>pG)TJSf)#!3ZNgt(;r z%bn{@Y2(~Xeabg+PY!&zmT9c2Zu$jpuh}5%Jh>t><=z2w z00>_VFC^Dwkg^0OVtS!{{O1`DKBN|Ezb%d#`>!}gy)J+vPhfp}1a^$LLmL;h0K)g6 zrajTz^H;+T@1q(O?T93>5ze~lvxfYZS$F1cvPKdU)J0hxuk?@mSO9T(r^r7!;ZpWj z^QqH9tp7R9d5yO*p@;};CEjcjz5I=hFmGccnCf`t0}dgNaO8NBB)z(TnWIa}bY*Dy zlslT7aX;Pral_UJB#m!?3E>JwNmW!24<>Td+*|ogr{~`jkF}kCIP=g%zb)9c?pve(MTSrBonh0TwqhEL~5&NW| zPiSVTWGL*rt6R<0$u5@i(H8rNM?9oOY2Ex*7B%rA;<#Yge3|jQQI5n? z8KMEoys|^x|Jqh3u ze{em;J2BVEmXD0Ybh1yR(XSufZXL?c9+GyJ28->Tf2s@Xda9pHbHj_l)ngSgcaqCBE{Pp%H2S9aa zNnV7n^O#%Z*AxYIO?dV2b8EdJw)Cs%46TUfUgoARZQL&A@cM3e=p_~eL83}9+>NTk{cm| ckw3~F(Ir!tZY{vG`R~$D&qTLG$2sQz0SBHAdjJ3c literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..8328fca --- /dev/null +++ b/package.json @@ -0,0 +1,87 @@ +{ + "name": "vidbee", + "version": "0.0.1", + "description": "A modern Electron application for downloading videos and audios", + "main": "./out/main/index.js", + "author": "VidBee", + "homepage": "https://github.com/nexmoe/vidbee", + "scripts": { + "check": "biome check --write . && pnpm run typecheck", + "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", + "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", + "typecheck": "pnpm run typecheck:node && pnpm run typecheck:web", + "start": "electron-vite preview", + "dev": "electron-vite dev", + "build": "pnpm run typecheck && electron-vite build", + "postinstall": "electron-builder install-app-deps", + "build:unpack": "pnpm run build && electron-builder --dir", + "build:win": "pnpm run build && electron-builder --win", + "build:mac": "pnpm run build && electron-builder --mac", + "build:linux": "pnpm run build && electron-builder --linux", + "release": "pnpm run check && bumpp" + }, + "dependencies": { + "@electron-toolkit/preload": "^3.0.2", + "@electron-toolkit/utils": "^4.0.0", + "@hookform/resolvers": "^5.2.2", + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.8", + "@svgr/core": "^8.1.0", + "@svgr/plugin-jsx": "^8.1.0", + "@tailwindcss/vite": "^4.1.13", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "dayjs": "^1.11.18", + "electron-ipc-decorator": "^0.2.0", + "electron-log": "^5.4.3", + "electron-store": "^11.0.2", + "electron-updater": "^6.3.9", + "i18next": "^25.5.3", + "jotai": "^2.15.0", + "lucide-react": "^0.544.0", + "next-themes": "^0.4.6", + "react-hook-form": "^7.63.0", + "react-i18next": "^16.0.0", + "react-router": "^7.9.4", + "sonner": "^2.0.7", + "tailwind-merge": "^3.3.1", + "tailwindcss": "^4.1.13", + "yt-dlp-wrap-plus": "^2.3.20", + "zod": "^4.1.11" + }, + "devDependencies": { + "@biomejs/biome": "2.2.4", + "@electron-toolkit/tsconfig": "^2.0.0", + "@iconify/json": "^2.2.394", + "@types/node": "^22.18.6", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "bumpp": "^10.3.1", + "electron": "^38.1.2", + "electron-builder": "^25.1.8", + "electron-vite": "^4.0.1", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "typescript": "^5.9.2", + "unplugin-icons": "^22.4.2", + "vite": "^7.1.6" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "electron", + "esbuild" + ] + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..799fc76 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,6621 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@electron-toolkit/preload': + specifier: ^3.0.2 + version: 3.0.2(electron@38.3.0) + '@electron-toolkit/utils': + specifier: ^4.0.0 + version: 4.0.0(electron@38.3.0) + '@hookform/resolvers': + specifier: ^5.2.2 + version: 5.2.2(react-hook-form@7.65.0(react@19.2.0)) + '@radix-ui/react-accordion': + specifier: ^1.2.12 + version: 1.2.12(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-checkbox': + specifier: ^1.3.3 + version: 1.3.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.16 + version: 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-label': + specifier: ^2.1.7 + version: 2.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-progress': + specifier: ^1.1.7 + version: 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-scroll-area': + specifier: ^1.2.10 + version: 1.2.10(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-select': + specifier: ^2.2.6 + version: 2.2.6(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-separator': + specifier: ^1.1.7 + version: 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': + specifier: ^1.2.3 + version: 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-switch': + specifier: ^1.2.6 + version: 1.2.6(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.13(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@svgr/core': + specifier: ^8.1.0 + version: 8.1.0(typescript@5.9.3) + '@svgr/plugin-jsx': + specifier: ^8.1.0 + version: 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + '@tailwindcss/vite': + specifier: ^4.1.13 + version: 4.1.15(vite@7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + dayjs: + specifier: ^1.11.18 + version: 1.11.18 + electron-ipc-decorator: + specifier: ^0.2.0 + version: 0.2.0(electron@38.3.0) + electron-log: + specifier: ^5.4.3 + version: 5.4.3 + electron-store: + specifier: ^11.0.2 + version: 11.0.2 + electron-updater: + specifier: ^6.3.9 + version: 6.6.2 + i18next: + specifier: ^25.5.3 + version: 25.6.0(typescript@5.9.3) + jotai: + specifier: ^2.15.0 + version: 2.15.0(@babel/core@7.28.4)(@babel/template@7.27.2)(@types/react@19.2.2)(react@19.2.0) + lucide-react: + specifier: ^0.544.0 + version: 0.544.0(react@19.2.0) + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-hook-form: + specifier: ^7.63.0 + version: 7.65.0(react@19.2.0) + react-i18next: + specifier: ^16.0.0 + version: 16.1.2(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react-router: + specifier: ^7.9.4 + version: 7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + sonner: + specifier: ^2.0.7 + version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + tailwind-merge: + specifier: ^3.3.1 + version: 3.3.1 + tailwindcss: + specifier: ^4.1.13 + version: 4.1.15 + yt-dlp-wrap-plus: + specifier: ^2.3.20 + version: 2.3.20 + zod: + specifier: ^4.1.11 + version: 4.1.12 + devDependencies: + '@biomejs/biome': + specifier: 2.2.4 + version: 2.2.4 + '@electron-toolkit/tsconfig': + specifier: ^2.0.0 + version: 2.0.0(@types/node@22.18.12) + '@iconify/json': + specifier: ^2.2.394 + version: 2.2.398 + '@types/node': + specifier: ^22.18.6 + version: 22.18.12 + '@types/react': + specifier: ^19.1.13 + version: 19.2.2 + '@types/react-dom': + specifier: ^19.1.9 + version: 19.2.2(@types/react@19.2.2) + '@vitejs/plugin-react': + specifier: ^5.0.3 + version: 5.0.4(vite@7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + bumpp: + specifier: ^10.3.1 + version: 10.3.1 + electron: + specifier: ^38.1.2 + version: 38.3.0 + electron-builder: + specifier: ^25.1.8 + version: 25.1.8(electron-builder-squirrel-windows@25.1.8) + electron-vite: + specifier: ^4.0.1 + version: 4.0.1(vite@7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + react: + specifier: ^19.1.1 + version: 19.2.0 + react-dom: + specifier: ^19.1.1 + version: 19.2.0(react@19.2.0) + typescript: + specifier: ^5.9.2 + version: 5.9.3 + unplugin-icons: + specifier: ^22.4.2 + version: 22.5.0(@svgr/core@8.1.0(typescript@5.9.3)) + vite: + specifier: ^7.1.6 + version: 7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + +packages: + + 7zip-bin@5.2.0: + resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} + + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@antfu/utils@9.3.0': + resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.4': + resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.4': + resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.3': + resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.4': + resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.4': + resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.4': + resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + engines: {node: '>=6.9.0'} + + '@biomejs/biome@2.2.4': + resolution: {integrity: sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@2.2.4': + resolution: {integrity: sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@2.2.4': + resolution: {integrity: sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@2.2.4': + resolution: {integrity: sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@biomejs/cli-linux-arm64@2.2.4': + resolution: {integrity: sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@biomejs/cli-linux-x64-musl@2.2.4': + resolution: {integrity: sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@biomejs/cli-linux-x64@2.2.4': + resolution: {integrity: sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@biomejs/cli-win32-arm64@2.2.4': + resolution: {integrity: sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.2.4': + resolution: {integrity: sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@develar/schema-utils@2.6.5': + resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} + engines: {node: '>= 8.9.0'} + + '@electron-toolkit/preload@3.0.2': + resolution: {integrity: sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==} + peerDependencies: + electron: '>=13.0.0' + + '@electron-toolkit/tsconfig@2.0.0': + resolution: {integrity: sha512-AdPsP770WhW7b260h13SHMdmjEEHJL6xFtgi3jwgdsSQbJOkJLeNnnpZW9qxTPCvmRI6vmdzWz5K3gibFS6SNg==} + peerDependencies: + '@types/node': '*' + + '@electron-toolkit/utils@4.0.0': + resolution: {integrity: sha512-qXSntwEzluSzKl4z5yFNBknmPGjPa3zFhE4mp9+h0cgokY5ornAeP+CJQDBhKsL1S58aOQfcwkD3NwLZCl+64g==} + peerDependencies: + electron: '>=13.0.0' + + '@electron/asar@3.4.1': + resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} + engines: {node: '>=10.12.0'} + hasBin: true + + '@electron/get@2.0.3': + resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} + engines: {node: '>=12'} + + '@electron/notarize@2.5.0': + resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} + engines: {node: '>= 10.0.0'} + + '@electron/osx-sign@1.3.1': + resolution: {integrity: sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==} + engines: {node: '>=12.0.0'} + hasBin: true + + '@electron/rebuild@3.6.1': + resolution: {integrity: sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==} + engines: {node: '>=12.13.0'} + hasBin: true + + '@electron/universal@2.0.1': + resolution: {integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==} + engines: {node: '>=16.4'} + + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@gar/promisify@1.1.3': + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + + '@hookform/resolvers@5.2.2': + resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} + peerDependencies: + react-hook-form: ^7.55.0 + + '@iconify/json@2.2.398': + resolution: {integrity: sha512-SEUDjkyAenAKMd5hDfzNzeObZw+KgQdIHaOuWA4yv89qSf2s0dJ7L1iXhRjtEZxFnuXQ2D67uFiHmE+90jvDGQ==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.0.2': + resolution: {integrity: sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ==} + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@malept/cross-spawn-promise@2.0.0': + resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} + engines: {node: '>= 12.13.0'} + + '@malept/flatpak-bundler@0.4.0': + resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} + engines: {node: '>= 10.0.0'} + + '@npmcli/fs@2.1.2': + resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + '@npmcli/move-file@2.0.1': + resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This functionality has been moved to @npmcli/fs + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-accordion@1.2.12': + resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.3': + resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collapsible@1.1.12': + resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.16': + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.7': + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-progress@1.1.7': + resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.10': + resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.7': + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@rolldown/pluginutils@1.0.0-beta.38': + resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} + + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} + cpu: [x64] + os: [win32] + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0': + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0': + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0': + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0': + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-preset@8.1.0': + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/core@8.1.0': + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} + engines: {node: '>=14'} + + '@svgr/hast-util-to-babel-ast@8.0.0': + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} + engines: {node: '>=14'} + + '@svgr/plugin-jsx@8.1.0': + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@tailwindcss/node@4.1.15': + resolution: {integrity: sha512-HF4+7QxATZWY3Jr8OlZrBSXmwT3Watj0OogeDvdUY/ByXJHQ+LBtqA2brDb3sBxYslIFx6UP94BJ4X6a4L9Bmw==} + + '@tailwindcss/oxide-android-arm64@4.1.15': + resolution: {integrity: sha512-TkUkUgAw8At4cBjCeVCRMc/guVLKOU1D+sBPrHt5uVcGhlbVKxrCaCW9OKUIBv1oWkjh4GbunD/u/Mf0ql6kEA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.15': + resolution: {integrity: sha512-xt5XEJpn2piMSfvd1UFN6jrWXyaKCwikP4Pidcf+yfHTSzSpYhG3dcMktjNkQO3JiLCp+0bG0HoWGvz97K162w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.15': + resolution: {integrity: sha512-TnWaxP6Bx2CojZEXAV2M01Yl13nYPpp0EtGpUrY+LMciKfIXiLL2r/SiSRpagE5Fp2gX+rflp/Os1VJDAyqymg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.15': + resolution: {integrity: sha512-quISQDWqiB6Cqhjc3iWptXVZHNVENsWoI77L1qgGEHNIdLDLFnw3/AfY7DidAiiCIkGX/MjIdB3bbBZR/G2aJg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.15': + resolution: {integrity: sha512-ObG76+vPlab65xzVUQbExmDU9FIeYLQ5k2LrQdR2Ud6hboR+ZobXpDoKEYXf/uOezOfIYmy2Ta3w0ejkTg9yxg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.15': + resolution: {integrity: sha512-4WbBacRmk43pkb8/xts3wnOZMDKsPFyEH/oisCm2q3aLZND25ufvJKcDUpAu0cS+CBOL05dYa8D4U5OWECuH/Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.15': + resolution: {integrity: sha512-AbvmEiteEj1nf42nE8skdHv73NoR+EwXVSgPY6l39X12Ex8pzOwwfi3Kc8GAmjsnsaDEbk+aj9NyL3UeyHcTLg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.15': + resolution: {integrity: sha512-+rzMVlvVgrXtFiS+ES78yWgKqpThgV19ISKD58Ck+YO5pO5KjyxLt7AWKsWMbY0R9yBDC82w6QVGz837AKQcHg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.1.15': + resolution: {integrity: sha512-fPdEy7a8eQN9qOIK3Em9D3TO1z41JScJn8yxl/76mp4sAXFDfV4YXxsiptJcOwy6bGR+70ZSwFIZhTXzQeqwQg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.1.15': + resolution: {integrity: sha512-sJ4yd6iXXdlgIMfIBXuVGp/NvmviEoMVWMOAGxtxhzLPp9LOj5k0pMEMZdjeMCl4C6Up+RM8T3Zgk+BMQ0bGcQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.15': + resolution: {integrity: sha512-sJGE5faXnNQ1iXeqmRin7Ds/ru2fgCiaQZQQz3ZGIDtvbkeV85rAZ0QJFMDg0FrqsffZG96H1U9AQlNBRLsHVg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.15': + resolution: {integrity: sha512-NLeHE7jUV6HcFKS504bpOohyi01zPXi2PXmjFfkzTph8xRxDdxkRsXm/xDO5uV5K3brrE1cCwbUYmFUSHR3u1w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.15': + resolution: {integrity: sha512-krhX+UOOgnsUuks2SR7hFafXmLQrKxB4YyRTERuCE59JlYL+FawgaAlSkOYmDRJdf1Q+IFNDMl9iRnBW7QBDfQ==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.15': + resolution: {integrity: sha512-B6s60MZRTUil+xKoZoGe6i0Iar5VuW+pmcGlda2FX+guDuQ1G1sjiIy1W0frneVpeL/ZjZ4KEgWZHNrIm++2qA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/fs-extra@9.0.13': + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@22.18.12': + resolution: {integrity: sha512-BICHQ67iqxQGFSzfCFTT7MRQ5XcBjG5aeKh5Ok38UBbPe5fxTyE+aHFxwVrGyr8GNlqFMLKD1D3P2K/1ks8tog==} + + '@types/plist@3.0.5': + resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} + + '@types/react-dom@19.2.2': + resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.2': + resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/verror@1.10.11': + resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@vitejs/plugin-react@5.0.4': + resolution: {integrity: sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@xmldom/xmldom@0.8.11': + resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} + engines: {node: '>=10.0.0'} + + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + 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==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + + app-builder-bin@5.0.0-alpha.10: + resolution: {integrity: sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==} + + app-builder-lib@25.1.8: + resolution: {integrity: sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==} + engines: {node: '>=14.0.0'} + peerDependencies: + dmg-builder: 25.1.8 + electron-builder-squirrel-windows: 25.1.8 + + aproba@2.1.0: + resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==} + + archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + + archiver-utils@3.0.4: + resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} + engines: {node: '>= 10'} + + archiver@5.3.2: + resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} + engines: {node: '>= 10'} + + are-we-there-yet@3.0.1: + resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + args-tokenizer@0.3.0: + resolution: {integrity: sha512-xXAd7G2Mll5W8uo37GETpQ2VrE84M181Z7ugHFGQnJZ50M2mbOv0osSZ9VsSgPfJQ+LVG0prSi0th+ELMsno7Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + 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==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + atomically@2.0.3: + resolution: {integrity: sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.8.18: + resolution: {integrity: sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==} + hasBin: true + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + bluebird-lst@1.0.9: + resolution: {integrity: sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + boolean@3.2.0: + resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + browserslist@4.26.3: + resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + 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-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + builder-util-runtime@9.2.10: + resolution: {integrity: sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==} + engines: {node: '>=12.0.0'} + + builder-util-runtime@9.3.1: + resolution: {integrity: sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==} + engines: {node: '>=12.0.0'} + + builder-util@25.1.7: + resolution: {integrity: sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==} + + bumpp@10.3.1: + resolution: {integrity: sha512-cOKPRFCWvHcYPJQAHN6V7Jp/wAfnyqQRXQ+2fgWIL6Gao20rpu7xQ1cGGo1APOfmbQmmHngEPg9Fy7nJ3giRkQ==} + engines: {node: '>=18'} + hasBin: true + + c12@3.3.1: + resolution: {integrity: sha512-LcWQ01LT9tkoUINHgpIOv3mMs+Abv7oVCrtpMRi1PaapVEpWoMga5WuT7/DqFTu7URP9ftbOmimNw1KNIGh9DQ==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cacache@16.1.3: + resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001751: + resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + chromium-pickle-js@0.2.0: + resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + 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@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + + compare-version@0.1.2: + resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} + engines: {node: '>=0.10.0'} + + compress-commons@4.1.2: + resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} + engines: {node: '>= 10'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + conf@15.0.2: + resolution: {integrity: sha512-JBSrutapCafTrddF9dH3lc7+T2tBycGF4uPkI4Js+g4vLLEhG6RZcFi3aJd5zntdf5tQxAejJt8dihkoQ/eSJw==} + engines: {node: '>=20'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + + config-file-ts@0.2.8-rc1: + resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@4.0.3: + resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} + engines: {node: '>= 10'} + + crc@3.8.0: + resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + dayjs@1.11.18: + resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==} + + debounce-fn@6.0.0: + resolution: {integrity: sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==} + engines: {node: '>=18'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + 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'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + + dir-compare@4.2.0: + resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} + + dmg-builder@25.1.8: + resolution: {integrity: sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==} + + dmg-license@1.0.11: + resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} + engines: {node: '>=8'} + os: [darwin] + hasBin: true + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dot-prop@10.1.0: + resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} + engines: {node: '>=20'} + + dotenv-expand@11.0.7: + resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dotenv@17.2.3: + resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-builder-squirrel-windows@25.1.8: + resolution: {integrity: sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==} + + electron-builder@25.1.8: + resolution: {integrity: sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==} + engines: {node: '>=14.0.0'} + hasBin: true + + electron-ipc-decorator@0.2.0: + resolution: {integrity: sha512-7020pQ/8qdm+CkVQRQG1A0zhWERI4OFyCnULtcPFv4JJRE1rwfBKrKwWIxsoeFpjBEGEV1M7Ms5FGt2jLrMY5g==} + engines: {node: '>=18.0.0'} + peerDependencies: + electron: '>=32.0.0' + + electron-log@5.4.3: + resolution: {integrity: sha512-sOUsM3LjZdugatazSQ/XTyNcw8dfvH1SYhXWiJyfYodAAKOZdHs0txPiLDXFzOZbhXgAgshQkshH2ccq0feyLQ==} + engines: {node: '>= 14'} + + electron-publish@25.1.7: + resolution: {integrity: sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==} + + electron-store@11.0.2: + resolution: {integrity: sha512-4VkNRdN+BImL2KcCi41WvAYbh6zLX5AUTi4so68yPqiItjbgTjqpEnGAqasgnG+lB6GuAyUltKwVopp6Uv+gwQ==} + engines: {node: '>=20'} + + electron-to-chromium@1.5.237: + resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==} + + electron-updater@6.6.2: + resolution: {integrity: sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw==} + + electron-vite@4.0.1: + resolution: {integrity: sha512-QqacJbA8f1pmwUTqki1qLL5vIBaOQmeq13CZZefZ3r3vKVaIoC7cpoTgE+KPKxJDFTax+iFZV0VYvLVWPiQ8Aw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@swc/core': ^1.0.0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + '@swc/core': + optional: true + + electron@38.3.0: + resolution: {integrity: sha512-Wij4AzX4SAV0X/ktq+NrWrp5piTCSS8F6YWh1KAcG+QRtNzyns9XLKERP68nFHIwfprhxF2YCN2uj7nx9DaeJw==} + engines: {node: '>= 12.20.55'} + hasBin: true + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + extsprintf@1.4.1: + resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} + engines: {'0': node >=0.6.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + engines: {node: '>=14.14'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + 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==} + + gauge@4.0.4: + resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + 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 + + global-agent@3.0.0: + resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} + engines: {node: '>=10.0'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + 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-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + i18next@25.6.0: + resolution: {integrity: sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw==} + peerDependencies: + typescript: ^5 + peerDependenciesMeta: + typescript: + optional: true + + iconv-corefoundation@1.1.7: + resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} + engines: {node: ^8.11.2 || >=10} + os: [darwin] + + 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==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + + 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==} + + ip-address@10.0.1: + resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + engines: {node: '>= 12'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isbinaryfile@4.0.10: + resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} + engines: {node: '>= 8.0.0'} + + isbinaryfile@5.0.6: + resolution: {integrity: sha512-I+NmIfBHUl+r2wcDd6JwE9yWje/PIVY/R5/CmV8dXLZd5K+L9X2klAOwfAHNnondLXkbHyTAleQAWonpTJBTtw==} + engines: {node: '>= 18.0.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jake@10.9.4: + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} + hasBin: true + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + jotai@2.15.0: + resolution: {integrity: sha512-nbp/6jN2Ftxgw0VwoVnOg0m5qYM1rVcfvij+MZx99Z5IK13eGve9FJoCwGv+17JvVthTjhSmNtT5e1coJnr6aw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@babel/core': '>=7.0.0' + '@babel/template': '>=7.0.0' + '@types/react': '>=17.0.0' + react: '>=17.0.0' + peerDependenciesMeta: + '@babel/core': + optional: true + '@babel/template': + optional: true + '@types/react': + optional: true + react: + optional: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + 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-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.1: + resolution: {integrity: sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + lazy-val@1.0.5: + resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + + lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lucide-react@0.544.0: + resolution: {integrity: sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + + make-fetch-happen@10.2.1: + resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + matcher@3.0.0: + resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} + engines: {node: '>=10'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + 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'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + + 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-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + + minipass-fetch@2.1.2: + resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-abi@3.78.0: + resolution: {integrity: sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==} + engines: {node: '>=10'} + + node-addon-api@1.7.2: + resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} + + node-api-version@0.2.1: + resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-gyp@9.4.1: + resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==} + engines: {node: ^12.13 || ^14.13 || >=16} + hasBin: true + + node-releases@2.0.25: + resolution: {integrity: sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==} + + nopt@6.0.0: + resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + npmlog@6.0.2: + resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + + nypm@0.6.2: + resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-manager-detector@1.5.0: + resolution: {integrity: sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + 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-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pe-library@0.4.1: + resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} + engines: {node: '>=12', npm: '>=6'} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + perfect-debounce@2.0.0: + resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + + plist@3.1.0: + resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} + engines: {node: '>=10.4.0'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + peerDependencies: + react: ^19.2.0 + + react-hook-form@7.65.0: + resolution: {integrity: sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-i18next@16.1.2: + resolution: {integrity: sha512-AxZAojM6CsP9qWUu8d0XD0KXYBG6yyitcWRRPSRXgGVkJ47hCIy3Mc/sE9deB0k+OK9WcC04vSFoQC9QdMcd6Q==} + peerDependencies: + i18next: '>= 25.5.2' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + typescript: ^5 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-router@7.9.4: + resolution: {integrity: sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + read-binary-file-arch@1.0.6: + resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} + hasBin: true + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resedit@1.7.2: + resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} + engines: {node: '>=12', npm: '>=6'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + roarr@2.15.4: + resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} + engines: {node: '>=8.0'} + + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sanitize-filename@1.6.3: + resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + + 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'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + + slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + socks-proxy-agent@7.0.0: + resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} + engines: {node: '>= 10'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + 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'} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + ssri@9.0.1: + resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + stat-mode@1.0.0: + resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} + engines: {node: '>= 6'} + + 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_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.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + + stubborn-fs@1.2.5: + resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} + + sumchecker@3.0.1: + resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} + engines: {node: '>= 8.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + tailwind-merge@3.3.1: + resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} + + tailwindcss@4.1.15: + resolution: {integrity: sha512-k2WLnWkYFkdpRv+Oby3EBXIyQC8/s1HOFMBUViwtAh6Z5uAozeUSMQlIsn/c6Q2iJzqG6aJT3wdPaRNj70iYxQ==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + + temp-file@3.4.0: + resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} + + tiny-typed-emitter@2.1.0: + resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==} + + tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tmp-promise@3.0.3: + resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} + + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + + type-fest@5.1.0: + resolution: {integrity: sha512-wQ531tuWvB6oK+pchHIu5lHe5f5wpSCqB8Kf4dWQRbOYc9HTge7JL0G4Qd44bh6QuJCccIzL3bugb8GI0MwHrg==} + engines: {node: '>=20'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unique-filename@2.0.1: + resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + unique-slug@3.0.0: + resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unplugin-icons@22.5.0: + resolution: {integrity: sha512-MBlMtT5RuMYZy4TZgqUL2OTtOdTUVsS1Mhj6G1pEzMlFJlEnq6mhUfoIt45gBWxHcsOdXJDWLg3pRZ+YmvAVWQ==} + peerDependencies: + '@svgr/core': '>=7.0.0' + '@svgx/core': ^1.0.1 + '@vue/compiler-sfc': ^3.0.2 || ^2.7.0 + svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 + vue-template-compiler: ^2.6.12 + vue-template-es2015-compiler: ^1.9.0 + peerDependenciesMeta: + '@svgr/core': + optional: true + '@svgx/core': + optional: true + '@vue/compiler-sfc': + optional: true + svelte: + optional: true + vue-template-compiler: + optional: true + vue-template-es2015-compiler: + optional: true + + unplugin@2.3.10: + resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==} + engines: {node: '>=18.12.0'} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + verror@1.10.1: + resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} + engines: {node: '>=0.6.0'} + + vite@7.1.11: + resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + 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 + + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + when-exit@2.1.4: + resolution: {integrity: sha512-4rnvd3A1t16PWzrBUcSDZqcAmsUIy4minDXT/CZ8F2mVDgd65i4Aalimgz1aQkRGU0iH5eT5+6Rx2TK8o443Pg==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + + 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'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + 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==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yt-dlp-wrap-plus@2.3.20: + resolution: {integrity: sha512-vKQfQMvvSbTta+mrRrMFYm+e/vkbHK5X9L2LiO3JRVHUmEjzpk8qdFpQwp27FPIA7nLR17AZA5gG9yEVcF3avQ==} + + zip-stream@4.1.1: + resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} + engines: {node: '>= 10'} + + zod@4.1.12: + resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + +snapshots: + + 7zip-bin@5.2.0: {} + + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.5.0 + tinyexec: 1.0.1 + + '@antfu/utils@9.3.0': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.4': {} + + '@babel/core@7.28.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.3': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.4 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.26.3 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + + '@babel/parser@7.28.4': + dependencies: + '@babel/types': 7.28.4 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + + '@babel/traverse@7.28.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.4': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@biomejs/biome@2.2.4': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.2.4 + '@biomejs/cli-darwin-x64': 2.2.4 + '@biomejs/cli-linux-arm64': 2.2.4 + '@biomejs/cli-linux-arm64-musl': 2.2.4 + '@biomejs/cli-linux-x64': 2.2.4 + '@biomejs/cli-linux-x64-musl': 2.2.4 + '@biomejs/cli-win32-arm64': 2.2.4 + '@biomejs/cli-win32-x64': 2.2.4 + + '@biomejs/cli-darwin-arm64@2.2.4': + optional: true + + '@biomejs/cli-darwin-x64@2.2.4': + optional: true + + '@biomejs/cli-linux-arm64-musl@2.2.4': + optional: true + + '@biomejs/cli-linux-arm64@2.2.4': + optional: true + + '@biomejs/cli-linux-x64-musl@2.2.4': + optional: true + + '@biomejs/cli-linux-x64@2.2.4': + optional: true + + '@biomejs/cli-win32-arm64@2.2.4': + optional: true + + '@biomejs/cli-win32-x64@2.2.4': + optional: true + + '@develar/schema-utils@2.6.5': + dependencies: + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + '@electron-toolkit/preload@3.0.2(electron@38.3.0)': + dependencies: + electron: 38.3.0 + + '@electron-toolkit/tsconfig@2.0.0(@types/node@22.18.12)': + dependencies: + '@types/node': 22.18.12 + + '@electron-toolkit/utils@4.0.0(electron@38.3.0)': + dependencies: + electron: 38.3.0 + + '@electron/asar@3.4.1': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.2 + + '@electron/get@2.0.3': + dependencies: + debug: 4.4.3 + env-paths: 2.2.1 + fs-extra: 8.1.0 + got: 11.8.6 + progress: 2.0.3 + semver: 6.3.1 + sumchecker: 3.0.1 + optionalDependencies: + global-agent: 3.0.0 + transitivePeerDependencies: + - supports-color + + '@electron/notarize@2.5.0': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + promise-retry: 2.0.1 + transitivePeerDependencies: + - supports-color + + '@electron/osx-sign@1.3.1': + dependencies: + compare-version: 0.1.2 + debug: 4.4.3 + fs-extra: 10.1.0 + isbinaryfile: 4.0.10 + minimist: 1.2.8 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/rebuild@3.6.1': + dependencies: + '@malept/cross-spawn-promise': 2.0.0 + chalk: 4.1.2 + debug: 4.4.3 + detect-libc: 2.1.2 + fs-extra: 10.1.0 + got: 11.8.6 + node-abi: 3.78.0 + node-api-version: 0.2.1 + node-gyp: 9.4.1 + ora: 5.4.1 + read-binary-file-arch: 1.0.6 + semver: 7.7.3 + tar: 6.2.1 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - supports-color + + '@electron/universal@2.0.1': + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.3 + dir-compare: 4.2.0 + fs-extra: 11.3.2 + minimatch: 9.0.5 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@esbuild/aix-ppc64@0.25.11': + optional: true + + '@esbuild/android-arm64@0.25.11': + optional: true + + '@esbuild/android-arm@0.25.11': + optional: true + + '@esbuild/android-x64@0.25.11': + optional: true + + '@esbuild/darwin-arm64@0.25.11': + optional: true + + '@esbuild/darwin-x64@0.25.11': + optional: true + + '@esbuild/freebsd-arm64@0.25.11': + optional: true + + '@esbuild/freebsd-x64@0.25.11': + optional: true + + '@esbuild/linux-arm64@0.25.11': + optional: true + + '@esbuild/linux-arm@0.25.11': + optional: true + + '@esbuild/linux-ia32@0.25.11': + optional: true + + '@esbuild/linux-loong64@0.25.11': + optional: true + + '@esbuild/linux-mips64el@0.25.11': + optional: true + + '@esbuild/linux-ppc64@0.25.11': + optional: true + + '@esbuild/linux-riscv64@0.25.11': + optional: true + + '@esbuild/linux-s390x@0.25.11': + optional: true + + '@esbuild/linux-x64@0.25.11': + optional: true + + '@esbuild/netbsd-arm64@0.25.11': + optional: true + + '@esbuild/netbsd-x64@0.25.11': + optional: true + + '@esbuild/openbsd-arm64@0.25.11': + optional: true + + '@esbuild/openbsd-x64@0.25.11': + optional: true + + '@esbuild/openharmony-arm64@0.25.11': + optional: true + + '@esbuild/sunos-x64@0.25.11': + optional: true + + '@esbuild/win32-arm64@0.25.11': + optional: true + + '@esbuild/win32-ia32@0.25.11': + optional: true + + '@esbuild/win32-x64@0.25.11': + optional: true + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@floating-ui/utils@0.2.10': {} + + '@gar/promisify@1.1.3': {} + + '@hookform/resolvers@5.2.2(react-hook-form@7.65.0(react@19.2.0))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.65.0(react@19.2.0) + + '@iconify/json@2.2.398': + dependencies: + '@iconify/types': 2.0.0 + pathe: 2.0.3 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.0.2': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 9.3.0 + '@iconify/types': 2.0.0 + debug: 4.4.3 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.1.2 + mlly: 1.8.0 + transitivePeerDependencies: + - supports-color + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@malept/cross-spawn-promise@2.0.0': + dependencies: + cross-spawn: 7.0.6 + + '@malept/flatpak-bundler@0.4.0': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + lodash: 4.17.21 + tmp-promise: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@npmcli/fs@2.1.2': + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.7.3 + + '@npmcli/move-file@2.0.1': + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.2)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.2 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + + '@radix-ui/rect@1.1.1': {} + + '@rolldown/pluginutils@1.0.0-beta.38': {} + + '@rollup/rollup-android-arm-eabi@4.52.5': + optional: true + + '@rollup/rollup-android-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-x64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-musl@4.52.5': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.5': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.52.5': + optional: true + + '@sindresorhus/is@4.6.0': {} + + '@standard-schema/utils@0.3.0': {} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + + '@svgr/babel-preset@8.1.0(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.4) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.4) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.4) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.4) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.4) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.4) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.4) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.4) + + '@svgr/core@8.1.0(typescript@5.9.3)': + dependencies: + '@babel/core': 7.28.4 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.9.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@svgr/hast-util-to-babel-ast@8.0.0': + dependencies: + '@babel/types': 7.28.4 + entities: 4.5.0 + + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + dependencies: + '@babel/core': 7.28.4 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@tailwindcss/node@4.1.15': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.19 + source-map-js: 1.2.1 + tailwindcss: 4.1.15 + + '@tailwindcss/oxide-android-arm64@4.1.15': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.15': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.15': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.15': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.15': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.15': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.15': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.15': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.15': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.15': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.15': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.15': + optional: true + + '@tailwindcss/oxide@4.1.15': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.15 + '@tailwindcss/oxide-darwin-arm64': 4.1.15 + '@tailwindcss/oxide-darwin-x64': 4.1.15 + '@tailwindcss/oxide-freebsd-x64': 4.1.15 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.15 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.15 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.15 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.15 + '@tailwindcss/oxide-linux-x64-musl': 4.1.15 + '@tailwindcss/oxide-wasm32-wasi': 4.1.15 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.15 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.15 + + '@tailwindcss/vite@4.1.15(vite@7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + dependencies: + '@tailwindcss/node': 4.1.15 + '@tailwindcss/oxide': 4.1.15 + tailwindcss: 4.1.15 + vite: 7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + + '@tootallnate/once@2.0.0': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.4 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.4 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 22.18.12 + '@types/responselike': 1.0.3 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree@1.0.8': {} + + '@types/fs-extra@9.0.13': + dependencies: + '@types/node': 22.18.12 + + '@types/http-cache-semantics@4.0.4': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 22.18.12 + + '@types/ms@2.1.0': {} + + '@types/node@22.18.12': + dependencies: + undici-types: 6.21.0 + + '@types/plist@3.0.5': + dependencies: + '@types/node': 22.18.12 + xmlbuilder: 15.1.1 + optional: true + + '@types/react-dom@19.2.2(@types/react@19.2.2)': + dependencies: + '@types/react': 19.2.2 + + '@types/react@19.2.2': + dependencies: + csstype: 3.1.3 + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 22.18.12 + + '@types/verror@1.10.11': + optional: true + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 22.18.12 + optional: true + + '@vitejs/plugin-react@5.0.4(vite@7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) + '@rolldown/pluginutils': 1.0.0-beta.38 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + + '@xmldom/xmldom@0.8.11': {} + + abbrev@1.1.1: {} + + acorn@8.15.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + agent-base@7.1.4: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + 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 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + ansis@4.2.0: {} + + app-builder-bin@5.0.0-alpha.10: {} + + app-builder-lib@25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8): + dependencies: + '@develar/schema-utils': 2.6.5 + '@electron/notarize': 2.5.0 + '@electron/osx-sign': 1.3.1 + '@electron/rebuild': 3.6.1 + '@electron/universal': 2.0.1 + '@malept/flatpak-bundler': 0.4.0 + '@types/fs-extra': 9.0.13 + async-exit-hook: 2.0.1 + bluebird-lst: 1.0.9 + builder-util: 25.1.7 + builder-util-runtime: 9.2.10 + chromium-pickle-js: 0.2.0 + config-file-ts: 0.2.8-rc1 + debug: 4.4.3 + dmg-builder: 25.1.8(electron-builder-squirrel-windows@25.1.8) + dotenv: 16.6.1 + dotenv-expand: 11.0.7 + ejs: 3.1.10 + electron-builder-squirrel-windows: 25.1.8(dmg-builder@25.1.8) + electron-publish: 25.1.7 + form-data: 4.0.4 + fs-extra: 10.1.0 + hosted-git-info: 4.1.0 + is-ci: 3.0.1 + isbinaryfile: 5.0.6 + js-yaml: 4.1.0 + json5: 2.2.3 + lazy-val: 1.0.5 + minimatch: 10.0.3 + resedit: 1.7.2 + sanitize-filename: 1.6.3 + semver: 7.7.3 + tar: 6.2.1 + temp-file: 3.4.0 + transitivePeerDependencies: + - bluebird + - supports-color + + aproba@2.1.0: {} + + archiver-utils@2.1.0: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.8 + + archiver-utils@3.0.4: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + archiver@5.3.2: + dependencies: + archiver-utils: 2.1.0 + async: 3.2.6 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 2.2.0 + zip-stream: 4.1.1 + + are-we-there-yet@3.0.1: + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + + argparse@2.0.1: {} + + args-tokenizer@0.3.0: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + assert-plus@1.0.0: + optional: true + + astral-regex@2.0.0: + optional: true + + async-exit-hook@2.0.1: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + atomically@2.0.3: + dependencies: + stubborn-fs: 1.2.5 + when-exit: 2.1.4 + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.8.18: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + bluebird-lst@1.0.9: + dependencies: + bluebird: 3.7.2 + + bluebird@3.7.2: {} + + boolean@3.2.0: + optional: true + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + browserslist@4.26.3: + dependencies: + baseline-browser-mapping: 2.8.18 + caniuse-lite: 1.0.30001751 + electron-to-chromium: 1.5.237 + node-releases: 2.0.25 + update-browserslist-db: 1.1.3(browserslist@4.26.3) + + buffer-crc32@0.2.13: {} + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + builder-util-runtime@9.2.10: + dependencies: + debug: 4.4.3 + sax: 1.4.1 + transitivePeerDependencies: + - supports-color + + builder-util-runtime@9.3.1: + dependencies: + debug: 4.4.3 + sax: 1.4.1 + transitivePeerDependencies: + - supports-color + + builder-util@25.1.7: + dependencies: + 7zip-bin: 5.2.0 + '@types/debug': 4.1.12 + app-builder-bin: 5.0.0-alpha.10 + bluebird-lst: 1.0.9 + builder-util-runtime: 9.2.10 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + fs-extra: 10.1.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-ci: 3.0.1 + js-yaml: 4.1.0 + source-map-support: 0.5.21 + stat-mode: 1.0.0 + temp-file: 3.4.0 + transitivePeerDependencies: + - supports-color + + bumpp@10.3.1: + dependencies: + ansis: 4.2.0 + args-tokenizer: 0.3.0 + c12: 3.3.1 + cac: 6.7.14 + escalade: 3.2.0 + jsonc-parser: 3.3.1 + package-manager-detector: 1.5.0 + semver: 7.7.3 + tinyexec: 1.0.1 + tinyglobby: 0.2.15 + yaml: 2.8.1 + transitivePeerDependencies: + - magicast + + c12@3.3.1: + dependencies: + chokidar: 4.0.3 + confbox: 0.2.2 + defu: 6.1.4 + dotenv: 17.2.3 + exsolve: 1.0.7 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + rc9: 2.1.2 + + cac@6.7.14: {} + + cacache@16.1.3: + dependencies: + '@npmcli/fs': 2.1.2 + '@npmcli/move-file': 2.0.1 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 8.1.0 + infer-owner: 1.0.4 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 9.0.1 + tar: 6.2.1 + unique-filename: 2.0.1 + transitivePeerDependencies: + - bluebird + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001751: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chownr@2.0.0: {} + + chromium-pickle-js@0.2.0: {} + + ci-info@3.9.0: {} + + citty@0.1.6: + dependencies: + consola: 3.4.2 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.9.2: {} + + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + optional: true + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + clone@1.0.4: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-support@1.1.3: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@5.1.0: {} + + compare-version@0.1.2: {} + + compress-commons@4.1.2: + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.3 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + concat-map@0.0.1: {} + + conf@15.0.2: + dependencies: + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + atomically: 2.0.3 + debounce-fn: 6.0.0 + dot-prop: 10.1.0 + env-paths: 3.0.0 + json-schema-typed: 8.0.1 + semver: 7.7.3 + uint8array-extras: 1.5.0 + + confbox@0.1.8: {} + + confbox@0.2.2: {} + + config-file-ts@0.2.8-rc1: + dependencies: + glob: 10.4.5 + typescript: 5.9.3 + + consola@3.4.2: {} + + console-control-strings@1.1.0: {} + + convert-source-map@2.0.0: {} + + cookie@1.0.2: {} + + core-util-is@1.0.2: + optional: true + + core-util-is@1.0.3: {} + + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + + crc-32@1.2.2: {} + + crc32-stream@4.0.3: + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + + crc@3.8.0: + dependencies: + buffer: 5.7.1 + optional: true + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + dayjs@1.11.18: {} + + debounce-fn@6.0.0: + dependencies: + mimic-function: 5.0.1 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + optional: true + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + optional: true + + defu@6.1.4: {} + + delayed-stream@1.0.0: {} + + delegates@1.0.0: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + detect-node-es@1.1.0: {} + + detect-node@2.1.0: + optional: true + + dir-compare@4.2.0: + dependencies: + minimatch: 3.1.2 + p-limit: 3.1.0 + + dmg-builder@25.1.8(electron-builder-squirrel-windows@25.1.8): + dependencies: + app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8) + builder-util: 25.1.7 + builder-util-runtime: 9.2.10 + fs-extra: 10.1.0 + iconv-lite: 0.6.3 + js-yaml: 4.1.0 + optionalDependencies: + dmg-license: 1.0.11 + transitivePeerDependencies: + - bluebird + - electron-builder-squirrel-windows + - supports-color + + dmg-license@1.0.11: + dependencies: + '@types/plist': 3.0.5 + '@types/verror': 1.10.11 + ajv: 6.12.6 + crc: 3.8.0 + iconv-corefoundation: 1.1.7 + plist: 3.1.0 + smart-buffer: 4.2.0 + verror: 1.10.1 + optional: true + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dot-prop@10.1.0: + dependencies: + type-fest: 5.1.0 + + dotenv-expand@11.0.7: + dependencies: + dotenv: 16.6.1 + + dotenv@16.6.1: {} + + dotenv@17.2.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8): + dependencies: + app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8) + archiver: 5.3.2 + builder-util: 25.1.7 + fs-extra: 10.1.0 + transitivePeerDependencies: + - bluebird + - dmg-builder + - supports-color + + electron-builder@25.1.8(electron-builder-squirrel-windows@25.1.8): + dependencies: + app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8) + builder-util: 25.1.7 + builder-util-runtime: 9.2.10 + chalk: 4.1.2 + dmg-builder: 25.1.8(electron-builder-squirrel-windows@25.1.8) + fs-extra: 10.1.0 + is-ci: 3.0.1 + lazy-val: 1.0.5 + simple-update-notifier: 2.0.0 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - electron-builder-squirrel-windows + - supports-color + + electron-ipc-decorator@0.2.0(electron@38.3.0): + dependencies: + electron: 38.3.0 + + electron-log@5.4.3: {} + + electron-publish@25.1.7: + dependencies: + '@types/fs-extra': 9.0.13 + builder-util: 25.1.7 + builder-util-runtime: 9.2.10 + chalk: 4.1.2 + fs-extra: 10.1.0 + lazy-val: 1.0.5 + mime: 2.6.0 + transitivePeerDependencies: + - supports-color + + electron-store@11.0.2: + dependencies: + conf: 15.0.2 + type-fest: 5.1.0 + + electron-to-chromium@1.5.237: {} + + electron-updater@6.6.2: + dependencies: + builder-util-runtime: 9.3.1 + fs-extra: 10.1.0 + js-yaml: 4.1.0 + lazy-val: 1.0.5 + lodash.escaperegexp: 4.1.2 + lodash.isequal: 4.5.0 + semver: 7.7.3 + tiny-typed-emitter: 2.1.0 + transitivePeerDependencies: + - supports-color + + electron-vite@4.0.1(vite@7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)): + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.4) + cac: 6.7.14 + esbuild: 0.25.11 + magic-string: 0.30.19 + picocolors: 1.1.1 + vite: 7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + + electron@38.3.0: + dependencies: + '@electron/get': 2.0.3 + '@types/node': 22.18.12 + extract-zip: 2.0.1 + transitivePeerDependencies: + - supports-color + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encoding@0.1.13: + dependencies: + iconv-lite: 0.6.3 + optional: true + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@4.5.0: {} + + env-paths@2.2.1: {} + + env-paths@3.0.0: {} + + err-code@2.0.3: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es6-error@4.1.1: + optional: true + + esbuild@0.25.11: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: + optional: true + + exponential-backoff@3.1.3: {} + + exsolve@1.0.7: {} + + extract-zip@2.0.1: + dependencies: + debug: 4.4.3 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + extsprintf@1.4.1: + optional: true + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-uri@3.1.0: {} + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fs-constants@1.0.0: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gauge@4.0.4: + dependencies: + aproba: 2.1.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@5.2.0: + dependencies: + pump: 3.0.3 + + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + node-fetch-native: 1.6.7 + nypm: 0.6.2 + pathe: 2.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.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 + + global-agent@3.0.0: + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.7.3 + serialize-error: 7.0.1 + optional: true + + globals@15.15.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + optional: true + + gopd@1.2.0: {} + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + optional: true + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + has-unicode@2.0.1: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + + http-cache-semantics@4.2.0: {} + + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + i18next@25.6.0(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.28.4 + optionalDependencies: + typescript: 5.9.3 + + iconv-corefoundation@1.1.7: + dependencies: + cli-truncate: 2.1.0 + node-addon-api: 1.7.2 + optional: true + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + infer-owner@1.0.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ip-address@10.0.1: {} + + is-arrayish@0.2.1: {} + + is-ci@3.0.1: + dependencies: + ci-info: 3.9.0 + + is-fullwidth-code-point@3.0.0: {} + + is-interactive@1.0.0: {} + + is-lambda@1.0.1: {} + + is-unicode-supported@0.1.0: {} + + isarray@1.0.0: {} + + isbinaryfile@4.0.10: {} + + isbinaryfile@5.0.6: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.4 + picocolors: 1.1.1 + + jiti@2.6.1: {} + + jotai@2.15.0(@babel/core@7.28.4)(@babel/template@7.27.2)(@types/react@19.2.2)(react@19.2.0): + optionalDependencies: + '@babel/core': 7.28.4 + '@babel/template': 7.27.2 + '@types/react': 19.2.2 + react: 19.2.0 + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.1: {} + + json-stringify-safe@5.0.1: + optional: true + + json5@2.2.3: {} + + jsonc-parser@3.3.1: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kolorist@1.8.0: {} + + lazy-val@1.0.5: {} + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + lines-and-columns@1.2.4: {} + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.0 + pkg-types: 2.3.0 + quansync: 0.2.11 + + lodash.defaults@4.2.0: {} + + lodash.difference@4.5.0: {} + + lodash.escaperegexp@4.1.2: {} + + lodash.flatten@4.4.0: {} + + lodash.isequal@4.5.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.union@4.6.0: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lowercase-keys@2.0.0: {} + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lru-cache@7.18.3: {} + + lucide-react@0.544.0(react@19.2.0): + dependencies: + react: 19.2.0 + + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-fetch-happen@10.2.1: + dependencies: + agentkeepalive: 4.6.0 + cacache: 16.1.3 + http-cache-semantics: 4.2.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 2.1.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.4 + promise-retry: 2.0.1 + socks-proxy-agent: 7.0.0 + ssri: 9.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + + matcher@3.0.0: + dependencies: + escape-string-regexp: 4.0.0 + optional: true + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@2.6.0: {} + + mimic-fn@2.1.0: {} + + mimic-function@5.0.1: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass-collect@1.0.2: + dependencies: + minipass: 3.3.6 + + minipass-fetch@2.1.2: + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + + minipass-flush@1.0.5: + dependencies: + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass-sized@1.0.3: + dependencies: + minipass: 3.3.6 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.2: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mkdirp@1.0.4: {} + + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + negotiator@0.6.4: {} + + next-themes@0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + node-abi@3.78.0: + dependencies: + semver: 7.7.3 + + node-addon-api@1.7.2: + optional: true + + node-api-version@0.2.1: + dependencies: + semver: 7.7.3 + + node-fetch-native@1.6.7: {} + + node-gyp@9.4.1: + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + glob: 7.2.3 + graceful-fs: 4.2.11 + make-fetch-happen: 10.2.1 + nopt: 6.0.0 + npmlog: 6.0.2 + rimraf: 3.0.2 + semver: 7.7.3 + tar: 6.2.1 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + + node-releases@2.0.25: {} + + nopt@6.0.0: + dependencies: + abbrev: 1.1.1 + + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + + npmlog@6.0.2: + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + + nypm@0.6.2: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 2.3.0 + tinyexec: 1.0.1 + + object-keys@1.1.1: + optional: true + + ohash@2.0.11: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + p-cancelable@2.1.1: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + package-json-from-dist@1.0.1: {} + + package-manager-detector@1.5.0: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + pe-library@0.4.1: {} + + pend@1.2.0: {} + + perfect-debounce@2.0.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + + pkg-types@2.3.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.7 + pathe: 2.0.3 + + plist@3.1.0: + dependencies: + '@xmldom/xmldom': 0.8.11 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + process-nextick-args@2.0.1: {} + + progress@2.0.3: {} + + promise-inflight@1.0.1: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + quansync@0.2.11: {} + + quick-lru@5.1.1: {} + + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + + react-hook-form@7.65.0(react@19.2.0): + dependencies: + react: 19.2.0 + + react-i18next@16.1.2(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.28.4 + html-parse-stringify: 3.0.1 + i18next: 25.6.0(typescript@5.9.3) + react: 19.2.0 + optionalDependencies: + react-dom: 19.2.0(react@19.2.0) + typescript: 5.9.3 + + react-refresh@0.17.0: {} + + react-remove-scroll-bar@2.3.8(@types/react@19.2.2)(react@19.2.0): + dependencies: + react: 19.2.0 + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + react-remove-scroll@2.7.1(@types/react@19.2.2)(react@19.2.0): + dependencies: + react: 19.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.2)(react@19.2.0) + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.2)(react@19.2.0) + use-sidecar: 1.1.3(@types/react@19.2.2)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + + react-router@7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + cookie: 1.0.2 + react: 19.2.0 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.2.0(react@19.2.0) + + react-style-singleton@2.2.3(@types/react@19.2.2)(react@19.2.0): + dependencies: + get-nonce: 1.0.1 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + react@19.2.0: {} + + read-binary-file-arch@1.0.6: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + 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@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + + readdirp@4.1.2: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resedit@1.7.2: + dependencies: + pe-library: 0.4.1 + + resolve-alpn@1.2.1: {} + + resolve-from@4.0.0: {} + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + retry@0.12.0: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + roarr@2.15.4: + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.4 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.3 + optional: true + + rollup@4.52.5: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 + fsevents: 2.3.3 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + sanitize-filename@1.6.3: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sax@1.4.1: {} + + scheduler@0.27.0: {} + + semver-compare@1.0.0: + optional: true + + semver@6.3.1: {} + + semver@7.7.3: {} + + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + optional: true + + set-blocking@2.0.0: {} + + set-cookie-parser@2.7.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + simple-update-notifier@2.0.0: + dependencies: + semver: 7.7.3 + + slice-ansi@3.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + optional: true + + smart-buffer@4.2.0: {} + + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + socks-proxy-agent@7.0.0: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.0.1 + smart-buffer: 4.2.0 + + sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.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: {} + + sprintf-js@1.1.3: + optional: true + + ssri@9.0.1: + dependencies: + minipass: 3.3.6 + + stat-mode@1.0.0: {} + + 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.2 + + 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.2: + dependencies: + ansi-regex: 6.2.2 + + stubborn-fs@1.2.5: {} + + sumchecker@3.0.1: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + svg-parser@2.0.4: {} + + tagged-tag@1.0.0: {} + + tailwind-merge@3.3.1: {} + + tailwindcss@4.1.15: {} + + tapable@2.3.0: {} + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + temp-file@3.4.0: + dependencies: + async-exit-hook: 2.0.1 + fs-extra: 10.1.0 + + tiny-typed-emitter@2.1.0: {} + + tinyexec@1.0.1: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tmp-promise@3.0.3: + dependencies: + tmp: 0.2.5 + + tmp@0.2.5: {} + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + tslib@2.8.1: {} + + type-fest@0.13.1: + optional: true + + type-fest@5.1.0: + dependencies: + tagged-tag: 1.0.0 + + typescript@5.9.3: {} + + ufo@1.6.1: {} + + uint8array-extras@1.5.0: {} + + undici-types@6.21.0: {} + + unique-filename@2.0.1: + dependencies: + unique-slug: 3.0.0 + + unique-slug@3.0.0: + dependencies: + imurmurhash: 0.1.4 + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unplugin-icons@22.5.0(@svgr/core@8.1.0(typescript@5.9.3)): + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/utils': 3.0.2 + debug: 4.4.3 + local-pkg: 1.1.2 + unplugin: 2.3.10 + optionalDependencies: + '@svgr/core': 8.1.0(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + unplugin@2.3.10: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.1.3(browserslist@4.26.3): + dependencies: + browserslist: 4.26.3 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.2.0): + dependencies: + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + use-sidecar@1.1.3(@types/react@19.2.2)(react@19.2.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.2 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + verror@1.10.1: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.4.1 + optional: true + + vite@7.1.11(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1): + dependencies: + esbuild: 0.25.11 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.52.5 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.18.12 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + yaml: 2.8.1 + + void-elements@3.1.0: {} + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + webpack-virtual-modules@0.6.2: {} + + when-exit@2.1.4: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wide-align@1.1.5: + dependencies: + string-width: 4.2.3 + + 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.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + + wrappy@1.0.2: {} + + xmlbuilder@15.1.1: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@2.8.1: {} + + yargs-parser@21.1.1: {} + + 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 + + yocto-queue@0.1.0: {} + + yt-dlp-wrap-plus@2.3.20: {} + + zip-stream@4.1.1: + dependencies: + archiver-utils: 3.0.4 + compress-commons: 4.1.2 + readable-stream: 3.6.2 + + zod@4.1.12: {} diff --git a/resources/.gitignore b/resources/.gitignore new file mode 100644 index 0000000..7ae4548 --- /dev/null +++ b/resources/.gitignore @@ -0,0 +1,9 @@ +# Ignore yt-dlp binaries (too large for git) +yt-dlp.exe +yt-dlp_macos +yt-dlp_linux + +# But keep the README +!README.md +!.gitignore + diff --git a/resources/README.md b/resources/README.md new file mode 100644 index 0000000..d485295 --- /dev/null +++ b/resources/README.md @@ -0,0 +1,55 @@ +# Resources Directory + +This directory contains bundled resources for the application. + +## yt-dlp Binaries + +To bundle yt-dlp with the application, place the appropriate binaries in this directory: + +### Required Files + +1. **Windows**: `yt-dlp.exe` +2. **macOS**: `yt-dlp_macos` +3. **Linux**: `yt-dlp_linux` + +### How to Download + +You can download the latest yt-dlp binaries from the official GitHub releases: + +**Option 1: Manual Download** + +- Visit: +- Download the appropriate version for each platform: + - Windows: `yt-dlp.exe` + - macOS: `yt-dlp_macos` + - Linux: `yt-dlp` (rename to `yt-dlp_linux`) + +**Option 2: Using curl/wget (Linux/macOS)** + +```bash +# For Windows binary +curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe -o resources/yt-dlp.exe + +# For macOS binary +curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos -o resources/yt-dlp_macos +chmod +x resources/yt-dlp_macos + +# For Linux binary +curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o resources/yt-dlp_linux +chmod +x resources/yt-dlp_linux +``` + +**Option 3: Using PowerShell (Windows)** + +```powershell +# Download all three binaries +Invoke-WebRequest -Uri "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe" -OutFile "resources/yt-dlp.exe" +Invoke-WebRequest -Uri "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos" -OutFile "resources/yt-dlp_macos" +Invoke-WebRequest -Uri "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp" -OutFile "resources/yt-dlp_linux" +``` + +### Note + +- If you don't place binaries here, the app will attempt to download them at runtime +- The app will automatically use the bundled version if available +- File sizes: ~10-15 MB per binary diff --git a/resources/icon.png b/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6d03b62e74457b56db6ef87883b4b04a419f65ee GIT binary patch literal 14607 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 literal 0 HcmV?d00001 diff --git a/src/main/assets.d.ts b/src/main/assets.d.ts new file mode 100644 index 0000000..1170b59 --- /dev/null +++ b/src/main/assets.d.ts @@ -0,0 +1,36 @@ +/// + +declare module '*.png?asset' { + const value: string + export default value +} + +declare module '*.ico?asset' { + const value: string + export default value +} + +declare module '*.icns?asset' { + const value: string + export default value +} + +declare module '*.jpg?asset' { + const value: string + export default value +} + +declare module '*.jpeg?asset' { + const value: string + export default value +} + +declare module '*.gif?asset' { + const value: string + export default value +} + +declare module '*.svg?asset' { + const value: string + export default value +} diff --git a/src/main/download-engine.ts b/src/main/download-engine.ts new file mode 100644 index 0000000..554abd4 --- /dev/null +++ b/src/main/download-engine.ts @@ -0,0 +1,1091 @@ +import { EventEmitter } from 'node:events' +import path from 'node:path' +import type { YTDlpEventEmitter } from 'yt-dlp-wrap-plus' +import type { + AppSettings, + DownloadHistoryItem, + DownloadItem, + DownloadOptions, + DownloadProgress, + OneClickQualityPreset, + PlaylistDownloadOptions, + PlaylistInfo, + VideoFormat, + VideoInfo +} from '../shared/types' +import { DownloadQueue } from './lib/download-queue' +import { historyManager } from './lib/history-manager' +import { ytdlpManager } from './lib/ytdlp-manager' +import { settingsManager } from './settings' + +const qualityPresetToVideoHeight: Record = { + auto: null, + best: null, + good: 1080, + normal: 720, + bad: 480, + worst: 360 +} + +const qualityPresetToAudioAbr: Record = { + auto: null, + best: 320, + good: 256, + normal: 192, + bad: 128, + worst: 96 +} + +const selectVideoFormatForPreset = ( + formats: VideoFormat[], + preset: OneClickQualityPreset +): VideoFormat | undefined => { + if (formats.length === 0) { + return undefined + } + + const sorted = [...formats].sort((a, b) => { + const heightDiff = (b.height ?? 0) - (a.height ?? 0) + if (heightDiff !== 0) return heightDiff + const fpsDiff = (b.fps ?? 0) - (a.fps ?? 0) + if (fpsDiff !== 0) return fpsDiff + return (b.tbr ?? 0) - (a.tbr ?? 0) + }) + + if (preset === 'worst') { + return sorted[sorted.length - 1] ?? sorted[0] + } + + const heightLimit = qualityPresetToVideoHeight[preset] + if (!heightLimit) { + return sorted[0] + } + + const withinLimit = sorted.find((format) => { + const height = format.height ?? 0 + return height > 0 && height <= heightLimit + }) + + return withinLimit ?? sorted[0] +} + +const selectAudioFormatForPreset = ( + formats: VideoFormat[], + preset: OneClickQualityPreset +): VideoFormat | undefined => { + if (formats.length === 0) { + return undefined + } + + const sorted = [...formats].sort((a, b) => { + const bitrateDiff = (b.tbr ?? 0) - (a.tbr ?? 0) + if (bitrateDiff !== 0) return bitrateDiff + const sizeA = a.filesize ?? a.filesize_approx ?? 0 + const sizeB = b.filesize ?? b.filesize_approx ?? 0 + if (sizeB !== sizeA) return sizeB - sizeA + return 0 + }) + + if (preset === 'worst') { + return sorted[sorted.length - 1] ?? sorted[0] + } + + const abrLimit = qualityPresetToAudioAbr[preset] + if (!abrLimit) { + return sorted[0] + } + + const withinLimit = sorted.find((format) => { + const bitrate = format.tbr ?? 0 + return bitrate > 0 && bitrate <= abrLimit + }) + + return withinLimit ?? sorted[0] +} + +const findFormatBySelector = ( + formats: VideoFormat[], + selector?: string +): VideoFormat | undefined => { + if (!selector) { + return undefined + } + + const candidateIds = selector + .split('/') + .map((option) => option.split('+')[0].trim()) + .filter((option) => option.length > 0) + + for (const candidateId of candidateIds) { + const match = formats.find((format) => format.format_id === candidateId) + if (match) { + return match + } + } + + return undefined +} + +const findFormatByIdCandidates = ( + formats: VideoFormat[], + rawFormatId: string | undefined +): VideoFormat | undefined => { + if (!rawFormatId) { + return undefined + } + + const parts = rawFormatId + .split('+') + .map((part) => part.trim()) + .filter((part) => part.length > 0) + + for (const part of parts) { + const match = formats.find((format) => format.format_id === part) + if (match) { + return match + } + } + + return undefined +} + +const parseSizeToBytes = (value?: string): number | undefined => { + if (!value) { + return undefined + } + + const cleaned = value.trim().replace(/^~\s*/, '') + if (!cleaned) { + return undefined + } + + const match = cleaned.match(/^([\d.,]+)\s*([KMGTP]?i?B)$/i) + if (!match) { + return undefined + } + + const amount = Number(match[1].replace(/,/g, '')) + if (Number.isNaN(amount)) { + return undefined + } + + const unit = match[2].toUpperCase() + const multipliers: Record = { + B: 1, + KB: 1_000, + KIB: 1_024, + MB: 1_000_000, + MIB: 1_048_576, + GB: 1_000_000_000, + GIB: 1_073_741_824, + TB: 1_000_000_000_000, + TIB: 1_099_511_627_776 + } + + const multiplier = multipliers[unit] + if (!multiplier) { + return undefined + } + + return Math.round(amount * multiplier) +} + +const resolveSelectedFormat = ( + formats: VideoFormat[], + options: DownloadOptions, + settings: AppSettings +): VideoFormat | undefined => { + const directMatch = findFormatBySelector(formats, options.format) + if (directMatch) { + return directMatch + } + + const preset = settings.oneClickQuality ?? 'auto' + + if (options.type === 'video') { + const videoFormats = formats.filter( + (format) => format.video_ext !== 'none' && !!format.vcodec && format.vcodec !== 'none' + ) + return selectVideoFormatForPreset(videoFormats, preset) + } + + if (options.type === 'audio' || options.type === 'extract') { + const audioFormats = formats.filter( + (format) => + !!format.acodec && + format.acodec !== 'none' && + (!format.video_ext || format.video_ext === 'none') + ) + return selectAudioFormatForPreset(audioFormats, preset) + } + + return undefined +} + +interface DownloadProcess { + controller: AbortController + process: YTDlpEventEmitter +} + +class DownloadEngine extends EventEmitter { + private activeDownloads: Map = new Map() + private queue: DownloadQueue + + constructor() { + super() + const maxConcurrent = settingsManager.get('maxConcurrentDownloads') + this.queue = new DownloadQueue(maxConcurrent) + + this.queue.on('start-download', async (item) => { + await this.executeDownload(item.id, item.options) + }) + } + + async getVideoInfo(url: string): Promise { + const ytdlp = ytdlpManager.getInstance() + const settings = settingsManager.getAll() + + const args = ['-j', '--no-playlist', '--no-warnings'] + + // Add encoding support for proper handling of non-ASCII characters + args.push('--encoding', 'utf-8') + + // Add proxy if configured + if (settings.proxy) { + args.push('--proxy', settings.proxy) + } + + // Add browser cookies if configured (skip if 'none') + if (settings.browserForCookies && settings.browserForCookies !== 'none') { + args.push('--cookies-from-browser', settings.browserForCookies) + } + + // Add config file if configured + if (settings.configPath) { + args.push('--config-location', `"${settings.configPath}"`) + } + + args.push(url) + + return new Promise((resolve, reject) => { + const process = ytdlp.exec(args) + let stdout = '' + let stderr = '' + + process.ytDlpProcess?.stdout?.on('data', (data: Buffer) => { + stdout += data.toString() + }) + + process.ytDlpProcess?.stderr?.on('data', (data: Buffer) => { + stderr += data.toString() + }) + + process.on('close', (code) => { + if (code === 0 && stdout) { + try { + const info = JSON.parse(stdout) + resolve(info) + } catch (error) { + reject(new Error(`Failed to parse video info: ${error}`)) + } + } else { + reject(new Error(stderr || 'Failed to fetch video info')) + } + }) + + process.on('error', (error) => { + reject(error) + }) + }) + } + + async getPlaylistInfo(url: string): Promise { + const ytdlp = ytdlpManager.getInstance() + const settings = settingsManager.getAll() + + const args = ['-j', '--flat-playlist', '--no-warnings'] + + // Add encoding support for proper handling of non-ASCII characters + args.push('--encoding', 'utf-8') + + // Add proxy if configured + if (settings.proxy) { + args.push('--proxy', settings.proxy) + } + + // Add browser cookies if configured (skip if 'none') + if (settings.browserForCookies && settings.browserForCookies !== 'none') { + args.push('--cookies-from-browser', settings.browserForCookies) + } + + args.push(url) + + return new Promise((resolve, reject) => { + const process = ytdlp.exec(args) + let stdout = '' + let stderr = '' + + process.ytDlpProcess?.stdout?.on('data', (data: Buffer) => { + stdout += data.toString() + }) + + process.ytDlpProcess?.stderr?.on('data', (data: Buffer) => { + stderr += data.toString() + }) + + process.on('close', (code) => { + if (code === 0 && stdout) { + try { + const lines = stdout.trim().split('\n') + const entries = lines.map((line) => JSON.parse(line)) + const playlistEntry = entries[0] + + resolve({ + id: playlistEntry.id || '', + title: playlistEntry.title || 'Playlist', + entries: entries.map((entry) => ({ + id: entry.id || '', + title: entry.title || 'Unknown', + url: entry.url || entry.webpage_url || '' + })), + entryCount: entries.length + }) + } catch (error) { + reject(new Error(`Failed to parse playlist info: ${error}`)) + } + } else { + reject(new Error(stderr || 'Failed to fetch playlist info')) + } + }) + + process.on('error', (error) => { + reject(error) + }) + }) + } + + async startPlaylistDownload(options: PlaylistDownloadOptions): Promise { + const playlistInfo = await this.getPlaylistInfo(options.url) + const downloadIds: string[] = [] + + // Calculate the range of entries to download + const startIndex = (options.startIndex || 1) - 1 // Convert to 0-based index + const endIndex = options.endIndex ? options.endIndex - 1 : playlistInfo.entries.length - 1 + const entriesToDownload = playlistInfo.entries.slice(startIndex, endIndex + 1) + + console.log( + `Starting playlist download: ${entriesToDownload.length} videos from "${playlistInfo.title}"` + ) + + // Create download items for each video in the playlist + for (const entry of entriesToDownload) { + const downloadId = `playlist_${Date.now()}_${Math.random().toString(36).substring(7)}` + downloadIds.push(downloadId) + + const downloadOptions: DownloadOptions = { + url: entry.url, + type: options.type, + format: options.format, + audioFormat: options.type === 'audio' ? options.format : undefined + } + + const createdAt = Date.now() + + // Add to queue + this.queue.add(downloadId, downloadOptions, { + id: downloadId, + url: entry.url, + title: entry.title, + type: options.type, + status: 'pending', + progress: { percent: 0 }, + createdAt + }) + + this.upsertHistoryEntry(downloadId, downloadOptions, { + title: entry.title, + status: 'pending', + downloadedAt: createdAt + }) + } + + return downloadIds + } + + startDownload(id: string, options: DownloadOptions): void { + if (this.activeDownloads.has(id)) { + console.warn(`Download ${id} is already active`) + return + } + + const createdAt = Date.now() + + const item: DownloadItem = { + id, + url: options.url, + title: 'Downloading...', + type: options.type, + status: 'pending' as const, + createdAt + } + + this.queue.add(id, options, item) + + this.upsertHistoryEntry(id, options, { + title: item.title, + status: 'pending', + downloadedAt: createdAt, + outputPath: options.outputPath + }) + } + + private async executeDownload(id: string, options: DownloadOptions): Promise { + const ytdlp = ytdlpManager.getInstance() + const settings = settingsManager.getAll() + const downloadPath = options.outputPath || settings.downloadPath + + // Set environment variables for proper encoding on Windows + if (process.platform === 'win32') { + process.env.PYTHONIOENCODING = 'utf-8' + process.env.LC_ALL = 'C.UTF-8' + } + + let availableFormats: VideoFormat[] = [] + let selectedFormat: VideoFormat | undefined + let actualFormat: string | null = null + let actualQuality: string | null = null + let actualCodec: string | null = null + + // First, get detailed video info to capture basic metadata and formats + try { + const videoInfo = await this.getVideoInfo(options.url) + + availableFormats = Array.isArray(videoInfo.formats) ? videoInfo.formats : [] + selectedFormat = resolveSelectedFormat(availableFormats, options, settings) + + if (selectedFormat) { + actualFormat = selectedFormat.ext || actualFormat + + if (selectedFormat.height) { + actualQuality = `${selectedFormat.height}p${ + selectedFormat.fps && selectedFormat.fps === 60 ? '60' : '' + }` + } else if (selectedFormat.format_note) { + actualQuality = selectedFormat.format_note + } + + if (options.type === 'audio' || options.type === 'extract') { + actualCodec = selectedFormat.acodec || actualCodec + } else { + actualCodec = selectedFormat.vcodec || selectedFormat.acodec || actualCodec + } + } + + this.updateDownloadInfo(id, { + title: videoInfo.title, + thumbnail: videoInfo.thumbnail, + duration: videoInfo.duration, + description: videoInfo.description, + uploader: videoInfo.uploader, + viewCount: videoInfo.view_count, + // Store only essential download info + selectedFormat + }) + + this.upsertHistoryEntry(id, options, { + title: videoInfo.title, + thumbnail: videoInfo.thumbnail, + duration: videoInfo.duration, + description: videoInfo.description, + uploader: videoInfo.uploader, + viewCount: videoInfo.view_count, + // Store only essential download info + selectedFormat + }) + } catch (error) { + console.warn('Failed to get detailed video info:', error) + } + + const applySelectedFormat = (formatId: string | undefined): boolean => { + if (!formatId) { + return false + } + + const candidate = findFormatByIdCandidates(availableFormats, formatId) + if (!candidate) { + return false + } + + if (selectedFormat?.format_id === candidate.format_id) { + return true + } + + selectedFormat = candidate + actualFormat = candidate.ext || actualFormat + + if (candidate.height) { + actualQuality = `${candidate.height}p${candidate.fps === 60 ? '60' : ''}` + } else if (candidate.format_note) { + actualQuality = candidate.format_note + } + + if (options.type === 'audio' || options.type === 'extract') { + actualCodec = candidate.acodec || actualCodec + } else { + actualCodec = candidate.vcodec || candidate.acodec || actualCodec + } + + this.updateDownloadInfo(id, { + selectedFormat: candidate + }) + + return true + } + + const args = this.buildDownloadArgs(options, downloadPath, settings) + + const controller = new AbortController() + const ytdlpProcess = ytdlp.exec(args, { + signal: controller.signal + }) + + this.activeDownloads.set(id, { controller, process: ytdlpProcess }) + + this.emit('download-started', id) + + this.upsertHistoryEntry(id, options, { + status: 'downloading' + }) + + let latestKnownSizeBytes: number | undefined + + // Handle progress + ytdlpProcess.on( + 'progress', + (progress: { + percent?: number + currentSpeed?: string + eta?: string + downloaded?: string + total?: string + }) => { + const totalBytes = parseSizeToBytes(progress.total) + if (totalBytes !== undefined) { + latestKnownSizeBytes = totalBytes + } + + const downloadedBytes = parseSizeToBytes(progress.downloaded) + if (downloadedBytes !== undefined) { + latestKnownSizeBytes = + latestKnownSizeBytes !== undefined + ? Math.max(latestKnownSizeBytes, downloadedBytes) + : downloadedBytes + } + + const downloadProgress: DownloadProgress = { + percent: progress.percent || 0, + currentSpeed: progress.currentSpeed || '', + eta: progress.eta || '', + downloaded: progress.downloaded || '', + total: progress.total || '' + } + this.emit('download-progress', id, downloadProgress) + } + ) + + // Handle yt-dlp events to capture output file path and format info + let actualOutputPath: string | null = null + + ytdlpProcess.on('ytDlpEvent', (eventType: string, eventData: string) => { + // Look for download destination messages + if (eventType === 'download' && eventData.includes('Destination:')) { + const match = eventData.match(/Destination:\s*(.+)/) + if (match?.[1]) { + actualOutputPath = match[1].trim() + } + } + + // Also look for other output path patterns + if ( + eventType === 'download' && + (eventData.includes('has already been downloaded') || + eventData.includes('has already been downloaded')) + ) { + const match = eventData.match(/\[download\]\s*(.+?)\s+has already been downloaded/) + if (match?.[1]) { + actualOutputPath = match[1].trim() + } + } + + // Look for final output path in download messages + if (eventType === 'download' && eventData.includes('[download] 100%')) { + const match = eventData.match(/\[download\]\s*100%.*?of\s*(.+?)\s+at/) + if (match?.[1]) { + actualOutputPath = match[1].trim() + } + } + + // Look for format selection messages + if (eventType === 'info' && eventData.includes('format')) { + // Extract format info from yt-dlp output + const formatMatch = eventData.match(/\[info\]\s*([^\s:]+):\s*(.+)/) + if (formatMatch) { + const formatId = formatMatch[1] + const formatInfo = formatMatch[2] + + applySelectedFormat(formatId) + + // Extract format details with better regex patterns + const extMatch = formatInfo.match(/(\w+)(?:\s|$)/) + if (extMatch && !actualFormat) { + actualFormat = extMatch[1] + } + + const heightMatch = formatInfo.match(/(\d+)p/) + if (heightMatch && !actualQuality) { + actualQuality = `${heightMatch[1]}p` + } + + const codecMatch = formatInfo.match(/(?:vcodec|acodec)[:\s]*([^\s,]+)/) + if (codecMatch && !actualCodec) { + actualCodec = codecMatch[1] + } + } + } + + // Also look for download progress messages that might contain format info + if (eventType === 'download' && eventData.includes('format')) { + const formatMatch = eventData.match(/format\s*([0-9A-Za-z+-]+)/) + if (formatMatch) { + applySelectedFormat(formatMatch[1]) + } + } + }) + + // Handle completion + ytdlpProcess.on('close', async (code: number | null) => { + this.activeDownloads.delete(id) + this.queue.downloadCompleted(id) + + if (code === 0) { + // Try to get the actual output path from yt-dlp events first + let finalOutputPath = actualOutputPath + + // If we don't have the actual path, try to construct it + if (!finalOutputPath) { + try { + // Get video info to construct the expected output path + const videoInfo = await this.getVideoInfo(options.url) + const title = videoInfo.title || 'Unknown' + + // Sanitize title for filename - handle Chinese characters and special chars + const sanitizedTitle = title + .replace(/[<>:"/\\|?*]/g, '_') + .replace(/[\u4e00-\u9fff]/g, '') // Remove Chinese characters + .replace(/\s+/g, '_') // Replace spaces with underscores + .replace(/_{2,}/g, '_') // Replace multiple underscores with single + .substring(0, 50) // Shorter limit for safety + + // Determine file extension based on format + let extension = 'mp4' // default + if (options.type === 'audio') { + extension = options.extractFormat || 'mp3' + } else if (actualFormat) { + extension = actualFormat + } + + // Construct the expected output path + const expectedFileName = `${sanitizedTitle}.${extension}` + const expectedPath = path.join(downloadPath, expectedFileName) + + // Check if the file exists + const fs = await import('node:fs/promises') + try { + await fs.access(expectedPath) + finalOutputPath = expectedPath + } catch { + // Try to find any file with similar name in the download directory + try { + const files = await fs.readdir(downloadPath) + const matchingFile = files.find((file) => { + // Look for files that might match our download + const isVideoFile = + file.endsWith('.mp4') || + file.endsWith('.webm') || + file.endsWith('.mkv') || + file.endsWith('.avi') || + file.endsWith('.mov') + + const isAudioFile = + file.endsWith('.mp3') || + file.endsWith('.m4a') || + file.endsWith('.aac') || + file.endsWith('.ogg') + + const isCorrectType = + (options.type === 'video' && isVideoFile) || + (options.type === 'audio' && isAudioFile) + + // Check if file was created recently (within last 5 minutes) + const filePath = path.join(downloadPath, file) + try { + const fsSync = require('node:fs') + const stats = fsSync.statSync(filePath) + const isRecent = Date.now() - stats.mtime.getTime() < 5 * 60 * 1000 + return isCorrectType && isRecent + } catch { + return false + } + }) + if (matchingFile) { + finalOutputPath = path.join(downloadPath, matchingFile) + } + } catch (error) { + console.warn('Failed to search for matching files:', error) + } + } + } catch (error) { + console.warn('Failed to construct output path:', error) + } + } + + // Fallback to default path if still no output path + if (!finalOutputPath) { + // Create a generic filename with timestamp + const timestamp = Date.now() + const extension = options.type === 'audio' ? options.extractFormat || 'mp3' : 'mp4' + const genericFileName = `download_${timestamp}.${extension}` + finalOutputPath = path.join(downloadPath, genericFileName) + } + + // Get file size if we have the output path + let fileSize: number | undefined + let fileSizeError: unknown + if (finalOutputPath) { + try { + const fs = await import('node:fs/promises') + const stats = await fs.stat(finalOutputPath) + fileSize = stats.size + } catch (error) { + fileSizeError = error + } + } + + if (fileSize === undefined && latestKnownSizeBytes !== undefined) { + fileSize = latestKnownSizeBytes + } else if (fileSize === undefined && fileSizeError) { + console.warn('Failed to get file size:', fileSizeError) + } + + this.updateDownloadInfo(id, { + status: 'completed', + outputPath: finalOutputPath, + completedAt: Date.now(), + fileSize, + format: actualFormat || undefined, + quality: actualQuality || undefined, + codec: actualCodec || undefined + }) + this.emit('download-completed', id) + this.addToHistory(id, options, 'completed', undefined, finalOutputPath) + } else { + this.emit('download-error', id, new Error(`Download exited with code ${code}`)) + this.addToHistory(id, options, 'error', `Download exited with code ${code}`) + } + }) + + // Handle errors + ytdlpProcess.on('error', (error: Error) => { + this.activeDownloads.delete(id) + this.queue.downloadCompleted(id) + this.emit('download-error', id, error) + this.addToHistory(id, options, 'error', error.message) + }) + } + + private buildDownloadArgs( + options: DownloadOptions, + downloadPath: string, + settings: AppSettings + ): string[] { + const args: string[] = ['--no-playlist', '--embed-chapters', '--no-mtime'] + + // Add encoding support for proper handling of non-ASCII characters + args.push('--encoding', 'utf-8') + + // Format selection + if (options.type === 'video') { + args.push('-f', this.resolveVideoFormatSelector(options)) + } else if (options.type === 'audio') { + args.push('-f', this.resolveAudioFormatSelector(options)) + } else if (options.type === 'extract') { + args.push('-x') + args.push('--audio-format', options.extractFormat || 'mp3') + args.push('--audio-quality', options.extractQuality || '5') + } + + // Time range + if (options.startTime || options.endTime) { + const start = options.startTime || '0' + const end = options.endTime || '' + args.push('--download-sections', `*${start}-${end || ''}`) + } + + // Subtitles + if (options.downloadSubs) { + args.push('--write-subs', '--sub-langs', 'all') + } + + // Output path with proper encoding handling + // Use sanitized filename to avoid encoding issues + const outputTemplate = path.join(downloadPath, '%(title).100s.%(ext)s') + args.push('-o', outputTemplate) + + // Add options for better filename handling on Windows + if (process.platform === 'win32') { + // On Windows, use a more conservative approach to avoid encoding issues + args.push('--windows-filenames') // Use Windows-compatible filenames + } + + // Browser cookies + if (settings.browserForCookies && settings.browserForCookies !== 'none') { + args.push('--cookies-from-browser', settings.browserForCookies) + } + + // Proxy + if (settings.proxy) { + args.push('--proxy', settings.proxy) + } + + // Config file + if (settings.configPath) { + args.push('--config-location', settings.configPath) + } + + // URL (must be last) + args.push(options.url) + + return args + } + + private resolveVideoFormatSelector(options: DownloadOptions): string { + const format = options.format + const audioFormat = options.audioFormat + + if (format && (format.includes('/') || (audioFormat === undefined && format.includes('+')))) { + return format + } + + if (!format || format === 'best') { + if (audioFormat === 'none') { + return 'bestvideo+none' + } + if (!audioFormat || audioFormat === 'best') { + return 'best' + } + return `bestvideo+${audioFormat}` + } + + if (audioFormat === 'none') { + return `${format}+none` + } + + const audio = audioFormat && audioFormat !== 'best' ? audioFormat : 'bestaudio' + return `${format}+${audio}` + } + + private resolveAudioFormatSelector(options: DownloadOptions): string { + const format = options.format + + if (!format) { + return 'bestaudio' + } + + if (format.includes('/') || format.includes('+') || format.includes('[')) { + return format + } + + return format + } + + cancelDownload(id: string): boolean { + const snapshot = this.queue.getItemDetails(id) + + const download = this.activeDownloads.get(id) + if (download) { + download.controller.abort() + const removedFromQueue = this.queue.remove(id) + this.activeDownloads.delete(id) + this.emit('download-cancelled', id) + if (snapshot) { + this.upsertHistoryEntry(id, snapshot.options, { + status: 'cancelled', + completedAt: Date.now() + }) + } + return removedFromQueue + } + const removed = this.queue.remove(id) + if (removed && snapshot) { + this.upsertHistoryEntry(id, snapshot.options, { + status: 'cancelled', + completedAt: Date.now() + }) + } + return removed + } + + updateMaxConcurrent(max: number): void { + this.queue.setMaxConcurrent(max) + } + + getQueueStatus() { + return this.queue.getQueueStatus() + } + + updateDownloadInfo(id: string, updates: Partial): void { + this.queue.updateItemInfo(id, updates) + + const snapshot = this.queue.getItemDetails(id) + if (!snapshot) { + return + } + + const historyUpdates: Partial = {} + + if (updates.title !== undefined) { + historyUpdates.title = updates.title + } + if (updates.thumbnail !== undefined) { + historyUpdates.thumbnail = updates.thumbnail + } + if (updates.duration !== undefined) { + historyUpdates.duration = updates.duration + } + if (updates.outputPath !== undefined) { + historyUpdates.outputPath = updates.outputPath + } + if (updates.fileSize !== undefined) { + historyUpdates.fileSize = updates.fileSize + } + if (updates.format !== undefined) { + historyUpdates.format = updates.format + } + if (updates.quality !== undefined) { + historyUpdates.quality = updates.quality + } + if (updates.codec !== undefined) { + historyUpdates.codec = updates.codec + } + if (updates.description !== undefined) { + historyUpdates.description = updates.description + } + if (updates.channel !== undefined) { + historyUpdates.channel = updates.channel + } + if (updates.uploader !== undefined) { + historyUpdates.uploader = updates.uploader + } + if (updates.viewCount !== undefined) { + historyUpdates.viewCount = updates.viewCount + } + if (updates.tags !== undefined) { + historyUpdates.tags = updates.tags + } + if (updates.status !== undefined) { + historyUpdates.status = updates.status + } + if (updates.completedAt !== undefined) { + historyUpdates.completedAt = updates.completedAt + } + if (updates.error !== undefined) { + historyUpdates.error = updates.error + } + if (updates.selectedFormat !== undefined) { + historyUpdates.selectedFormat = updates.selectedFormat + } + + if (Object.keys(historyUpdates).length > 0) { + this.upsertHistoryEntry(id, snapshot.options, historyUpdates) + } + } + + private addToHistory( + id: string, + options: DownloadOptions, + status: DownloadHistoryItem['status'], + error?: string, + actualOutputPath?: string + ): void { + // Get the download item from the queue to get additional info + const completedDownload = this.queue.getCompletedDownload(id) + + const completedAt = Date.now() + + this.upsertHistoryEntry(id, options, { + title: completedDownload?.item.title || `Download ${id}`, + thumbnail: completedDownload?.item.thumbnail, + status, + outputPath: actualOutputPath || options.outputPath, + completedAt, + error, + duration: completedDownload?.item.duration, + fileSize: completedDownload?.item.fileSize, + format: completedDownload?.item.format, + quality: completedDownload?.item.quality, + codec: completedDownload?.item.codec, + description: completedDownload?.item.description, + channel: completedDownload?.item.channel, + uploader: completedDownload?.item.uploader, + viewCount: completedDownload?.item.viewCount, + tags: completedDownload?.item.tags + }) + } + + private upsertHistoryEntry( + id: string, + options: DownloadOptions, + updates: Partial + ): void { + const existing = historyManager.getHistoryById(id) + const base: DownloadHistoryItem = existing ?? { + id, + url: options.url, + title: updates.title || `Download ${id}`, + thumbnail: updates.thumbnail, + type: options.type, + status: updates.status || 'pending', + outputPath: updates.outputPath, + fileSize: updates.fileSize, + duration: updates.duration, + downloadedAt: updates.downloadedAt ?? Date.now(), + completedAt: updates.completedAt, + error: updates.error, + format: updates.format, + quality: updates.quality, + codec: updates.codec, + description: updates.description, + channel: updates.channel, + uploader: updates.uploader, + viewCount: updates.viewCount, + tags: updates.tags, + // Download-specific format info + selectedFormat: updates.selectedFormat + } + + const merged: DownloadHistoryItem = { + ...base, + ...updates, + id, + url: updates.url ?? base.url, + type: updates.type ?? base.type, + title: updates.title ?? base.title, + status: updates.status ?? base.status, + downloadedAt: updates.downloadedAt ?? base.downloadedAt + } + + historyManager.addHistoryItem(merged) + } +} + +export const downloadEngine = new DownloadEngine() diff --git a/src/main/index.ts b/src/main/index.ts new file mode 100644 index 0000000..b13ab35 --- /dev/null +++ b/src/main/index.ts @@ -0,0 +1,230 @@ +import { join } from 'node:path' +import { electronApp, optimizer } from '@electron-toolkit/utils' +import { app, BrowserWindow, shell } from 'electron' +import log from 'electron-log' +import { autoUpdater } from 'electron-updater' +import appIcon from '../../build/icon.png?asset' +import { downloadEngine } from './download-engine' +import { services } from './ipc' +import { ytdlpManager } from './lib/ytdlp-manager' +import { settingsManager } from './settings' +import { createTray, destroyTray } from './tray' + +let mainWindow: BrowserWindow | null = null +let isQuitting = false + +export function createWindow(): void { + // Create the browser window + mainWindow = new BrowserWindow({ + width: 1200, + height: 800, + show: false, + titleBarStyle: 'hidden', // Hide title bar on macOS + autoHideMenuBar: true, + icon: appIcon, // Set application icon + frame: false, + vibrancy: 'fullscreen-ui', // on MacOS + backgroundMaterial: 'acrylic', // on Windows 11 + webPreferences: { + preload: join(__dirname, '../preload/index.js'), + sandbox: false, + contextIsolation: true, + nodeIntegration: false, + webSecurity: false // Allow drag regions to work + } + }) + + mainWindow.on('close', (event) => { + const closeToTray = settingsManager.get('closeToTray') + if (closeToTray && !isQuitting) { + event.preventDefault() + mainWindow?.hide() + } + }) + + mainWindow.on('ready-to-show', () => { + mainWindow?.show() + }) + + mainWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url) + return { action: 'deny' } + }) + + // HMR for renderer base on electron-vite cli. + // Load the remote URL for development or the local html file for production. + if (process.env.ELECTRON_RENDERER_URL) { + mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL) + } else { + mainWindow.loadFile(join(__dirname, '../renderer/index.html')) + } + + // Setup download engine event forwarding to renderer + setupDownloadEvents() +} + +function setupDownloadEvents(): void { + downloadEngine.on('download-started', (id: string) => { + mainWindow?.webContents.send('download:started', id) + }) + + downloadEngine.on('download-progress', (id: string, progress: unknown) => { + mainWindow?.webContents.send('download:progress', { id, progress }) + }) + + downloadEngine.on('download-completed', (id: string) => { + mainWindow?.webContents.send('download:completed', id) + }) + + downloadEngine.on('download-error', (id: string, error: Error) => { + mainWindow?.webContents.send('download:error', { id, error: error.message }) + }) + + downloadEngine.on('download-cancelled', (id: string) => { + mainWindow?.webContents.send('download:cancelled', id) + }) +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.whenReady().then(async () => { + // Set app user model id for windows + electronApp.setAppUserModelId('com.vidbee') + + // Default open or close DevTools by F12 in development + // and ignore CommandOrControl + R in production. + app.on('browser-window-created', (_, window) => { + optimizer.watchWindowShortcuts(window) + }) + + // IPC services are automatically registered by electron-ipc-decorator when imported + console.log('IPC services available:', Object.keys(services)) + + // Initialize yt-dlp + try { + console.log('Initializing yt-dlp...') + await ytdlpManager.initialize() + console.log('yt-dlp initialized successfully') + } catch (error) { + console.error('Failed to initialize yt-dlp:', error) + } + + // Initialize auto-updater (only in production) + if (process.env.NODE_ENV === 'production') { + try { + console.log('Initializing auto-updater...') + + // Configure logging + log.transports.file.level = 'info' + autoUpdater.logger = log + + // Configure auto-updater for production + autoUpdater.autoDownload = true // Auto download updates + autoUpdater.autoInstallOnAppQuit = true // Auto install on quit + + // Set up event listeners + autoUpdater.on('update-available', (info) => { + log.info('Update available:', info.version) + console.log('Update available:', info.version) + // Send notification to renderer + mainWindow?.webContents.send('update:available', info) + }) + + autoUpdater.on('update-not-available', (info) => { + log.info('Update not available:', info.version) + console.log('Update not available:', info.version) + // Send notification to renderer + mainWindow?.webContents.send('update:not-available', info) + }) + + autoUpdater.on('error', (err) => { + log.error('Update error:', err) + console.error('Update error:', err) + // Send error to renderer + mainWindow?.webContents.send('update:error', err.message) + }) + + autoUpdater.on('download-progress', (progressObj) => { + log.info('Download progress:', progressObj.percent) + console.log('Download progress:', progressObj.percent) + // Send progress to renderer + mainWindow?.webContents.send('update:download-progress', progressObj) + }) + + autoUpdater.on('update-downloaded', (info) => { + log.info('Update downloaded:', info.version) + console.log('Update downloaded:', info.version) + // Send notification to renderer + mainWindow?.webContents.send('update:downloaded', info) + + // Show system notification + if (mainWindow) { + mainWindow.webContents.send('update:show-notification', { + title: 'Update Ready', + body: `Version ${info.version} has been downloaded and will be installed on restart.`, + icon: 'app-icon' + }) + } + }) + + // Check for updates on startup if auto-update is enabled + if (settingsManager.get('autoUpdate')) { + log.info('Auto-update is enabled, checking for updates...') + console.log('Auto-update is enabled, checking for updates...') + // Use checkForUpdatesAndNotify for automatic notifications + await autoUpdater.checkForUpdatesAndNotify() + } + + log.info('Auto-updater initialized successfully') + console.log('Auto-updater initialized successfully') + } catch (error) { + log.error('Failed to initialize auto-updater:', error) + console.error('Failed to initialize auto-updater:', error) + } + } else { + console.log('Skipping auto-updater initialization in development mode') + } + + createWindow() + + // Create system tray + createTray() + + app.on('activate', () => { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('before-quit', () => { + isQuitting = true +}) + +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', () => { + const closeToTray = settingsManager.get('closeToTray') + + if (process.platform !== 'darwin') { + if (closeToTray) { + // Hide to tray instead of quitting + const mainWindow = BrowserWindow.getAllWindows().find((window) => !window.isDestroyed()) + if (mainWindow) { + mainWindow.hide() + } + } else { + app.quit() + } + } +}) + +// Cleanup tray on quit +app.on('will-quit', () => { + destroyTray() +}) + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts new file mode 100644 index 0000000..5a9bc54 --- /dev/null +++ b/src/main/ipc/index.ts @@ -0,0 +1,24 @@ +import { createServices, type MergeIpcService } from 'electron-ipc-decorator' +import { AppService } from './services/app-service' +import { DownloadService } from './services/download-service' +import { FileSystemService } from './services/file-system-service' +import { HistoryService } from './services/history-service' +import { SettingsService } from './services/settings-service' +import { ThumbnailService } from './services/thumbnail-service' +import { UpdateService } from './services/update-service' +import { WindowService } from './services/window-service' + +// Create services with automatic type inference +export const services = createServices([ + AppService, + DownloadService, + FileSystemService, + HistoryService, + SettingsService, + ThumbnailService, + UpdateService, + WindowService +]) + +// Generate type definition for all services +export type IpcServices = MergeIpcService diff --git a/src/main/ipc/services/app-service.ts b/src/main/ipc/services/app-service.ts new file mode 100644 index 0000000..8b9e258 --- /dev/null +++ b/src/main/ipc/services/app-service.ts @@ -0,0 +1,37 @@ +import os from 'node:os' +import { app, BrowserWindow, dialog } from 'electron' +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' + +class AppService extends IpcService { + static readonly groupName = 'app' + + @IpcMethod() + getVersion(_context: IpcContext): string { + return app.getVersion() + } + + @IpcMethod() + getPlatform(_context: IpcContext): string { + return os.platform() + } + + @IpcMethod() + quit(_context: IpcContext): void { + app.quit() + } + + @IpcMethod() + async showMessageBox( + _context: IpcContext, + options: Electron.MessageBoxOptions + ): Promise { + const window = BrowserWindow.getFocusedWindow() + if (window) { + return dialog.showMessageBox(window, options) + } + + return dialog.showMessageBox(options) + } +} + +export { AppService } diff --git a/src/main/ipc/services/download-service.ts b/src/main/ipc/services/download-service.ts new file mode 100644 index 0000000..eae0727 --- /dev/null +++ b/src/main/ipc/services/download-service.ts @@ -0,0 +1,53 @@ +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' +import type { + DownloadItem, + DownloadOptions, + PlaylistDownloadOptions, + PlaylistInfo, + VideoInfo +} from '../../../shared/types' +import { downloadEngine } from '../../download-engine' + +class DownloadService extends IpcService { + static readonly groupName = 'download' + + @IpcMethod() + async getVideoInfo(_context: IpcContext, url: string): Promise { + return downloadEngine.getVideoInfo(url) + } + + @IpcMethod() + async getPlaylistInfo(_context: IpcContext, url: string): Promise { + return downloadEngine.getPlaylistInfo(url) + } + + @IpcMethod() + startDownload(_context: IpcContext, id: string, options: DownloadOptions): void { + downloadEngine.startDownload(id, options) + } + + @IpcMethod() + cancelDownload(_context: IpcContext, id: string): boolean { + return downloadEngine.cancelDownload(id) + } + + @IpcMethod() + getQueueStatus(_context: IpcContext) { + return downloadEngine.getQueueStatus() + } + + @IpcMethod() + updateDownloadInfo(_context: IpcContext, id: string, updates: Partial): void { + downloadEngine.updateDownloadInfo(id, updates) + } + + @IpcMethod() + async startPlaylistDownload( + _context: IpcContext, + options: PlaylistDownloadOptions + ): Promise { + return downloadEngine.startPlaylistDownload(options) + } +} + +export { DownloadService } diff --git a/src/main/ipc/services/file-system-service.ts b/src/main/ipc/services/file-system-service.ts new file mode 100644 index 0000000..4b058df --- /dev/null +++ b/src/main/ipc/services/file-system-service.ts @@ -0,0 +1,176 @@ +import type { Dirent } from 'node:fs' +import fs from 'node:fs/promises' +import os from 'node:os' +import path from 'node:path' +import { dialog, shell } from 'electron' +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' + +class FileSystemService extends IpcService { + static readonly groupName = 'fs' + + @IpcMethod() + async selectDirectory(_context: IpcContext): Promise { + const result = await dialog.showOpenDialog({ + properties: ['openDirectory'] + }) + + if (result.canceled || result.filePaths.length === 0) { + return null + } + + return result.filePaths[0] + } + + @IpcMethod() + async selectFile(_context: IpcContext): Promise { + const result = await dialog.showOpenDialog({ + properties: ['openFile'] + }) + + if (result.canceled || result.filePaths.length === 0) { + return null + } + + return result.filePaths[0] + } + + @IpcMethod() + getDefaultDownloadPath(_context: IpcContext): string { + return `${os.homedir()}/Downloads` + } + + @IpcMethod() + async openFileLocation(_context: IpcContext, filePath: string): Promise { + try { + if (!filePath) { + return false + } + + const sanitizedPath = this.sanitizePath(filePath) + const normalizedPath = path.normalize(sanitizedPath) + const stats = await fs.stat(normalizedPath).catch(() => null) + + if (stats?.isFile()) { + shell.showItemInFolder(normalizedPath) + return true + } + + if (stats?.isDirectory()) { + const candidate = await this.findLikelyFile(normalizedPath, normalizedPath) + if (candidate) { + shell.showItemInFolder(candidate) + return true + } + + const result = await shell.openPath(normalizedPath) + if (result) { + console.error('Failed to open directory:', result) + return false + } + return true + } + + const fallbackDirectory = path.dirname(normalizedPath) + const fallbackCandidate = await this.findLikelyFile(fallbackDirectory, normalizedPath) + if (fallbackCandidate) { + shell.showItemInFolder(fallbackCandidate) + return true + } + + const result = await shell.openPath(fallbackDirectory) + if (!result) { + return true + } + console.error('Failed to open directory:', result) + } catch (error) { + try { + const directory = path.dirname(path.normalize(this.sanitizePath(filePath))) + const dirStats = await fs.stat(directory) + if (dirStats.isDirectory()) { + const fallbackCandidate = await this.findLikelyFile(directory, directory) + if (fallbackCandidate) { + shell.showItemInFolder(fallbackCandidate) + return true + } + const result = await shell.openPath(directory) + if (result) { + console.error('Failed to open directory:', result) + return false + } + return true + } + } catch (dirError) { + console.error('Failed to open parent directory:', dirError) + } + console.error('Failed to open file location:', error) + return false + } + + return false + } + + private sanitizePath(target: string): string { + return target.trim().replace(/^['"]|['"]$/g, '') + } + + private async findLikelyFile(directory: string, expectedPath: string): Promise { + try { + const dirStats = await fs.stat(directory) + if (!dirStats.isDirectory()) { + return null + } + + const entries = await fs.readdir(directory, { withFileTypes: true }) + const files = entries.filter((entry: Dirent) => entry.isFile()) + if (files.length === 0) { + return null + } + + const expectedBase = path.basename(expectedPath).toLowerCase() + const expectedName = path.parse(expectedPath).name.toLowerCase() + + const exactMatch = files.find((entry) => entry.name.toLowerCase() === expectedBase) + if (exactMatch) { + return path.join(directory, exactMatch.name) + } + + if (expectedName) { + const partialMatch = files.find((entry) => entry.name.toLowerCase().includes(expectedName)) + if (partialMatch) { + return path.join(directory, partialMatch.name) + } + } + + let latestMatch: { filePath: string; mtimeMs: number } | null = null + for (const entry of files) { + const candidatePath = path.join(directory, entry.name) + try { + const candidateStats = await fs.stat(candidatePath) + if (!latestMatch || candidateStats.mtimeMs > latestMatch.mtimeMs) { + latestMatch = { filePath: candidatePath, mtimeMs: candidateStats.mtimeMs } + } + } catch (statError) { + console.error('Failed to stat candidate file:', statError) + } + } + + return latestMatch?.filePath ?? null + } catch (error) { + console.error('Failed to search for matching file:', error) + return null + } + } + + @IpcMethod() + async openExternal(_context: IpcContext, url: string): Promise { + try { + await shell.openExternal(url) + return true + } catch (error) { + console.error('Failed to open external URL:', error) + return false + } + } +} + +export { FileSystemService } diff --git a/src/main/ipc/services/history-service.ts b/src/main/ipc/services/history-service.ts new file mode 100644 index 0000000..5b8f620 --- /dev/null +++ b/src/main/ipc/services/history-service.ts @@ -0,0 +1,315 @@ +import fs from 'node:fs/promises' +import path from 'node:path' +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' +import type { DownloadHistoryItem } from '../../../shared/types' +import { historyManager } from '../../lib/history-manager' +import { settingsManager } from '../../settings' + +class HistoryService extends IpcService { + static readonly groupName = 'history' + + @IpcMethod() + getHistory(_context: IpcContext): DownloadHistoryItem[] { + return historyManager.getHistory() + } + + @IpcMethod() + getHistoryById(_context: IpcContext, id: string): DownloadHistoryItem | undefined { + return historyManager.getHistoryById(id) + } + + @IpcMethod() + addHistoryItem(_context: IpcContext, item: DownloadHistoryItem): void { + historyManager.addHistoryItem(item) + } + + @IpcMethod() + async removeHistoryItem(_context: IpcContext, id: string, outputPath?: string): Promise { + const record = historyManager.getHistoryById(id) + + await this.deleteOutputResource(record, outputPath) + + return historyManager.removeHistoryItem(id) + } + + private async deleteOutputResource( + record: DownloadHistoryItem | undefined, + fallbackOutputPath?: string + ): Promise { + try { + const candidatePaths = new Set() + if (record?.outputPath) { + candidatePaths.add(record.outputPath) + } + if (fallbackOutputPath) { + candidatePaths.add(fallbackOutputPath) + } + + for (const candidate of candidatePaths) { + if (await this.tryDeletePath(candidate)) { + return + } + } + + const directories = this.collectCandidateDirectories(candidatePaths) + if (directories.length === 0) { + const defaultDownloadPath = settingsManager.get('downloadPath') + if (defaultDownloadPath) { + directories.push(defaultDownloadPath) + } + } + + const matchKeys = this.collectMatchKeys(record, candidatePaths) + if (matchKeys.length === 0) { + return + } + + const extensions = this.collectExtensions(candidatePaths, record) + for (const directory of directories) { + const matchedPath = await this.findMatchingFile(directory, matchKeys, extensions, record) + if (matchedPath && (await this.tryDeletePath(matchedPath))) { + return + } + } + } catch (error) { + console.error('Failed to delete output resource:', error) + } + } + + private sanitizePath(target: string): string { + return target.trim().replace(/^['"]|['"]$/g, '') + } + + private normalizeMatchString(value?: string): string { + if (!value) { + return '' + } + return value + .normalize('NFKC') + .toLowerCase() + .replace(/[^\p{L}\p{N}]+/gu, '') + } + + private collectCandidateDirectories(candidatePaths: Set): string[] { + const directories = new Set() + for (const candidate of candidatePaths) { + const sanitized = this.sanitizePath(candidate) + if (!sanitized) continue + const normalized = path.normalize(sanitized) + if (!path.isAbsolute(normalized)) continue + const directory = path.dirname(normalized) + if (directory) { + directories.add(directory) + } + } + return Array.from(directories) + } + + private collectExtensions( + candidatePaths: Set, + record: DownloadHistoryItem | undefined + ): Set { + const extensions = new Set() + + const addExtension = (ext?: string) => { + if (!ext) { + return + } + const trimmed = ext.trim() + if (!trimmed) { + return + } + const normalized = trimmed.startsWith('.') + ? trimmed.toLowerCase() + : `.${trimmed.toLowerCase()}` + extensions.add(normalized) + } + + for (const candidate of candidatePaths) { + const sanitized = this.sanitizePath(candidate) + if (!sanitized) continue + addExtension(path.extname(sanitized)) + } + + addExtension(record?.outputPath ? path.extname(record.outputPath) : undefined) + addExtension(record?.selectedFormat?.ext) + addExtension(record?.selectedFormat?.video_ext) + addExtension(record?.selectedFormat?.audio_ext) + + if (extensions.size === 0) { + const fallback = + record?.type === 'audio' + ? ['.mp3', '.m4a', '.aac', '.ogg', '.opus', '.flac', '.wav'] + : ['.mp4', '.mkv', '.webm', '.mov', '.avi'] + for (const ext of fallback) { + extensions.add(ext) + } + } + + return extensions + } + + private collectMatchKeys( + record: DownloadHistoryItem | undefined, + candidatePaths: Set + ): string[] { + const keys = new Set() + const fallbackKeys: string[] = [] + + const tryAddKey = (value?: string) => { + if (!value) return + const normalized = this.normalizeMatchString(value) + if (!normalized) return + if (normalized.length >= 3) { + keys.add(normalized) + } else { + fallbackKeys.push(normalized) + } + } + + for (const candidate of candidatePaths) { + const sanitized = this.sanitizePath(candidate) + if (!sanitized) continue + const baseName = path.parse(sanitized).name + tryAddKey(baseName) + } + + tryAddKey(record?.title) + tryAddKey(record?.id) + + if (keys.size === 0) { + for (const key of fallbackKeys) { + keys.add(key) + } + } + + return Array.from(keys) + } + + private async findMatchingFile( + directory: string, + matchKeys: string[], + extensions: Set, + record: DownloadHistoryItem | undefined + ): Promise { + try { + const dirStats = await fs.stat(directory).catch((error) => { + const err = error as NodeJS.ErrnoException + if (err?.code === 'ENOENT') { + return null + } + throw error + }) + + if (!dirStats || !dirStats.isDirectory()) { + return null + } + + const entries = await fs.readdir(directory, { withFileTypes: true }) + const matches: Array<{ path: string; diff: number }> = [] + const targetTimestamp = record?.completedAt ?? record?.downloadedAt + const maxDiff = 10 * 60 * 1000 // 10 minutes + + for (const entry of entries) { + if (!entry.isFile()) continue + + const entryPath = path.join(directory, entry.name) + const entryExt = path.extname(entry.name).toLowerCase() + if (extensions.size > 0 && entryExt && !extensions.has(entryExt)) { + continue + } + + const normalizedName = this.normalizeMatchString(entry.name) + if (!normalizedName && matchKeys.length > 0) continue + + const hasMatchKeys = matchKeys.length > 0 + const isMatch = hasMatchKeys + ? matchKeys.some((key) => key && normalizedName.includes(key)) + : true + if (!isMatch) continue + + const stats = await fs.stat(entryPath).catch(() => null) + if (!stats) continue + + if (targetTimestamp) { + const diff = Math.abs(stats.mtimeMs - targetTimestamp) + if (diff > maxDiff) { + continue + } + matches.push({ path: entryPath, diff }) + } else { + if (!hasMatchKeys) { + continue + } + matches.push({ path: entryPath, diff: Number.POSITIVE_INFINITY }) + } + } + + if (matches.length === 0) { + return null + } + + matches.sort((a, b) => a.diff - b.diff) + return matches[0]?.path ?? null + } catch (error) { + console.error('Failed to search for matching file:', error) + return null + } + } + + private async tryDeletePath(rawPath: string): Promise { + const sanitizedPath = this.sanitizePath(rawPath) + if (!sanitizedPath) return false + + const normalizedPath = path.normalize(sanitizedPath) + const stats = await fs.stat(normalizedPath).catch((error) => { + const err = error as NodeJS.ErrnoException + if (err?.code === 'ENOENT') { + return null + } + throw error + }) + + if (!stats) { + return false + } + + if (stats.isFile()) { + await fs.unlink(normalizedPath).catch((error) => { + const err = error as NodeJS.ErrnoException + if (err?.code !== 'ENOENT') { + throw error + } + }) + return true + } + + if (stats.isDirectory()) { + const entries = await fs.readdir(normalizedPath) + if (entries.length === 0) { + await fs.rmdir(normalizedPath).catch((error) => { + const err = error as NodeJS.ErrnoException + if (err?.code !== 'ENOENT') { + throw error + } + }) + return true + } + } + + return false + } + + @IpcMethod() + getHistoryCount(_context: IpcContext): { + active: number + completed: number + error: number + cancelled: number + total: number + } { + return historyManager.getHistoryCount() + } +} + +export { HistoryService } diff --git a/src/main/ipc/services/settings-service.ts b/src/main/ipc/services/settings-service.ts new file mode 100644 index 0000000..cec5938 --- /dev/null +++ b/src/main/ipc/services/settings-service.ts @@ -0,0 +1,43 @@ +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' +import type { AppSettings } from '../../../shared/types' +import { settingsManager } from '../../settings' +import { updateTrayMenu } from '../../tray' + +class SettingsService extends IpcService { + static readonly groupName = 'settings' + + @IpcMethod() + get(_context: IpcContext, key: K): AppSettings[K] { + return settingsManager.get(key) + } + + @IpcMethod() + set(_context: IpcContext, key: K, value: AppSettings[K]): void { + settingsManager.set(key, value) + + if (key === 'language') { + updateTrayMenu() + } + } + + @IpcMethod() + getAll(_context: IpcContext): AppSettings { + return settingsManager.getAll() + } + + @IpcMethod() + setAll(_context: IpcContext, settings: Partial): void { + settingsManager.setAll(settings) + + if (settings.language) { + updateTrayMenu() + } + } + + @IpcMethod() + reset(_context: IpcContext): void { + settingsManager.reset() + } +} + +export { SettingsService } diff --git a/src/main/ipc/services/thumbnail-service.ts b/src/main/ipc/services/thumbnail-service.ts new file mode 100644 index 0000000..ac8322a --- /dev/null +++ b/src/main/ipc/services/thumbnail-service.ts @@ -0,0 +1,20 @@ +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' +import { thumbnailCache } from '../../lib/thumbnail-cache' + +class ThumbnailService extends IpcService { + static readonly groupName = 'thumbnail' + + @IpcMethod() + async getThumbnailPath( + _context: IpcContext, + url: string | null | undefined + ): Promise { + if (!url) { + return null + } + + return thumbnailCache.getThumbnailUrl(url) + } +} + +export { ThumbnailService } diff --git a/src/main/ipc/services/update-service.ts b/src/main/ipc/services/update-service.ts new file mode 100644 index 0000000..2ad5cab --- /dev/null +++ b/src/main/ipc/services/update-service.ts @@ -0,0 +1,57 @@ +import { app } from 'electron' +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' +import { autoUpdater } from 'electron-updater' +import { settingsManager } from '../../settings' + +class UpdateService extends IpcService { + static readonly groupName = 'update' + + @IpcMethod() + async checkForUpdates( + _context: IpcContext + ): Promise<{ available: boolean; version?: string; error?: string }> { + try { + // In production, use checkForUpdatesAndNotify for automatic notifications + const result = await autoUpdater.checkForUpdatesAndNotify() + return { + available: result !== null, + version: result?.updateInfo?.version + } + } catch (error) { + return { + available: false, + error: error instanceof Error ? error.message : 'Unknown error' + } + } + } + + @IpcMethod() + async downloadUpdate(_context: IpcContext): Promise<{ success: boolean; error?: string }> { + try { + await autoUpdater.downloadUpdate() + return { success: true } + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Unknown error' + } + } + } + + @IpcMethod() + quitAndInstall(_context: IpcContext): void { + autoUpdater.quitAndInstall() + } + + @IpcMethod() + getCurrentVersion(_context: IpcContext): string { + return app.getVersion() + } + + @IpcMethod() + isAutoUpdateEnabled(_context: IpcContext): boolean { + return settingsManager.get('autoUpdate') + } +} + +export { UpdateService } diff --git a/src/main/ipc/services/window-service.ts b/src/main/ipc/services/window-service.ts new file mode 100644 index 0000000..3204dd9 --- /dev/null +++ b/src/main/ipc/services/window-service.ts @@ -0,0 +1,42 @@ +import { BrowserWindow } from 'electron' +import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator' + +class WindowService extends IpcService { + static readonly groupName = 'window' + + @IpcMethod() + minimize(_context: IpcContext): void { + const window = BrowserWindow.getFocusedWindow() + if (window) { + window.minimize() + } + } + + @IpcMethod() + maximize(_context: IpcContext): void { + const window = BrowserWindow.getFocusedWindow() + if (window) { + if (window.isMaximized()) { + window.unmaximize() + } else { + window.maximize() + } + } + } + + @IpcMethod() + close(_context: IpcContext): void { + const window = BrowserWindow.getFocusedWindow() + if (window) { + window.close() + } + } + + @IpcMethod() + isMaximized(_context: IpcContext): boolean { + const window = BrowserWindow.getFocusedWindow() + return window ? window.isMaximized() : false + } +} + +export { WindowService } diff --git a/src/main/lib/download-queue.ts b/src/main/lib/download-queue.ts new file mode 100644 index 0000000..70331fd --- /dev/null +++ b/src/main/lib/download-queue.ts @@ -0,0 +1,145 @@ +import { EventEmitter } from 'node:events' +import type { DownloadItem, DownloadOptions } from '../../shared/types' + +interface QueueItem { + id: string + options: DownloadOptions + item: DownloadItem +} + +export class DownloadQueue extends EventEmitter { + private queue: QueueItem[] = [] + private activeDownloads: Map = new Map() + private completedDownloads: Map = new Map() + private maxConcurrent: number + + constructor(maxConcurrent: number = 5) { + super() + this.maxConcurrent = maxConcurrent + } + + setMaxConcurrent(max: number): void { + this.maxConcurrent = max + this.processQueue() + } + + add(id: string, options: DownloadOptions, item: DownloadItem): void { + this.queue.push({ id, options, item }) + this.emit('queue-updated', this.getQueueStatus()) + this.processQueue() + } + + remove(id: string): boolean { + // Remove from queue + const queueIndex = this.queue.findIndex((item) => item.id === id) + if (queueIndex !== -1) { + this.queue.splice(queueIndex, 1) + this.emit('queue-updated', this.getQueueStatus()) + return true + } + + // Remove from active downloads + if (this.activeDownloads.has(id)) { + this.activeDownloads.delete(id) + this.emit('queue-updated', this.getQueueStatus()) + this.processQueue() + return true + } + + return false + } + + downloadCompleted(id: string): void { + const activeDownload = this.activeDownloads.get(id) + if (activeDownload) { + this.completedDownloads.set(id, activeDownload) + this.activeDownloads.delete(id) + } + this.emit('queue-updated', this.getQueueStatus()) + this.processQueue() + } + + private processQueue(): void { + while (this.activeDownloads.size < this.maxConcurrent && this.queue.length > 0) { + const item = this.queue.shift() + if (item) { + this.activeDownloads.set(item.id, item) + this.emit('start-download', item) + } + } + this.emit('queue-updated', this.getQueueStatus()) + } + + getQueueStatus(): { + queued: number + active: number + activeIds: string[] + } { + return { + queued: this.queue.length, + active: this.activeDownloads.size, + activeIds: Array.from(this.activeDownloads.keys()) + } + } + + isDownloading(id: string): boolean { + return this.activeDownloads.has(id) + } + + getCompletedDownload(id: string): QueueItem | undefined { + return this.completedDownloads.get(id) + } + + getItemDetails(id: string): { options: DownloadOptions; item: DownloadItem } | undefined { + const inActive = this.activeDownloads.get(id) + if (inActive) { + return { + options: inActive.options, + item: { ...inActive.item } + } + } + + const inQueue = this.queue.find((entry) => entry.id === id) + if (inQueue) { + return { + options: inQueue.options, + item: { ...inQueue.item } + } + } + + const completed = this.completedDownloads.get(id) + if (completed) { + return { + options: completed.options, + item: { ...completed.item } + } + } + + return undefined + } + + updateItemInfo(id: string, updates: Partial): void { + // Update in queue + const queueItem = this.queue.find((item) => item.id === id) + if (queueItem) { + Object.assign(queueItem.item, updates) + } + + // Update in active downloads + const activeItem = this.activeDownloads.get(id) + if (activeItem) { + Object.assign(activeItem.item, updates) + } + + // Update in completed downloads + const completedItem = this.completedDownloads.get(id) + if (completedItem) { + Object.assign(completedItem.item, updates) + } + } + + clear(): void { + this.queue = [] + this.emit('queue-updated', this.getQueueStatus()) + } +} diff --git a/src/main/lib/history-manager.ts b/src/main/lib/history-manager.ts new file mode 100644 index 0000000..dfebee8 --- /dev/null +++ b/src/main/lib/history-manager.ts @@ -0,0 +1,116 @@ +// Use require for electron-store to avoid CommonJS/ESM issues +const ElectronStore = require('electron-store') +// Access the default export +const Store = ElectronStore.default || ElectronStore + +import type { DownloadHistoryItem } from '../../shared/types' + +class HistoryManager { + // biome-ignore lint/suspicious/noExplicitAny: electron-store requires dynamic import + private store: any + private history: Map = new Map() + + constructor() { + this.store = new Store({ + name: 'download-history', + defaults: { + items: [] + } + }) + this.loadHistory() + } + + private loadHistory(): void { + try { + const historyArray = this.store.get('items', []) + this.history = new Map(historyArray.map((item) => [item.id, item])) + } catch (error) { + console.error('Failed to load download history:', error) + } + } + + private saveHistory(): void { + try { + const historyArray = Array.from(this.history.values()) + this.store.set('items', historyArray) + } catch (error) { + console.error('Failed to save download history:', error) + } + } + + addHistoryItem(item: DownloadHistoryItem): void { + this.history.set(item.id, item) + this.saveHistory() + } + + getHistory(): DownloadHistoryItem[] { + return Array.from(this.history.values()).sort((a, b) => { + const aTime = a.completedAt || a.downloadedAt + const bTime = b.completedAt || b.downloadedAt + return bTime - aTime + }) + } + + getHistoryById(id: string): DownloadHistoryItem | undefined { + return this.history.get(id) + } + + removeHistoryItem(id: string): boolean { + const deleted = this.history.delete(id) + if (deleted) { + this.saveHistory() + } + return deleted + } + + clearHistory(): void { + this.history.clear() + this.saveHistory() + } + + clearHistoryByStatus(status: DownloadHistoryItem['status']): number { + let removedCount = 0 + for (const [id, item] of this.history.entries()) { + if (item.status === status) { + this.history.delete(id) + removedCount++ + } + } + if (removedCount > 0) { + this.saveHistory() + } + return removedCount + } + + getHistoryCount(): { + active: number + completed: number + error: number + cancelled: number + total: number + } { + const counts = { + active: 0, + completed: 0, + error: 0, + cancelled: 0, + total: this.history.size + } + + for (const item of this.history.values()) { + if (item.status === 'completed') { + counts.completed++ + } else if (item.status === 'error') { + counts.error++ + } else if (item.status === 'cancelled') { + counts.cancelled++ + } else { + counts.active++ + } + } + + return counts + } +} + +export const historyManager = new HistoryManager() diff --git a/src/main/lib/thumbnail-cache.ts b/src/main/lib/thumbnail-cache.ts new file mode 100644 index 0000000..f78f86d --- /dev/null +++ b/src/main/lib/thumbnail-cache.ts @@ -0,0 +1,137 @@ +import crypto from 'node:crypto' +import fs from 'node:fs' +import fsPromises from 'node:fs/promises' +import path from 'node:path' +import { pathToFileURL } from 'node:url' +import { app } from 'electron' + +const SUPPORTED_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.webp', '.gif']) + +const contentTypeToExtension = (contentType?: string): string => { + if (!contentType) return '.jpg' + if (contentType.includes('jpeg')) return '.jpg' + if (contentType.includes('png')) return '.png' + if (contentType.includes('webp')) return '.webp' + if (contentType.includes('gif')) return '.gif' + return '.jpg' +} + +export class ThumbnailCache { + private cacheDir?: string + private pending: Map> = new Map() + + private ensureCacheDir(): string { + if (this.cacheDir) { + return this.cacheDir + } + const dir = path.join(app.getPath('userData'), 'thumbnails') + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }) + } + this.cacheDir = dir + return dir + } + + async getThumbnailUrl(originalUrl: string): Promise { + if (!originalUrl) { + return null + } + + if (originalUrl.startsWith('file://') || originalUrl.startsWith('data:')) { + return originalUrl + } + + if (this.pending.has(originalUrl)) { + return this.pending.get(originalUrl) ?? null + } + + const task = this.fetchAndCache(originalUrl).finally(() => { + this.pending.delete(originalUrl) + }) + this.pending.set(originalUrl, task) + return task + } + + private async fetchAndCache(originalUrl: string): Promise { + try { + const cacheDir = this.ensureCacheDir() + const { basePath, defaultExtension } = this.getBasePath(cacheDir, originalUrl) + + const existingPath = await this.findExistingPath(basePath, defaultExtension) + if (existingPath) { + return pathToFileURL(existingPath).toString() + } + + const response = await fetch(originalUrl) + if (!response.ok) { + throw new Error(`Failed to fetch thumbnail (${response.status})`) + } + + const arrayBuffer = await response.arrayBuffer() + const buffer = Buffer.from(arrayBuffer) + const extension = + contentTypeToExtension(response.headers.get('content-type') ?? undefined) || + defaultExtension + const finalPath = `${basePath}${extension}` + + await fsPromises.writeFile(finalPath, buffer) + return pathToFileURL(finalPath).toString() + } catch (error) { + console.error('Failed to cache thumbnail:', error) + return null + } + } + + private async findExistingPath( + basePath: string, + defaultExtension: string + ): Promise { + for (const ext of SUPPORTED_EXTENSIONS) { + const candidate = `${basePath}${ext}` + if (await this.exists(candidate)) { + return candidate + } + } + + const fallback = `${basePath}${defaultExtension}` + if (await this.exists(fallback)) { + return fallback + } + + return null + } + + private async exists(filePath: string): Promise { + try { + await fsPromises.access(filePath) + return true + } catch { + return false + } + } + + private getBasePath( + cacheDir: string, + url: string + ): { + basePath: string + defaultExtension: string + } { + const hash = crypto.createHash('sha1').update(url).digest('hex') + let extension = '.jpg' + try { + const parsedUrl = new URL(url) + const urlExt = path.extname(parsedUrl.pathname).toLowerCase() + if (SUPPORTED_EXTENSIONS.has(urlExt)) { + extension = urlExt + } + } catch { + // Ignore parsing errors and keep default extension + } + + const basePath = path.join(cacheDir, `${hash}`) + return { basePath, defaultExtension: extension } + } +} + +export const thumbnailCache = new ThumbnailCache() diff --git a/src/main/lib/ytdlp-manager.ts b/src/main/lib/ytdlp-manager.ts new file mode 100644 index 0000000..62ed336 --- /dev/null +++ b/src/main/lib/ytdlp-manager.ts @@ -0,0 +1,121 @@ +import { execSync } from 'node:child_process' +import fs from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import type YTDlpWrap from 'yt-dlp-wrap-plus' + +// Use require for yt-dlp-wrap-plus to handle CommonJS/ESM compatibility +const YTDlpWrapModule = require('yt-dlp-wrap-plus') +const YTDlpWrapCtor: typeof YTDlpWrap = YTDlpWrapModule.default || YTDlpWrapModule +type YTDlpWrapInstance = InstanceType + +class YtDlpManager { + private ytdlpPath: string | null = null + private ytdlpInstance: YTDlpWrapInstance | null = null + + async initialize(): Promise { + this.ytdlpPath = await this.findOrDownloadYtDlp() + this.ytdlpInstance = new YTDlpWrapCtor(this.ytdlpPath) + console.log('yt-dlp initialized at:', this.ytdlpPath) + } + + getInstance(): YTDlpWrapInstance { + if (!this.ytdlpInstance) { + throw new Error('yt-dlp not initialized. Call initialize() first.') + } + return this.ytdlpInstance + } + + getPath(): string { + if (!this.ytdlpPath) { + throw new Error('yt-dlp not initialized. Call initialize() first.') + } + return this.ytdlpPath + } + + private getResourcesPath(): string { + // In development, read from project root's resources + if (process.env.NODE_ENV === 'development') { + return path.join(process.cwd(), 'resources') + } + // In production, unpacked binaries live under app.asar.unpacked/resources + return path.join(process.resourcesPath, 'app.asar.unpacked', 'resources') + } + + private async findOrDownloadYtDlp(): Promise { + const platform = os.platform() + let bundledName: string + + // Determine the binary name based on platform + if (platform === 'win32') { + bundledName = 'yt-dlp.exe' + } else if (platform === 'darwin') { + bundledName = 'yt-dlp_macos' + } else { + bundledName = 'yt-dlp_linux' + } + + // Check environment variable first + if (process.env.YTDLP_PATH && fs.existsSync(process.env.YTDLP_PATH)) { + console.log('Using yt-dlp from YTDLP_PATH:', process.env.YTDLP_PATH) + return process.env.YTDLP_PATH + } + + // Check for bundled yt-dlp in resources directory + const resourcesPath = this.getResourcesPath() + const bundledPath = path.join(resourcesPath, bundledName) + if (fs.existsSync(bundledPath)) { + console.log('Using bundled yt-dlp:', bundledPath) + // Make executable on Unix-like systems if needed + if (platform !== 'win32') { + try { + fs.chmodSync(bundledPath, 0o755) + } catch (error) { + console.warn('Failed to set executable permission:', error) + } + } + return bundledPath + } + + // Check for system-installed yt-dlp on macOS + if (os.platform() === 'darwin') { + const possiblePaths = ['/opt/homebrew/bin/yt-dlp', '/usr/local/bin/yt-dlp'] + for (const p of possiblePaths) { + if (fs.existsSync(p)) { + console.log('Using system yt-dlp:', p) + return p + } + } + } + + // Check for system-installed yt-dlp on Linux/FreeBSD + if (os.platform() === 'linux' || os.platform() === 'freebsd') { + try { + const systemPath = execSync('which yt-dlp').toString().trim() + if (systemPath && fs.existsSync(systemPath)) { + console.log('Using system yt-dlp:', systemPath) + return systemPath + } + } catch (_error) { + // yt-dlp not in PATH, continue + } + } + + // At this point, no bundled/system binary found. + // For Windows, we do NOT download at runtime. Require bundling. + if (platform === 'win32') { + throw new Error( + 'yt-dlp not found. Ensure resources/yt-dlp.exe is bundled (asarUnpack) in the build.' + ) + } + + // For macOS/Linux, instruct user to bundle or install system yt-dlp. + throw new Error( + 'yt-dlp not found. Bundle it under resources/ (asarUnpack) or install yt-dlp in system PATH.' + ) + } + + // Removed runtime download/update to avoid network dependency in production builds +} + +export const ytdlpManager = new YtDlpManager() diff --git a/src/main/settings.ts b/src/main/settings.ts new file mode 100644 index 0000000..36806e6 --- /dev/null +++ b/src/main/settings.ts @@ -0,0 +1,51 @@ +import os from 'node:os' +import path from 'node:path' +import type { AppSettings } from '../shared/types' +import { defaultSettings } from '../shared/types' + +// Use require for electron-store to avoid CommonJS/ESM issues +const ElectronStore = require('electron-store') +// Access the default export +const Store = ElectronStore.default || ElectronStore + +class SettingsManager { + // biome-ignore lint/suspicious/noExplicitAny: electron-store requires dynamic import + private store: any + + constructor() { + this.store = new Store({ + defaults: { + ...defaultSettings, + downloadPath: path.join(os.homedir(), 'Downloads') + } + }) + } + + get(key: K): AppSettings[K] { + return this.store.get(key) + } + + set(key: K, value: AppSettings[K]): void { + this.store.set(key, value) + } + + getAll(): AppSettings { + return this.store.store + } + + setAll(settings: Partial): void { + for (const [key, value] of Object.entries(settings)) { + this.store.set(key as keyof AppSettings, value as AppSettings[keyof AppSettings]) + } + } + + reset(): void { + this.store.clear() + this.store.set({ + ...defaultSettings, + downloadPath: path.join(os.homedir(), 'Downloads') + }) + } +} + +export const settingsManager = new SettingsManager() diff --git a/src/main/tray.ts b/src/main/tray.ts new file mode 100644 index 0000000..5c2e3e9 --- /dev/null +++ b/src/main/tray.ts @@ -0,0 +1,138 @@ +import { app, BrowserWindow, Menu, nativeImage, Tray } from 'electron' +import appIcon from '../../resources/icon.png?asset' +import { settingsManager } from './settings' + +let tray: Tray | null = null + +/** + * Get translated text based on current language setting + */ +function t(key: 'showHome' | 'quit'): string { + const language = settingsManager.get('language') || 'en' + + const translations = { + en: { + showHome: 'Show Home', + quit: 'Quit' + }, + zh: { + showHome: '打开首页', + quit: '关闭应用' + } + } + + const displayLang = language.startsWith('en') ? 'en' : 'zh' + return translations[displayLang][key] +} + +/** + * Find the main window + */ +function findMainWindow(): BrowserWindow | null { + const windows = BrowserWindow.getAllWindows() + return windows.find((window) => !window.isDestroyed()) || null +} + +/** + * Create context menu for tray + */ +function createContextMenu(): Menu { + return Menu.buildFromTemplate([ + { + label: t('showHome'), + click: () => { + const mainWindow = findMainWindow() + if (mainWindow) { + if (mainWindow.isMinimized()) { + mainWindow.restore() + } + mainWindow.show() + mainWindow.focus() + } + } + }, + { + type: 'separator' + }, + { + label: t('quit'), + click: () => { + // Force close all windows before quitting + const windows = BrowserWindow.getAllWindows() + + // Close all windows forcefully + for (const window of windows) { + window.destroy() + } + + // Quit the application and exit the process + app.quit() + + // Force exit if quit doesn't work + setTimeout(() => { + app.exit(0) + }, 1000) + } + } + ]) +} + +/** + * Create system tray icon + */ +export function createTray(): void { + if (tray) { + return + } + + const trayIcon = nativeImage.createFromPath(appIcon) + + tray = new Tray(trayIcon) + + // Set tooltip + tray.setToolTip('VidBee') + + // Set context menu + tray.setContextMenu(createContextMenu()) + + // On Windows/Linux: click to show/hide main window + tray.on('click', async () => { + const mainWindow = findMainWindow() + if (mainWindow) { + if (mainWindow.isVisible()) { + // If window is visible, hide it + mainWindow.hide() + } else { + // If window is hidden or minimized, show it + if (mainWindow.isMinimized()) { + mainWindow.restore() + } + mainWindow.show() + mainWindow.focus() + } + } else { + // If no main window exists, create a new one + const { createWindow } = await import('./index') + createWindow() + } + }) +} + +/** + * Update tray menu (call this when language changes) + */ +export function updateTrayMenu(): void { + if (tray) { + tray.setContextMenu(createContextMenu()) + } +} + +/** + * Destroy tray icon + */ +export function destroyTray(): void { + if (tray) { + tray.destroy() + tray = null + } +} diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts new file mode 100644 index 0000000..77defaf --- /dev/null +++ b/src/preload/index.d.ts @@ -0,0 +1,13 @@ +import type { ElectronAPI } from '@electron-toolkit/preload' +import type { IpcServices } from '../main/ipc' + +declare global { + interface Window { + electron: ElectronAPI + api: IpcServices & { + on: (channel: string, callback: (...args: unknown[]) => void) => void + removeListener: (channel: string, callback: (...args: unknown[]) => void) => void + send: (channel: string, ...args: unknown[]) => void + } + } +} diff --git a/src/preload/index.ts b/src/preload/index.ts new file mode 100644 index 0000000..da94e23 --- /dev/null +++ b/src/preload/index.ts @@ -0,0 +1,45 @@ +import { electronAPI } from '@electron-toolkit/preload' +import { contextBridge, ipcRenderer } from 'electron' +import { createIpcProxy } from 'electron-ipc-decorator/client' +import type { IpcServices } from '../main/ipc' + +// Create type-safe IPC proxy using electron-ipc-decorator +const ipcServices = createIpcProxy(ipcRenderer) + +// Custom APIs for renderer +const api = { + // IPC Services (type-safe, using decorators) + ...ipcServices, + + // Event listening API + on: (channel: string, callback: (...args: unknown[]) => void) => { + const subscription = (_event: Electron.IpcRendererEvent, ...args: unknown[]) => + callback(...args) + ipcRenderer.on(channel, subscription) + return subscription + }, + removeListener: (channel: string, callback: (...args: unknown[]) => void) => { + ipcRenderer.removeListener(channel, callback) + }, + // Send message to main process + send: (channel: string, ...args: unknown[]) => { + ipcRenderer.send(channel, ...args) + } +} + +// Use `contextBridge` APIs to expose Electron APIs to +// renderer only if context isolation is enabled, otherwise +// just add to the DOM global. +if (process.contextIsolated) { + try { + contextBridge.exposeInMainWorld('electron', electronAPI) + contextBridge.exposeInMainWorld('api', api) + } catch (error) { + console.error('Failed to expose APIs in context bridge:', error) + } +} else { + // @ts-expect-error (define in dts) + window.electron = electronAPI + // @ts-expect-error (define in dts) + window.api = api +} diff --git a/src/renderer/index.html b/src/renderer/index.html new file mode 100644 index 0000000..41cbb87 --- /dev/null +++ b/src/renderer/index.html @@ -0,0 +1,16 @@ + + + + + + VidBee + + + + +

+ + + + diff --git a/src/renderer/public/app-icon.png b/src/renderer/public/app-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6d03b62e74457b56db6ef87883b4b04a419f65ee GIT binary patch literal 14607 zcmY*=c|26#|Npr&V;Osv2pMI~-ipu+5t60Iz9w0t?Ad1UE=gr4Ql>?ez3gH}N*w+Cn7Q}7&N;7h=G=2$&*$@X<|$a7kYWlyr*DAQu>SZDVZ!$`jf5T$lh* zdugbvZ4nC1kJg= zYl)d+Lh?}d)PcJnI8;_oq@?bj)-?3G<{0sMTGBW+p1t=;BY$rO2kJ!R5gm7C<7Bn{ zK`&Yt{Ws=<4C*RAwuh)!H*~>PWod@@3_B9tiyH<;!bKo9|J9ZcMd7OQk?M-CJI^{O_?aSV665g(Hzg_#*m$(CBp8q8oC(ngUKrt2>= zY#s}9Zmptr7_8~u+>hKgqYSG~`*kaMoZ=f(3{M5 z^wGujmQ5)yH%?!V`6CW_kRF#Rb?CP!)G*E4c-}B2@}w~!n}Equ@3+IXoxo+t0HE>; z>1qPiJ*vWMQ%vY*Yus}#lfsvyZ!EuL?+DJqhkbjsA>~quPqXy7`t~3@DXysYM!Cn+ z$jLf!AxRKD^rIB_L~1GV4w^`cF7iA~?RFLl9l2$KCiaD7Z3h!^64^eVdd_bJ0p^c6 z1Q7b`);(%2ju|E;yTy~X`{Xk*KMp}l99oP$&l&u~t;?XLtmQt57&?0^hU&zD*x45+ zvu?#=sOY-H@nW;m^UX@Xj-W>wB-HdqlgTFUDzx5`TG~?4h0C|0Q~-8&3X$##4#^jm zNG)k9M*Hi3j~}qx=xU^jTEvG6XI!nHz&QlJUQpMT zvZkZO$Wms)Pwz-|^U+fpYn#%DL2GYu4QnhU?hb*~Ie9_M?Zc4lBj4rG0~?R|EbfTF zpi4#2Ozj$A3*0othYTtWII!S@o_)fBwH7 zJngmm9dyE3lo{Y;Sk65s``0b`Nfj}m#ILnpRJ)B)O1Nc`JTEC{<`x43?~vEHF-?~* z&7aJ~+^{Z;AeSo zvZOdp5~z!B4VugUndHR8ONt9>9{Q}iR4Q|w?#%=UWCK*oIg|=>3^5XMAbKeobN{wf z&)vY0+-S%VTU?0@Ij`tE?Fl~V^gL}rOJ0;(yQ{pIaNGfS%?iwO;Vf4XQbTC zJlU;QUfUEO-Hcdbv_^?jp-z2iT=3Tm(kOEBz}3Rt6N0RqcQDQbjq075PiJ!Gom>^I z7`Z+H8~ASLY)sBgLuwt(tnWMvEe8JHncj$jv%RI>zx>Ja*mh>)l3-!g_*!lor#-Krl*y*@CNeMy$dHbwX_AiBmUgGwUN#qgD$r} zt)q~0Yg|^5aQoW0OiN!SviBKg0aTY%MNMzgEc27a=ta z9~|Yfh@X{XXDBUg#wo0Jbyi%x=S5W;_|(?>r?<3(P3%MO3eY%9lt(E~S5nf9FY3Qw zh8+?Q`WZd8Q~cayMuS2x&%1VY<20K-;R^~iO2)@=u2jFVN{kSXXnW3uic+Kr^8nn% zaRs(WVyUD8NqVE~+dpgK<6EabM`|75wZh*%Q9l$bFquKBKN=HUEIAGhnzWH6Zax zDuZ^Q4K9$s4o%z^CUD))$%sES$g(I74JD5)>5q?Vge`JU5>IG9{i6GBII~9mh6t84 zm&O=gT$E~qJ?^PVfBS0eDGBrQnf)au5B?st%2?#z9&vCBvH{pWvt<3e+I|?qO0{-S!H_x(jGC+fcQ6}}# z+@29z*DJa{)EC-hw}_(2(mr&kZj;C@O3!>7tIBvp9`3FWFCQsk+{O(o2J4^RXI5yR z_{76}UT&byCn(qF7t)cjyu*@T;LPU`O`e~r!>)>1S)wJp-S@BzsjTa>1ZN2+n`$Q~ zwJAn^fck%*rR@zXjM>4{T1r2D#b5l%f$pm=cm5W)S2{3Rr!srmb6#eFB~RvHCeba3OBlMpKdus-Z7>2yX@T?8#K0_W$c>wQzlgYJ;ygcZ7>@yI+bGZ9*1nUARIGT;G5P z2H2<($Shj3w7ALEQqdOQ6w6*FxZ1Hi)Dpe2l&OE{4=kRGWrz7h);Q zYt0*v@M|HLjCg@&(Z0(hTJ9^2LO36zO@@hOF0rr@U4C(F{#r2_Xb77zv7UkMnr8`a z&{?!Y;BWBw_#OGF&Cjf~osdOePNJn2PZ_Nca2DkI&pOE--hgoi;f&uSLvt6Iz{b6~ z7>vR+#(B4cXbC@~0Wv)(e8##EcGyu292F-Wls@h4r+^7}ix?6B-jDXUS+P{c>4rVa zc@8uRry@T;A%(Rl!xDmL62I)gtQe&9;mCq&-zG1>Id=r`7C7^PD#q>GV?-e5f4a|w z>WnM&p|i8IfP)HMZLF8~JL7JyJ;%tlVrU!Q?5AthWmuUt0N1H+ZHt4}i>zQtTm$z@ z#W{&GZ+W5HPBr^(`b^W>xUoi@qE&Q*SZUsT6x!F>K(m*IeSOun?5`vEoG8`nuovypRj zZmvSODd&-=TXclA?GFCddqwb&$67?Z07Gbpkz#Hv)j9COuWx*O$BwISoo{@iyYftb zq{AAZv4xyG7AV3t{sJbyX@>HKuUGL_NAWbb$aF8Y)M<4n{*<5s6wCgGlV_;UbS-BA zB3R!wZSJMP)`f}#$i6$b8^SbAF&aB%(9LqLVvM=wFvRM^OzmWkIm_-GC_McRYKm72 zf9&%aLv&X7Spmfu0^i0u73DfBKJ9PTdhbzY68UF6(U??FbNQFL_6_8WEy%JlOzGt% zIrD-}1~=a-5qQbG)#k`yNd{M~VE+wb(zF%2;2+8Rbl7(k>u-f?qW3X?Bq*H{@as?_AJ9-{6<)@XaC@2p-R&6KpF;N4=OM??z^tM7 zOcnJ00yx~Y>4*X`$K(zDZ8d+pp`1CY;gb*x1TCGr+F8fSVtW$$1^pehm znB~ovs%R0EmJUEB4^Bi}C;8vDW0cYm+> z&F?)yGcS}QyluRmuVBR4cMSi|blifQ~@4uZI&@<~KfWkAY9M5Vk|6=QB0+Bu( zaNUoCf2k@NMza|MOU87Tpj2hT0uj5rbyLz324!)btZTpW6W%cMue=<4I%ir^N9_`5 z6hfkG5Nds~pY)xNl-}NzlcDQdv#2RUC4FbN7t`oOhP2^!)w3{QYA+WBf=ojDrs!xYk3BC>-tvQ+@{p@y z{oALM40`mwnKq|HIuqdV?8qV|^O5FAxi71Ax^TZ~EqEXlYlNx_3+cT7R>S$_eroX2 zB1LcMbIpjMZ$JU))+{;LZSv45W8eLaHRG_%;i<%%GwBo#7@~&WPY!_B@Ml(2I6S8@ z;vzf0|HDr>Ki8YV0e}CSLr=H=Z~_FlD^hLb2hzV3AgU+g@IX7RF8)Lep)MXwBlD< ze&Ufkt&iT}-=8KRfA8%!QQwX+q4Gu_yA9)LsK(2)Q0LHI4=N1HqMP$$KY ziJbcqap5il4=g^mevisWo!ccAKif;RpW#BBI(coRH-I~8j)Wo26I-nkFaXH)&V1%p zoZB=7_iyQtMD;!rLBR$7yx2-W(wqU}0ss^|th`3WP_xw`{|_5@P>?a^?v86e#{UpG z%FT+cJ0!THkRA87D+_XHaGPG^e~5J6XL^{>R0DV}|6RK@Ji9SwCr9tQh8q<#IeF~c zy)nCwhUp%nynz4VA%cZoEPeigZwAn8wf%d>_g&Xmt+Kz*vE(d6v3L(I$9Y+MT`Ulo zUN3$hQk}}Qqy2qs&g~0T;<%#YI}c3uJ6V1-sUW6gFAmG7KLOPQmC6(NmIBW`vo?6f zrmD}1+{6wI&0={@BfZ^gl1rP9%7+=`@qz{44XMiCk=*1317Ifm3*S~X!%Mp9xlRb- z0EZ+X!ZQvnkmeEo7N1LfGPnuN-a|(CoQZTSXm>k(K0MMEu!>*-+oxc;t+r!m5;Yl+ z%{~&-j&#NF&CCDy5CaG*D?aKs|6|hmY$SU73Nvu)xg4(XWvcvD2nHPbElZ1;chq_A z{xCmW>Cm^;Wf{BV3SOl{(8|l`@bB0t`jbBP7*bL);MbM8yY92R0A(fxhM(HaIpZNc zT7JRwzuFPd{3yYlnimq}ak%tnY^2 zea`mo_kR%`*zSbfFRWNlKo>s4AJFXyPwh!Vfe&d{IMq-PcYNt8n=oR34BRl z!oX@ZWHB)+{;o9SV1h&YKYIrdpvA4}`l2}Y^Fvd!N*!0TskY<{#^;9rCLS7zi)nST zVOnFEVRISjx7y!#pPVS{p4Xzu_~+*O)1x9?g#?YyqLN+|cWxDi7>if1b)T2*1h>9< zQ5UMtG)$TX0Mwc6hq9@uj`)M&>y!k$R?;tz_*@z{;)?Xwqt~X=4FI^ogMjpx>W-ox z4oU*j^JLIxW^lIk$S?=!}nu4^w5rg8n_MJiMG<@eI4zngU_VmAvCt2ip=@B-E|M8P;= z=wEC6y45Q)##bLdi3)}c^WE_`u!i!ddV&oG4t^^b;8TXjm{gw zugD0exvq;cd+w7rUZ!Dy9N7e|qnNuod6EE_8A$?J{(sM;%)h4xxicGwEX=>_h5(R# zk(FE%mCXjoj>tDPTf`iXn2Y`!1NRgl-w0znOj4P--(?xH`?1%Txckvu>zBQ$M*rFF zwU50u+Htwt{~?X_vcx=%5n4(9Oz53nTpQcfsvV!fuc_0Y41RP?Bzod-EU#-Q&l?^D6bd{$m@P4UWGi+ z+HLN-V)yLmOTr!^pU8rw|?>7i?tFey7-nOlj%;Z>l!b=Pc2G2P5yFa6^=F^wN$HEE^AvHEda zVH2%wBXN|i`AGR4q%FjokaTsxfBO`msdE0wH@R?CG1`(>%VJ+QaUhCPvg7V|C_uw4}BFkEKtRtstApK*UDqsmuYc-Rx-TvOpm-gf#6o zi(`)g;!X`)Jr|vhnW1>r!>j@y5lE=-qjOjwj*Bf~^b@euEcW)lN|4&I$KYIfy%Y~f ziiIp;FPibt=sPgSN;q180@SUdlbOsm^unJeE;B7t2UvCYRiJL<9)y6(>A^SfZNbKJ zwdqXmbZ~VLlV5={<0wYmPy*n73la*(ZSOqma?x5%S1n~N2K(jdHxj|GY6+Im#-Uo;xGfp+;^TR z9O~R_3bB$pDM61z#eIt=D6yeP50r@ z17E(iS>>uvUAk9@n)oOrA(L47QeY~j5JjT2%x&Xk2lKs7@pV7Qy_z7t^1PU2w^`SL z1|Dkl@B0(FCIt2_mk5v?IBt0N0*qf-fhg z8&fwsm_oeRox2UbdKqmTd-ZZgAlOZVIfW5$ zWlnw5X{rL86~_V^u3j|DV{Z zg|E}A$431rxe8VX);8Z-vMZ+b@Nz(mxMX?q>tF?sS0N50r~3XVnBL$k zxmdF)ve3}TIolU#dS>FsD?85(M)Sgay#DExgoW#`^kR4l*5}r2T?amHj3+lL7*Qx* zPnDzCC|*s{K-Ev7qc#Ute|#-}pVyLmISJfT7>gmbg%L z#Zw9cC(X1m{OqZNWH>fNCXcH^ha68Wt*dq-M#QpdFWndOsJ{A7nZX>soB!u40)Hf2 zJ8PL}0Uyp&F4~r?;SFc-2EuFOjBn+0^J5QoxNmv!E4`sntdzCc81$%iY2O93d-Hd8?C_VxKCyW)@4Q*W8O#j zdlB)okM%acc?;sVz(JBUbXwsqIPlJT5NfhL zqZhJ6_rvP1|AOXrHxn{;odOyd(wVy~d2wuXMrni5NpXWe_X;ugN!hO*P=uw=E`clf zht~ALCmTDJ-{DOBX=$MxOLXH}`KAyrM{>G1!sI{A6n@>Gnnp`(*7e<|eq0-_Sy=O7 zz#D_OSA+OFrgg!{+_GNynnD_p1R7efz@e?*z=vLlcUXqw?Y7NVaJf||MzbINxMDP| zFaMy~#i&ocv9UvPLTN$6vrk{Il#$PS2c2GuVE)$g@0h-b@ykpl(HC8sn(!EBLQoIHFN`c?!_3-%&dI(-xXbjSYH~47t;2$@Ck$=rhm+l(Uo+1c0c|OVVhz* zvgv+#CbOMLcliTFxIce)DW%8pNJ&n(3F%Nbs^DSC&Vij(ZhWYyAX|=6N2H5imQHl_c&+e#0%={v4k1l_Ujj9sj*k8YmvY&)?d9vAJWlypX|qeYH_mBx9_3tg3+YssAILqEC!U90x=(ST zqs9IX-#TKgUdknrH}9=0Q~=Tvp|@qz!<^&K*l5b$XOx)akyB#^UbSeVTGOp!`-!0y zoYby9^H*B~w|*v$)N~;ZH*Zi@Jd>Q4lr?Rc$ZviZtB1Qj>&7|$#F9=*0wFFeVcVJ> zXGE;(K!vt1Vh9RYaOW&ci6~+;w`j6v_4{E6LwOd<&w}&OM)xb&v!F>32EE{2Z|-1&eWW zhan(*SG?QamVOBO?=VCtUW!p*nS`&oa)EnOinF(mP(REx;YAs}J{BZ00x9G_!oSLQ zSOkD9FCe>wZk?S11EB{`h#`)|a)L=(6Zg7=Bg+GQ6ga`5h!|-nA(7E_!D4=p*l>sEU0?B1656J@vL=|glA{BCyrW}Liweg$CDV+Y|+eyw+VAkDTFhmR>NanF_% z^6t%TWV{S6qnd0f??>k3|3w)n)Qr~0?E!(U2Jm5@m~hayD> zhRvAC!z`Y^$m72~`oO)9_qglVDybZVcSypCc=N`JK3y!*2xazCrT{pzlpU+)sEmgazw`k}=5dPLj~O7^T0<<$p|knS!Vo zRBwO~H~Qy)?eUT<{nv~-dr-1z8BxPrLq2KnGXro#(ir^1aUA{^&2o7OKV{)lqkfu= zhmh7E^4HSv$JH4ETITa=yN>!UGK6IVkZn|m-`hiKswBDcHNu7rwn@Wyd9&$z4ZF7!+op^%q^Pt~BvhR+$pf!c4n+a$`? z$Fas(Cja6Ct^-U$PyqPUODnw${#y*7bi5eSILAhRCh!zkKmNh%j5*Ch5Fm$U14M~@ z%oTBLZ|a#rlq{3nGbV9w)ct}%8AvvpnRuu9L(A;Axx}=nLaZVIV6vOg^zeTrkJ792oDl}4M%;Mf9&qh;A-n;T-})yguqu9EpGY3;T$Fy4 zPATle&|b=WTiZDX$1Zs+<+GV7HRwO3U2+oMgMa(c-*uS1#*%E(c+;~%!HEn#s0I1m zBC^2^D}q+!jO*gJP44DwB$eZmU@HQi!c@U!a6eX#aPmaA=CXml87}+L&GZ1-HV1lP z4Y7{8Mr@|hU4*8K2R;2!Df*G3i^gt zk@esTOXs64VM;^{Kr4K8nLY&G1Nv=7-w z3kL-)&Zd&!oi%*!4(&g<8o2e)fwPx{ruIsvHr&Ir|`_U5Zm zU9uw_H$2Drdvq*#yU@Osf4_X;zhF06xImAIFav3OUdmV6rf^dQ*3067_6( zI@$>SbonwXqsb=Kq%sn2@T#`=Pbc-37h-DgZ|_sPZOfCt1S=E_n5yz_n-bRpR!YJX ze@+)ih0Pw0dH3op@$x2p^Nm|Wnk4xB=wCLWm-%(Xo*zK{WG z-%{+h@lN@)Qm;`JH)+H=>#o!lG4g%}W6W?HiT?FY(s&T0y@6HTx!tPNZfP1zoF5sj zjM7QLI9mws2FZ2{rI6~J2}>?TJLpW~T?!+mFHO+&vt6m8{Y~x_L~{BN%$vljPKccL zK_CQi`-N-I)zgyON2+HB(-9BEYx^4;5Ii@3ukVp+V$0)F<(!0%_AiA=F1kuPT^Ek= zTdNXRe|v7HF5*X8tH30K+FvnF!Ici2voRtoCzJ@^up~j{$H|R9g401U>xo1Ah8jLj zoz2M>dJ|M$wV!2=qpkgyY(L;gkR<;=@J>Bb)Y8Js|Ngr~G`|`fH5F;SzBm~alBNrq z#jypHu>+7X>!~`1@8lkGq6~j)t(%ouitAuvG}<4_y>;D2lmBBVe>`AL_dv2)4sfiI zs#pT8yEEUAN;Xc?ylL)l@PSb*3?SVh>h;$+h>Q-dUhGoGNSo8 zTqcYUzCK1C-8wzswq(nfK(QDQay|`yQHBeoSJ=xW3>+PAt=q zDj~*NQt_R-ltHmZ<}LH%MYCu7?{%~vPyIqkTQnD33U4^MnZJHotl#d$Y%aI;_U!Q~ z$&|vFmTjwdF4wiuOWLnQ@Y`G4WmfCW&JC;NsP_sUIs2~z@f*SEG+0}6UF^o641kK2e;dFnB@?p_Fwo<1@;&u82ztsu--^& z6Nz%-?uOIdAh30h0Ut5|T;*EGaVZ{X0Z1w~BQX%SKr&rL36F-D049zBlaR~6Kka@>#}T=&Qok~oAPLSsE5d;F z3?+7E9hAy{77DRaz|1wiygeowY5dSzA4P~HYzHq1QoaU+{WEt)q)4v^44B6N+;JP` zL^3C?e*DhEaUbJs@cK|QhIIO#@nU#PG%}DQv)RaW^(CaA+<}`9K|(!Q?BkP;02CZ( zcDa650us{pnh!z@?!;d;RN?0(?Xx~+j6jUtCmJ2@obecE%*|5D1rc$M0b7XHFe%fe zym~>57fWTW5mOUAvW#1Lx-Y<3`!8m<>ZD92$DgYsMz;oe2L>wI)4?#yDSaZ`}LyHeAYIn)F#{;)A2=V(?Yb z5Y^q`Zt;7chT-25P-}DoE(c3HDmE~bN8h{2r&BEF$qq67{gjDuJp{FC_x*Kn5$bmG zlp~yDfoInuZ;0Q4{RyZf^c{$fEWP?Vdc<4p;=@aIa$L>CZE>g-+e~60!e{-;{o(f| zY#)}K5Pi!3trkbC*}cS2vlj?dz2|b@hJPXkBW^lyEbZ5!D%6$CqbZLiJC`53Jhr0; ztT;s>HFO22rVVGXplYVP@zz}l2}D9~eeANOY$XY9y_;!Am3Bkal6XsnTOLxHw(Ly< z6#Helufti&@TW_buVPdyn5Z95rCEZN0+i_EiKmtC56BN%)29+JWLC@8OWr2j5lAj# z*TabZ>c=7V!#@>oT}Q`KkWKHZ=y9bjZ+4*Wx}K}yn8#$Z-Ry4py}mcb_8T>qY3BzE znvRgy(xao3P9-6?pU&XhKAq|1TOPt<#4?H*PFsI&X_th45co909%EZu-Jgn3=G;ug z$`GEUzYa$yQ<{de2F&Dd#SpcNir(!gGh+$bL;K8>!!G}A`P20I-9pHI660VB=}%8I zHTCnzqSYO)=V;XnqfKTY&UQd z6_n2=6`PTdL^jLKSt7UyH}5|RKsX{%TcG#1Wvcc_+3B%EB_YP#Tc^jQTjzZVU({A9 zHzWa*M!-)EZ>5qOYG!(;>SI|JnoTg@XWwe^$eIhU=L+)Q!;mo-OG9oqN5A18m;5D+aRiJ&P8#!EN*w5%TwTn3y&GEgF^XyDZeC; z`clOtTrXKrES3*Y>AioWhBvIZco8)|g`ESFp&z&Ll_zz#t`#qfRhdIjwsYozJ$Y^{ zAwE#t?9u{O*8JGSr0)~-HRcgS&^0^JYwVGpaTi0ris(zP#JtKCWIs(L4c2e;(&fP| z2R?S1_zcr|c=9k*fO1EtolCs=;Eq~XB*g(8_G{GQF$Ty!bYN_c?;bbVlRtnZFuk=T zxmgixOfGOn-7ggrPCKKrOuUkP{73W$YnvBqPMo}?dpX-HP6~OaCP`%8X*b2=e6gi8 zjc_jdxB9X5FlX?|d6sfob6AdleJ4Sb$Ks)isBQ&+>WdVCaM8YU z-t85m5XoYHHiyt5Pu<1HqUL<@Ihq40Un~Qi50i0zpGGs`?oAf9iT(I7$G5Tt9N~|> zoF@x&Lk$lH*qF&R$QoGfj;s!9Q|7)h!Ls#qzr(xkfT`@QZ`ksI^Kkz!tQ8+|w~`nx zb?jS0jBWSsc)pA*jMk%NkB5<&%=m^iNvxSpeVA$(`cyVxe|T#UEkF{ssondcZn)!D zo7{%vo`Io~TsgHz z0A7DOa1kMwF9m3u)fW3Yfe8Zl?#w4s{H>_?PsR_DkVM3+(umD$yBL2@vrh{lkIxUsG9IrO3gXefs~@t~YttNhXO1uMxMabsA1qRys)?cJVI9k0ilNd4cco6gB zITO#_^wOwbQt=&b+RvnIlRG*qm^_M}Bt)u>juR~a>gFGLKgXLh-w)6y`T4IEK0c3k zGZN2kE8*R1)<*Fp&B?iJwj1)ADO`iPbzfI1`vvjE5D6X-#$$42&nNq1LUOz#KmV`3 zcx=2xRAe{*3{&SiH@9gSsW@VuFX2jup7z44k@B2JzF3|UR>pG)TJSf)#!3ZNgt(;r z%bn{@Y2(~Xeabg+PY!&zmT9c2Zu$jpuh}5%Jh>t><=z2w z00>_VFC^Dwkg^0OVtS!{{O1`DKBN|Ezb%d#`>!}gy)J+vPhfp}1a^$LLmL;h0K)g6 zrajTz^H;+T@1q(O?T93>5ze~lvxfYZS$F1cvPKdU)J0hxuk?@mSO9T(r^r7!;ZpWj z^QqH9tp7R9d5yO*p@;};CEjcjz5I=hFmGccnCf`t0}dgNaO8NBB)z(TnWIa}bY*Dy zlslT7aX;Pral_UJB#m!?3E>JwNmW!24<>Td+*|ogr{~`jkF}kCIP=g%zb)9c?pve(MTSrBonh0TwqhEL~5&NW| zPiSVTWGL*rt6R<0$u5@i(H8rNM?9oOY2Ex*7B%rA;<#Yge3|jQQI5n? z8KMEoys|^x|Jqh3u ze{em;J2BVEmXD0Ybh1yR(XSufZXL?c9+GyJ28->Tf2s@Xda9pHbHj_l)ngSgcaqCBE{Pp%H2S9aa zNnV7n^O#%Z*AxYIO?dV2b8EdJw)Cs%46TUfUgoARZQL&A@cM3e=p_~eL83}9+>NTk{cm| ckw3~F(Ir!tZY{vG`R~$D&qTLG$2sQz0SBHAdjJ3c literal 0 HcmV?d00001 diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx new file mode 100644 index 0000000..c96e012 --- /dev/null +++ b/src/renderer/src/App.tsx @@ -0,0 +1,65 @@ +import { ScrollArea } from '@renderer/components/ui/scroll-area' +import { Sidebar } from '@renderer/components/ui/sidebar' +import { Toaster } from '@renderer/components/ui/sonner' +import { TitleBar } from '@renderer/components/ui/title-bar' +import { ThemeProvider } from 'next-themes' +import { useState } from 'react' +import { About } from './pages/About' +import { Home } from './pages/Home' +import { Settings } from './pages/Settings' +import { SupportedSites } from './pages/SupportedSites' + +type Page = 'home' | 'settings' | 'about' | 'sites' + +function AppContent() { + const [currentPage, setCurrentPage] = useState('home') + + const renderPage = () => { + switch (currentPage) { + case 'home': + return setCurrentPage('sites')} /> + case 'settings': + return + case 'about': + return + case 'sites': + return + default: + return setCurrentPage('sites')} /> + } + } + + return ( +
+ {/* Sidebar Navigation */} + + + {/* Main Content */} +
+ {/* Custom Title Bar */} + + + +
+ {renderPage()} +
+
+
+ + +
+ ) +} + +function App() { + return ( + + + + ) +} + +export default App diff --git a/src/renderer/src/assets/app-icon.png b/src/renderer/src/assets/app-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6d03b62e74457b56db6ef87883b4b04a419f65ee GIT binary patch literal 14607 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 literal 0 HcmV?d00001 diff --git a/src/renderer/src/assets/global.css b/src/renderer/src/assets/global.css new file mode 100644 index 0000000..b8840ac --- /dev/null +++ b/src/renderer/src/assets/global.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; +@import './theme.css'; + +@layer base { + * { + @apply border-border; + } + body { + @apply text-foreground; + } +} + diff --git a/src/renderer/src/assets/main.css b/src/renderer/src/assets/main.css new file mode 100644 index 0000000..03a5bd1 --- /dev/null +++ b/src/renderer/src/assets/main.css @@ -0,0 +1,23 @@ +body { + margin: 0; + padding: 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; +} + +* { + box-sizing: border-box; +} + +#root { + width: 100vw; + height: 100vh; + overflow: hidden; +} + diff --git a/src/renderer/src/assets/theme.css b/src/renderer/src/assets/theme.css new file mode 100644 index 0000000..6c10f4c --- /dev/null +++ b/src/renderer/src/assets/theme.css @@ -0,0 +1,160 @@ +:root { + --background: oklch(1.0000 0 0); + --foreground: oklch(0.1884 0.0128 248.5103); + --card: oklch(0.9881 0 0); + --card-foreground: oklch(0.1884 0.0128 248.5103); + --popover: oklch(1.0000 0 0); + --popover-foreground: oklch(0.1884 0.0128 248.5103); + --primary: oklch(0.8223 0.1704 79.8747); + --primary-foreground: oklch(1.0000 0 0); + --secondary: oklch(0.1884 0.0128 248.5103); + --secondary-foreground: oklch(1.0000 0 0); + --muted: oklch(0.9227 0.0011 17.1793); + --muted-foreground: oklch(0.1884 0.0128 248.5103); + --accent: oklch(0.9485 0.0162 64.6689); + --accent-foreground: oklch(0.8223 0.1704 79.8747); + --destructive: oklch(0.6188 0.2376 25.7658); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.8929 0.0133 82.4013); + --input: oklch(0.9823 0.0029 84.5589); + --ring: oklch(0.8223 0.1704 79.8747); + --chart-1: oklch(0.6723 0.1606 244.9955); + --chart-2: oklch(0.6907 0.1554 160.3454); + --chart-3: oklch(0.8214 0.1600 82.5337); + --chart-4: oklch(0.7064 0.1822 151.7125); + --chart-5: oklch(0.5919 0.2186 10.5826); + --sidebar: oklch(0.9784 0.0011 197.1387); + --sidebar-foreground: oklch(0.1884 0.0128 248.5103); + --sidebar-primary: oklch(0.8223 0.1704 79.8747); + --sidebar-primary-foreground: oklch(1.0000 0 0); + --sidebar-accent: oklch(0.9485 0.0162 64.6689); + --sidebar-accent-foreground: oklch(0.8223 0.1704 79.8747); + --sidebar-border: oklch(0.9330 0.0108 76.5962); + --sidebar-ring: oklch(0.8223 0.1704 79.8747); + --font-sans: Open Sans, sans-serif; + --font-serif: Georgia, serif; + --font-mono: Menlo, monospace; + --radius: 1.3rem; + --shadow-x: 0px; + --shadow-y: 2px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 0; + --shadow-color: #1da1f2; + --shadow-2xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-sm: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-md: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 2px 4px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-lg: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 4px 6px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 8px 10px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-2xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); + --tracking-normal: 0em; + --spacing: 0.25rem; +} + +.dark { + --background: oklch(0 0 0); + --foreground: oklch(0.9328 0.0025 228.7857); + --card: oklch(0.2097 0.0080 274.5332); + --card-foreground: oklch(0.8853 0 0); + --popover: oklch(0 0 0); + --popover-foreground: oklch(0.9328 0.0025 228.7857); + --primary: oklch(0.6692 0.1607 245.0110); + --primary-foreground: oklch(1.0000 0 0); + --secondary: oklch(0.9622 0.0035 219.5331); + --secondary-foreground: oklch(0.1884 0.0128 248.5103); + --muted: oklch(0.2090 0 0); + --muted-foreground: oklch(0.5637 0.0078 247.9662); + --accent: oklch(0.1928 0.0331 242.5459); + --accent-foreground: oklch(0.6692 0.1607 245.0110); + --destructive: oklch(0.6188 0.2376 25.7658); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.2674 0.0047 248.0045); + --input: oklch(0.3020 0.0288 244.8244); + --ring: oklch(0.6818 0.1584 243.3540); + --chart-1: oklch(0.6723 0.1606 244.9955); + --chart-2: oklch(0.6907 0.1554 160.3454); + --chart-3: oklch(0.8214 0.1600 82.5337); + --chart-4: oklch(0.7064 0.1822 151.7125); + --chart-5: oklch(0.5919 0.2186 10.5826); + --sidebar: oklch(0.2097 0.0080 274.5332); + --sidebar-foreground: oklch(0.8853 0 0); + --sidebar-primary: oklch(0.6818 0.1584 243.3540); + --sidebar-primary-foreground: oklch(1.0000 0 0); + --sidebar-accent: oklch(0.1928 0.0331 242.5459); + --sidebar-accent-foreground: oklch(0.6692 0.1607 245.0110); + --sidebar-border: oklch(0.3795 0.0220 240.5943); + --sidebar-ring: oklch(0.6818 0.1584 243.3540); + --font-sans: Open Sans, sans-serif; + --font-serif: Georgia, serif; + --font-mono: Menlo, monospace; + --radius: 1.3rem; + --shadow-x: 0px; + --shadow-y: 2px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 0; + --shadow-color: #1da1f2; + --shadow-2xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-sm: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-md: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 2px 4px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-lg: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 4px 6px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 8px 10px -1px hsl(202.8169 89.1213% 53.1373% / 0.00); + --shadow-2xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); + + --font-sans: var(--font-sans); + --font-mono: var(--font-mono); + --font-serif: var(--font-serif); + + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + + --shadow-2xs: var(--shadow-2xs); + --shadow-xs: var(--shadow-xs); + --shadow-sm: var(--shadow-sm); + --shadow: var(--shadow); + --shadow-md: var(--shadow-md); + --shadow-lg: var(--shadow-lg); + --shadow-xl: var(--shadow-xl); + --shadow-2xl: var(--shadow-2xl); +} diff --git a/src/renderer/src/assets/title-bar.css b/src/renderer/src/assets/title-bar.css new file mode 100644 index 0000000..88b73e0 --- /dev/null +++ b/src/renderer/src/assets/title-bar.css @@ -0,0 +1,10 @@ +/* Title bar drag region styles */ +.drag-region { + -webkit-app-region: drag; + app-region: drag; +} + +.no-drag { + -webkit-app-region: no-drag; + app-region: no-drag; +} diff --git a/src/renderer/src/components/download/DownloadItem.tsx b/src/renderer/src/components/download/DownloadItem.tsx new file mode 100644 index 0000000..53dc593 --- /dev/null +++ b/src/renderer/src/components/download/DownloadItem.tsx @@ -0,0 +1,418 @@ +import { Badge } from '@renderer/components/ui/badge' +import { Button } from '@renderer/components/ui/button' +import { ImageWithPlaceholder } from '@renderer/components/ui/image-with-placeholder' +import { Progress } from '@renderer/components/ui/progress' +import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip' +import { useSetAtom } from 'jotai' +import { + AlertCircle, + CheckCircle2, + ExternalLink, + FolderOpen, + Loader2, + Play, + Trash2, + X +} from 'lucide-react' +import { useTranslation } from 'react-i18next' +import { toast } from 'sonner' +import { useCachedThumbnail } from '../../hooks/use-cached-thumbnail' +import { ipcServices } from '../../lib/ipc' +import { + type DownloadRecord, + removeDownloadAtom, + removeHistoryRecordAtom +} from '../../store/downloads' + +interface DownloadItemProps { + download: DownloadRecord +} + +const formatFileSize = (bytes?: number) => { + if (!bytes) return '' + const sizes = ['B', 'KB', 'MB', 'GB'] + const order = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), sizes.length - 1) + return `${(bytes / 1024 ** order).toFixed(1)} ${sizes[order]}` +} + +const formatDuration = (seconds?: number) => { + if (!seconds) return '' + const h = Math.floor(seconds / 3600) + const m = Math.floor((seconds % 3600) / 60) + const s = Math.floor(seconds % 60) + if (h > 0) { + return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}` + } + return `${m}:${s.toString().padStart(2, '0')}` +} + +const formatDate = (timestamp?: number) => { + if (!timestamp) return '' + return new Date(timestamp).toLocaleString() +} + +export function DownloadItem({ download }: DownloadItemProps) { + const { t } = useTranslation() + const removeDownload = useSetAtom(removeDownloadAtom) + const removeHistory = useSetAtom(removeHistoryRecordAtom) + const isHistory = download.entryType === 'history' + const timestamp = download.completedAt ?? download.downloadedAt ?? download.createdAt + const thumbnailSrc = useCachedThumbnail(download.thumbnail) + const showActionsWithoutHover = isHistory || download.status === 'completed' + const actionsContainerBaseClass = + 'flex shrink-0 flex-wrap items-center justify-end gap-1 text-muted-foreground opacity-100 transition-opacity' + const actionsContainerClass = showActionsWithoutHover + ? actionsContainerBaseClass + : `${actionsContainerBaseClass} sm:opacity-0 sm:group-hover:opacity-100` + + const handleCancel = async () => { + if (isHistory) return + try { + await ipcServices.download.cancelDownload(download.id) + removeDownload(download.id) + } catch (error) { + console.error('Failed to cancel download:', error) + } + } + + const handleOpenFileLocation = async () => { + if (!download.outputPath) { + toast.error(t('notifications.openFolderFailed')) + return + } + + try { + const success = await ipcServices.fs.openFileLocation(download.outputPath) + if (!success) { + toast.error(t('notifications.openFolderFailed')) + } + } catch (error) { + console.error('Failed to open file location:', error) + toast.error(t('notifications.openFolderFailed')) + } + } + + const handleOpenFile = async () => { + if (!download.outputPath) { + toast.error(t('notifications.openFileFailed')) + return + } + + try { + await ipcServices.fs.openFileLocation(download.outputPath) + } catch (error) { + console.error('Failed to open file:', error) + toast.error(t('notifications.openFileFailed')) + } + } + + const handleOpenFolder = async () => { + await handleOpenFileLocation() + } + + const handleRemoveHistory = async () => { + if (!isHistory) return + try { + await ipcServices.history.removeHistoryItem(download.id, download.outputPath) + removeHistory(download.id) + toast.success(t('notifications.itemRemoved')) + } catch (error) { + console.error('Failed to remove item:', error) + toast.error(t('notifications.removeFailed')) + } + } + + const getStatusIcon = () => { + switch (download.status) { + case 'completed': + return + case 'error': + return + case 'downloading': + case 'processing': + return + case 'pending': + return + case 'cancelled': + return + default: + return null + } + } + + const getStatusText = () => { + switch (download.status) { + case 'completed': + return t('download.completed') + case 'error': + return t('download.error') + case 'downloading': + return t('download.downloading') + case 'processing': + return t('download.processing') + case 'pending': + return t('download.downloadPending') + case 'cancelled': + return t('download.cancelled') + default: + return '' + } + } + + const statusIcon = getStatusIcon() + const statusText = getStatusText() + + return ( +
+ ) +} diff --git a/src/renderer/src/components/download/UnifiedDownloadHistory.tsx b/src/renderer/src/components/download/UnifiedDownloadHistory.tsx new file mode 100644 index 0000000..4749550 --- /dev/null +++ b/src/renderer/src/components/download/UnifiedDownloadHistory.tsx @@ -0,0 +1,114 @@ +import { Button } from '@renderer/components/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@renderer/components/ui/card' +import { useAtomValue, useSetAtom } from 'jotai' +import { History as HistoryIcon } from 'lucide-react' +import { useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useHistorySync } from '../../hooks/use-history-sync' +import { clearCompletedAtom, downloadStatsAtom, downloadsArrayAtom } from '../../store/downloads' +import { DownloadItem } from './DownloadItem' + +type StatusFilter = 'all' | 'active' | 'completed' | 'error' + +export function UnifiedDownloadHistory() { + const { t } = useTranslation() + const allRecords = useAtomValue(downloadsArrayAtom) + const downloadStats = useAtomValue(downloadStatsAtom) + const clearCompleted = useSetAtom(clearCompletedAtom) + const [statusFilter, setStatusFilter] = useState('all') + + useHistorySync() + + const filteredRecords = useMemo(() => { + return allRecords.filter((record) => { + switch (statusFilter) { + case 'all': + return true + case 'active': + return ( + record.status === 'downloading' || + record.status === 'processing' || + record.status === 'pending' + ) + case 'completed': + case 'error': + return record.status === statusFilter + default: + return true + } + }) + }, [allRecords, statusFilter]) + + const filters: Array<{ key: StatusFilter; label: string; count: number }> = [ + { key: 'all', label: t('download.all'), count: downloadStats.total }, + { key: 'active', label: t('download.active'), count: downloadStats.active }, + { key: 'completed', label: t('download.completed'), count: downloadStats.completed }, + { key: 'error', label: t('download.error'), count: downloadStats.error } + ] + + const hasCompletedActive = allRecords.some( + (item) => item.entryType === 'active' && item.status === 'completed' + ) + const handleClearCompleted = () => { + clearCompleted() + } + + return ( + + +
+
+ {t('download.downloadQueue')} +
+
+ {hasCompletedActive && ( + + )} +
+
+
+ {filters.map((filter) => { + const isActive = statusFilter === filter.key + return ( + + ) + })} +
+
+ + {filteredRecords.length === 0 ? ( +
+ +

{t('download.noItems')}

+
+ ) : ( +
+ {filteredRecords.map((record) => ( + + ))} +
+ )} +
+
+ ) +} diff --git a/src/renderer/src/components/ui/accordion.tsx b/src/renderer/src/components/ui/accordion.tsx new file mode 100644 index 0000000..7a6fdf2 --- /dev/null +++ b/src/renderer/src/components/ui/accordion.tsx @@ -0,0 +1,61 @@ +import * as AccordionPrimitive from '@radix-ui/react-accordion' +import { cn } from '@renderer/lib/utils' +import { ChevronDownIcon } from 'lucide-react' +import type * as React from 'react' + +function Accordion({ ...props }: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180', + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/src/renderer/src/components/ui/badge.tsx b/src/renderer/src/components/ui/badge.tsx new file mode 100644 index 0000000..e65dc20 --- /dev/null +++ b/src/renderer/src/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import { Slot } from '@radix-ui/react-slot' +import { cn } from '@renderer/lib/utils' +import { cva, type VariantProps } from 'class-variance-authority' +import type * as React from 'react' + +const badgeVariants = cva( + 'inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden', + { + variants: { + variant: { + default: 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90', + secondary: + 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90', + destructive: + 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground' + } + }, + defaultVariants: { + variant: 'default' + } + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<'span'> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : 'span' + + return +} + +export { Badge, badgeVariants } diff --git a/src/renderer/src/components/ui/button.tsx b/src/renderer/src/components/ui/button.tsx new file mode 100644 index 0000000..29c9884 --- /dev/null +++ b/src/renderer/src/components/ui/button.tsx @@ -0,0 +1,48 @@ +import { Slot } from '@radix-ui/react-slot' +import { cn } from '@renderer/lib/utils' +import { cva, type VariantProps } from 'class-variance-authority' +import * as React from 'react' + +const buttonVariants = cva( + 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90', + destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', + outline: 'border bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline' + }, + size: { + default: 'h-9 px-4 py-2', + sm: 'h-8 rounded-md px-3 text-xs', + lg: 'h-10 rounded-md px-8', + icon: 'h-9 w-9' + } + }, + defaultVariants: { + variant: 'default', + size: 'default' + } + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button' + return ( + + ) + } +) +Button.displayName = 'Button' + +export { Button, buttonVariants } diff --git a/src/renderer/src/components/ui/card.tsx b/src/renderer/src/components/ui/card.tsx new file mode 100644 index 0000000..759defb --- /dev/null +++ b/src/renderer/src/components/ui/card.tsx @@ -0,0 +1,54 @@ +import { cn } from '@renderer/lib/utils' +import * as React from 'react' + +const Card = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +) +Card.displayName = 'Card' + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +) +CardHeader.displayName = 'CardHeader' + +const CardTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +) +CardTitle.displayName = 'CardTitle' + +const CardDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +) +CardDescription.displayName = 'CardDescription' + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +) +CardContent.displayName = 'CardContent' + +const CardFooter = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +) +CardFooter.displayName = 'CardFooter' + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/renderer/src/components/ui/checkbox.tsx b/src/renderer/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..1ca6867 --- /dev/null +++ b/src/renderer/src/components/ui/checkbox.tsx @@ -0,0 +1,26 @@ +import * as CheckboxPrimitive from '@radix-ui/react-checkbox' +import { cn } from '@renderer/lib/utils' +import { CheckIcon } from 'lucide-react' +import type * as React from 'react' + +function Checkbox({ className, ...props }: React.ComponentProps) { + return ( + + + + + + ) +} + +export { Checkbox } diff --git a/src/renderer/src/components/ui/dialog.tsx b/src/renderer/src/components/ui/dialog.tsx new file mode 100644 index 0000000..71d9761 --- /dev/null +++ b/src/renderer/src/components/ui/dialog.tsx @@ -0,0 +1,101 @@ +import * as DialogPrimitive from '@radix-ui/react-dialog' +import { cn } from '@renderer/lib/utils' +import { X } from 'lucide-react' +import * as React from 'react' + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = 'DialogHeader' + +const DialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = 'DialogFooter' + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription +} diff --git a/src/renderer/src/components/ui/dropdown-menu.tsx b/src/renderer/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..76ea62c --- /dev/null +++ b/src/renderer/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,225 @@ +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu' +import { cn } from '@renderer/lib/utils' +import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react' +import type * as React from 'react' + +function DropdownMenu({ ...props }: React.ComponentProps) { + return +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function DropdownMenuGroup({ ...props }: React.ComponentProps) { + return +} + +function DropdownMenuItem({ + className, + inset, + variant = 'default', + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: 'default' | 'destructive' +}) { + return ( + + ) +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) { + return ( + + ) +} + +function DropdownMenuSub({ ...props }: React.ComponentProps) { + return +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent +} diff --git a/src/renderer/src/components/ui/image-with-placeholder.tsx b/src/renderer/src/components/ui/image-with-placeholder.tsx new file mode 100644 index 0000000..33dc655 --- /dev/null +++ b/src/renderer/src/components/ui/image-with-placeholder.tsx @@ -0,0 +1,67 @@ +import { cn } from '@renderer/lib/utils' +import { ImageIcon } from 'lucide-react' +import { useState } from 'react' + +interface ImageWithPlaceholderProps { + src?: string + alt: string + className?: string + placeholderClassName?: string + fallbackIcon?: React.ReactNode + onError?: () => void +} + +export function ImageWithPlaceholder({ + src, + alt, + className, + placeholderClassName, + fallbackIcon, + onError +}: ImageWithPlaceholderProps) { + const [hasError, setHasError] = useState(false) + const [isLoading, setIsLoading] = useState(true) + + const handleError = () => { + setHasError(true) + setIsLoading(false) + onError?.() + } + + const handleLoad = () => { + setIsLoading(false) + } + + // Show placeholder if no src, error occurred, or still loading + if (!src || hasError) { + return ( +
+ {fallbackIcon || } +
+ ) + } + + return ( +
+ {isLoading && ( +
+ {fallbackIcon || } +
+ )} + {alt} +
+ ) +} diff --git a/src/renderer/src/components/ui/input.tsx b/src/renderer/src/components/ui/input.tsx new file mode 100644 index 0000000..e8930d0 --- /dev/null +++ b/src/renderer/src/components/ui/input.tsx @@ -0,0 +1,21 @@ +import { cn } from '@renderer/lib/utils' +import * as React from 'react' + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = 'Input' + +export { Input } diff --git a/src/renderer/src/components/ui/item.tsx b/src/renderer/src/components/ui/item.tsx new file mode 100644 index 0000000..8a733ae --- /dev/null +++ b/src/renderer/src/components/ui/item.tsx @@ -0,0 +1,182 @@ +import { Slot } from '@radix-ui/react-slot' +import { Separator } from '@renderer/components/ui/separator' +import { cn } from '@renderer/lib/utils' +import { cva, type VariantProps } from 'class-variance-authority' +import type * as React from 'react' + +function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +function ItemSeparator({ className, ...props }: React.ComponentProps) { + return ( +
+ +
+ ) +} + +const itemVariants = cva( + 'group/item flex items-center border border-transparent text-sm transition-colors [a]:hover:bg-accent/50 [a]:transition-colors duration-100 flex-wrap outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]', + { + variants: { + variant: { + default: 'bg-transparent', + outline: 'border-border', + muted: 'bg-muted/40' + }, + size: { + default: 'p-4 gap-4 ', + sm: 'py-3 px-4 gap-2.5' + }, + rounded: { + default: 'rounded-none', + none: 'rounded-none', + top: 'rounded-t-md', + bottom: 'rounded-b-md', + both: 'rounded-md' + } + }, + defaultVariants: { + variant: 'default', + size: 'default', + rounded: 'default' + } + } +) + +function Item({ + className, + variant = 'default', + size = 'default', + rounded = 'default', + asChild = false, + ...props +}: React.ComponentProps<'div'> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : 'div' + return ( + + ) +} + +const itemMediaVariants = cva( + 'flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none group-has-[[data-slot=item-description]]/item:translate-y-0.5', + { + variants: { + variant: { + default: 'bg-transparent', + icon: "size-8 border rounded-sm bg-muted [&_svg:not([class*='size-'])]:size-4", + image: 'size-10 rounded-sm overflow-hidden [&_img]:size-full [&_img]:object-cover' + } + }, + defaultVariants: { + variant: 'default' + } + } +) + +function ItemMedia({ + className, + variant = 'default', + ...props +}: React.ComponentProps<'div'> & VariantProps) { + return ( +
+ ) +} + +function ItemContent({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) { + return ( +

a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4', + className + )} + {...props} + /> + ) +} + +function ItemActions({ className, ...props }: React.ComponentProps<'div'>) { + return ( +

+ ) +} + +function ItemHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +function ItemFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +export { + Item, + ItemMedia, + ItemContent, + ItemActions, + ItemGroup, + ItemSeparator, + ItemTitle, + ItemDescription, + ItemHeader, + ItemFooter +} diff --git a/src/renderer/src/components/ui/label.tsx b/src/renderer/src/components/ui/label.tsx new file mode 100644 index 0000000..3ecf37a --- /dev/null +++ b/src/renderer/src/components/ui/label.tsx @@ -0,0 +1,18 @@ +import * as LabelPrimitive from '@radix-ui/react-label' +import { cn } from '@renderer/lib/utils' +import { cva, type VariantProps } from 'class-variance-authority' +import * as React from 'react' + +const labelVariants = cva( + 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70' +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/src/renderer/src/components/ui/progress.tsx b/src/renderer/src/components/ui/progress.tsx new file mode 100644 index 0000000..60a29fa --- /dev/null +++ b/src/renderer/src/components/ui/progress.tsx @@ -0,0 +1,25 @@ +import * as ProgressPrimitive from '@radix-ui/react-progress' +import { cn } from '@renderer/lib/utils' +import type * as React from 'react' + +function Progress({ + className, + value, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { Progress } diff --git a/src/renderer/src/components/ui/scroll-area.tsx b/src/renderer/src/components/ui/scroll-area.tsx new file mode 100644 index 0000000..5bb8080 --- /dev/null +++ b/src/renderer/src/components/ui/scroll-area.tsx @@ -0,0 +1,53 @@ +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area' +import { cn } from '@renderer/lib/utils' +import type * as React from 'react' + +function ScrollArea({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + {children} + + + + + ) +} + +function ScrollBar({ + className, + orientation = 'vertical', + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { ScrollArea, ScrollBar } diff --git a/src/renderer/src/components/ui/select.tsx b/src/renderer/src/components/ui/select.tsx new file mode 100644 index 0000000..f8e2824 --- /dev/null +++ b/src/renderer/src/components/ui/select.tsx @@ -0,0 +1,149 @@ +import * as SelectPrimitive from '@radix-ui/react-select' +import { cn } from '@renderer/lib/utils' +import { Check, ChevronDown, ChevronUp } from 'lucide-react' +import * as React from 'react' + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1', + className + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = 'popper', ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton +} diff --git a/src/renderer/src/components/ui/separator.tsx b/src/renderer/src/components/ui/separator.tsx new file mode 100644 index 0000000..2a7d926 --- /dev/null +++ b/src/renderer/src/components/ui/separator.tsx @@ -0,0 +1,25 @@ +import * as SeparatorPrimitive from '@radix-ui/react-separator' +import { cn } from '@renderer/lib/utils' +import type * as React from 'react' + +function Separator({ + className, + orientation = 'horizontal', + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Separator } diff --git a/src/renderer/src/components/ui/sidebar.tsx b/src/renderer/src/components/ui/sidebar.tsx new file mode 100644 index 0000000..3010e59 --- /dev/null +++ b/src/renderer/src/components/ui/sidebar.tsx @@ -0,0 +1,207 @@ +import { Button } from '@renderer/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from '@renderer/components/ui/dropdown-menu' +import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip' +import { saveSettingAtom } from '@renderer/store/settings' +import { useSetAtom } from 'jotai' +import { useTranslation } from 'react-i18next' +import { toast } from 'sonner' +import MingcuteCheckCircleFill from '~icons/mingcute/check-circle-fill' +import MingcuteCheckCircleLine from '~icons/mingcute/check-circle-line' +import MingcuteDownload3Fill from '~icons/mingcute/download-3-fill' +import MingcuteDownload3Line from '~icons/mingcute/download-3-line' +import MingcuteGlobeLine from '~icons/mingcute/globe-2-line' +import MingcuteInformationFill from '~icons/mingcute/information-fill' +import MingcuteInformationLine from '~icons/mingcute/information-line' +import MingcuteSettingsFill from '~icons/mingcute/settings-3-fill' +import MingcuteSettingsLine from '~icons/mingcute/settings-3-line' + +type Page = 'home' | 'settings' | 'about' | 'sites' + +interface NavigationItem { + id: Page + icon: { + active: React.ComponentType<{ className?: string }> + inactive: React.ComponentType<{ className?: string }> + } + label: string +} + +interface SidebarProps { + currentPage: Page + onPageChange: (page: Page) => void +} + +export function Sidebar({ currentPage, onPageChange }: SidebarProps) { + const { t, i18n } = useTranslation() + const saveSetting = useSetAtom(saveSettingAtom) + + const languageOptions = [ + { value: 'en', label: 'English' }, + { value: 'zh', label: '中文' } + ] + + const navigationItems: NavigationItem[] = [ + { + id: 'home', + icon: { + active: MingcuteDownload3Fill, + inactive: MingcuteDownload3Line + }, + label: t('menu.download') + }, + { + id: 'sites', + icon: { + active: MingcuteCheckCircleFill, + inactive: MingcuteCheckCircleLine + }, + label: t('menu.supportedSites') + } + ] + + const bottomNavigationItems: NavigationItem[] = [ + { + id: 'settings', + icon: { + active: MingcuteSettingsFill, + inactive: MingcuteSettingsLine + }, + label: t('menu.preferences') + }, + { + id: 'about', + icon: { + active: MingcuteInformationFill, + inactive: MingcuteInformationLine + }, + label: t('menu.about') + } + ] + + const activeLanguageCode = (i18n.language ?? 'en').split('-')[0] + const currentLanguage = + languageOptions.find((option) => option.value === activeLanguageCode) ?? languageOptions[0] + + const handleLanguageChange = async (value: string) => { + if (activeLanguageCode === value) { + return + } + + await saveSetting({ key: 'language', value }) + await i18n.changeLanguage(value) + toast.success(t('notifications.settingsSaved')) + } + + const renderNavigationItem = (item: NavigationItem, showLabel = true) => { + const isActive = currentPage === item.id + const IconComponent = isActive ? item.icon.active : item.icon.inactive + + return ( +
+ + + + + +

{item.label}

+
+
+ {showLabel && ( + + {item.label} + + )} +
+ ) + } + + return ( + + ) +} diff --git a/src/renderer/src/components/ui/sonner.tsx b/src/renderer/src/components/ui/sonner.tsx new file mode 100644 index 0000000..99c44e4 --- /dev/null +++ b/src/renderer/src/components/ui/sonner.tsx @@ -0,0 +1,27 @@ +import { useTheme } from 'next-themes' +import { Toaster as Sonner } from 'sonner' + +type ToasterProps = React.ComponentProps + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = 'system' } = useTheme() + + return ( + + ) +} + +export { Toaster } diff --git a/src/renderer/src/components/ui/switch.tsx b/src/renderer/src/components/ui/switch.tsx new file mode 100644 index 0000000..f1ce3ca --- /dev/null +++ b/src/renderer/src/components/ui/switch.tsx @@ -0,0 +1,26 @@ +import * as SwitchPrimitives from '@radix-ui/react-switch' +import { cn } from '@renderer/lib/utils' +import * as React from 'react' + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +Switch.displayName = SwitchPrimitives.Root.displayName + +export { Switch } diff --git a/src/renderer/src/components/ui/tabs.tsx b/src/renderer/src/components/ui/tabs.tsx new file mode 100644 index 0000000..a87bc3e --- /dev/null +++ b/src/renderer/src/components/ui/tabs.tsx @@ -0,0 +1,53 @@ +'use client' + +import * as TabsPrimitive from '@radix-ui/react-tabs' +import { cn } from '@renderer/lib/utils' +import type * as React from 'react' + +function Tabs({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +function TabsList({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +function TabsTrigger({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/src/renderer/src/components/ui/textarea.tsx b/src/renderer/src/components/ui/textarea.tsx new file mode 100644 index 0000000..1475167 --- /dev/null +++ b/src/renderer/src/components/ui/textarea.tsx @@ -0,0 +1,17 @@ +import { cn } from '@renderer/lib/utils' +import type * as React from 'react' + +function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) { + return ( +
+
+ {/* Thumbnail */} +
+ } + /> +
+ + {/* Content */} +
+
+
+ + +
+

+ {download.title} +

+
+
+ +

{download.title}

+
+
+
+ + {download.type} + + {(statusIcon || statusText) && ( +
+ {statusIcon} + {statusText} +
+ )} +
+
+ {timestamp ? ( + {formatDate(timestamp)} + ) : null} + + + + + + {download.uploader && + download.channel && + download.uploader !== download.channel + ? `${download.uploader} • ${download.channel}` + : download.uploader + ? `${download.uploader}` + : download.channel + ? `${download.channel}` + : ''} + + + +

{download.url}

+
+ + + {download.duration ? {formatDuration(download.duration)} : null} + {download.selectedFormat ? ( + <> + {download.selectedFormat.height ? ( + + {download.selectedFormat.height}p + {download.selectedFormat.fps === 60 ? '60' : ''} + + ) : null} + {download.selectedFormat.ext ? ( + + {download.selectedFormat.ext.toUpperCase()} + + ) : null} + {download.selectedFormat.filesize || download.selectedFormat.filesize_approx ? ( + + {formatFileSize( + download.selectedFormat.filesize || + download.selectedFormat.filesize_approx + )} + + ) : null} + + ) : ( + <> + {download.quality ? ( + + {download.quality} + + ) : null} + {download.format ? ( + + {download.format.toUpperCase()} + + ) : null} + {download.codec ? ( + {download.codec} + ) : null} + + )} +
+
+
+ {isHistory ? ( + <> + {download.outputPath && ( + <> + + + + + +

{t('history.openFile')}

+
+
+ + + + + +

{t('history.openFolder')}

+
+
+ + )} + + + + + +

{t('history.removeItem')}

+
+
+ + ) : ( + <> + {download.status === 'completed' && download.outputPath && ( + <> + + + + + +

{t('history.openFile')}

+
+
+ + + + + +

{t('history.openFolder')}

+
+
+ + )} + {(download.status === 'downloading' || + download.status === 'pending' || + download.status === 'processing') && ( + + )} + + )} +
+
+ + {/* Progress */} + {download.progress && download.status !== 'completed' && download.status !== 'error' && ( +
+ +
+ + {download.progress.percent.toFixed(1)}% + +
+ {download.progress.downloaded && download.progress.total && ( + + {download.progress.downloaded} / {download.progress.total} + + )} + {download.progress.currentSpeed && ( + {download.progress.currentSpeed} + )} + {download.progress.eta && ( + ETA: {download.progress.eta} + )} +
+
+
+ )} + + {/* Error message */} + {download.status === 'error' && download.error && ( +

+ {download.error} +

+ )} +
+
+