diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index aeadee7..1a2180a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,35 +1,46 @@ -name: Deploy to vercel -on: - push: - branches: - - main - workflow_dispatch: jobs: build_and_deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v1 - - uses: dkershner6/vercel-set-env-action@v3 + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 with: - token: ${{ secrets.VERCEL_TOKEN }} - projectName: builder-dashboard - envVariableKeys: COOKIE_SECRET,NEXT_PUBLIC_TURNSTILE_SITE_KEY,TURNSTILE_SECRET_KEY - env: + bun-version: latest + + - env: COOKIE_SECRET: ${{ secrets.COOKIE_SECRET }} - TARGET_COOKIE_SECRET: preview,development,production - TYPE_COOKIE_SECRET: encrypted NEXT_PUBLIC_TURNSTILE_SITE_KEY: ${{ secrets.NEXT_PUBLIC_TURNSTILE_SITE_KEY }} + TARGET_COOKIE_SECRET: preview,development,production TARGET_NEXT_PUBLIC_TURNSTILE_SITE_KEY: production - TYPE_NEXT_PUBLIC_TURNSTILE_SITE_KEY: plain - TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }} TARGET_TURNSTILE_SECRET_KEY: production + TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }} + TYPE_COOKIE_SECRET: encrypted + TYPE_NEXT_PUBLIC_TURNSTILE_SITE_KEY: plain TYPE_TURNSTILE_SECRET_KEY: encrypted - - uses: amondnet/vercel-action@v25 + name: Set Environment Variables for Vercel + uses: dkershner6/vercel-set-env-action@v3 + with: + envVariableKeys: COOKIE_SECRET,NEXT_PUBLIC_TURNSTILE_SITE_KEY,TURNSTILE_SECRET_KEY + projectName: builder-dashboard + token: ${{ secrets.VERCEL_TOKEN }} + + - name: Deploy to Vercel + uses: amondnet/vercel-action@v25 with: - vercel-token: ${{ secrets.VERCEL_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }} vercel-args: '--prod' vercel-org-id: ${{ secrets.ORG_ID }} vercel-project-id: ${{ secrets.PROJECT_ID }} vercel-project-name: builder-dashboard + vercel-token: ${{ secrets.VERCEL_TOKEN }} + +name: Deploy to vercel + +on: + push: + branches: + - main + workflow_dispatch: diff --git a/CachyOS Builder Dashboard.code-workspace b/CachyOS Builder Dashboard.code-workspace index 57528c5..8c10905 100644 --- a/CachyOS Builder Dashboard.code-workspace +++ b/CachyOS Builder Dashboard.code-workspace @@ -8,16 +8,23 @@ "cSpell.words": [ "Cachy", "cachyos", + "cmdk", "headlessui", "marsidev", + "nums", "pkgbase", "pkgname", "QPKG", "remixicon", "rxdb", + "scrollback", + "sonner", + "tabler", "toastify", "Upsert", - "webgl" + "vercel", + "webgl", + "ZNVER" ] } } diff --git a/README.md b/README.md index c403366..e215bc4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). ## Getting Started @@ -18,7 +18,7 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. ## Learn More @@ -27,10 +27,10 @@ To learn more about Next.js, take a look at the following resources: - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! ## Deploy on Vercel The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/app/actions.ts b/app/actions.ts deleted file mode 100644 index 92631c5..0000000 --- a/app/actions.ts +++ /dev/null @@ -1,297 +0,0 @@ -'use server'; - -import fetcher from '@/lib/fetcher'; -import servers from '@/lib/servers'; -import {SessionData, defaultSession, sessionOptions} from '@/lib/session'; -import {AuditLogEntry} from '@/types/AuditLog'; -import { - BaseBuilderPackage, - BuilderPackage, - BuilderPackageArchitecture, - BuilderPackageRepository, - BuilderRebuildPackage, -} from '@/types/BuilderPackage'; -import {getIronSession} from 'iron-session'; -import {cookies, headers} from 'next/headers'; -import {redirect} from 'next/navigation'; -import stripAnsi from 'strip-ansi'; -import {isURL} from 'validator'; - -export async function getSession() { - const session = await getIronSession(cookies(), sessionOptions); - if (!session.isLoggedIn) { - session.isLoggedIn = defaultSession.isLoggedIn; - session.token = defaultSession.token; - session.createdAt = Date.now(); - session.server = defaultSession.server; - } - return session; -} - -export async function logout() { - const session = await getSession(); - session.destroy(); - return redirect('/'); -} - -export async function login(_: unknown, formData: FormData) { - const session = await getSession(); - const token = formData.get('cf-turnstile-response')?.toString() ?? ''; - const username = formData.get('username')?.toString().trim() ?? ''; - const password = formData.get('password')?.toString() ?? ''; - const redirectTo = formData.get('redirect')?.toString() ?? ''; - const server = formData.get('server')?.toString() ?? defaultSession.server; - - if (!token) { - return { - errorCredentials: 'CF Turnstile verification failed. Please try again.', - errorPassword: '', - errorUsername: '', - }; - } - - if (!servers.find(s => s.url === server)) { - return { - errorCredentials: 'Invalid server.', - errorPassword: '', - errorUsername: '', - }; - } - - if (!username || !password) { - return { - errorCredentials: 'Missing username or password.', - errorPassword: 'Password is required.', - errorUsername: 'Username is required.', - }; - } - - const turnstileResponse = await fetch( - 'https://challenges.cloudflare.com/turnstile/v0/siteverify', - { - body: `secret=${encodeURIComponent(process.env.TURNSTILE_SECRET_KEY!)}&response=${encodeURIComponent(token)}`, - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - } - ) - .then(res => res.json()) - .then(res => res.success) - .catch(() => false); - if (!turnstileResponse) { - return { - errorCredentials: 'CF Turnstile verification failed. Please try again.', - errorPassword: '', - errorUsername: '', - }; - } - - const res = await fetcher<{token: string}>( - '/v1/login', - '', - headers(), - { - body: JSON.stringify({ - password, - username, - }), - method: 'POST', - }, - server - ).catch(() => {}); - if (!res?.token) { - return { - errorCredentials: 'Invalid username or password.', - errorPassword: '', - errorUsername: '', - }; - } - session.isLoggedIn = true; - session.token = res.token; - session.createdAt = Date.now(); - session.username = username; - session.server = server; - await session.save(); - if (redirectTo?.startsWith('/')) { - return redirect(redirectTo); - } - return redirect('/dashboard'); -} - -export async function getUsername() { - const session = await getSession(); - if (!session.isLoggedIn) { - return redirect('/'); - } - return session.username; -} - -export async function getServerDetails() { - const session = await getSession(); - if (!session.isLoggedIn) { - return redirect('/'); - } - return servers.find(s => s.url === session.server)!; -} - -export async function getPackages() { - const session = await getSession(); - if (!session.isLoggedIn) { - return redirect('/'); - } - return fetcher( - '/v1/packages', - session.token, - headers(), - {}, - session.server - ).catch(() => []); -} - -export async function getRebuildPackages() { - const session = await getSession(); - if (!session.isLoggedIn) { - return redirect('/'); - } - return fetcher( - '/v1/rebuild-status', - session.token, - headers(), - {}, - session.server - ).catch(() => []); -} - -export async function getPackageLog( - pkg: string, - march: BuilderPackageArchitecture, - strip = false, - redirectTo?: string -) { - const session = await getSession(); - if (!session.isLoggedIn) { - if (redirectTo?.startsWith('/')) { - return redirect(`/?redirect=${encodeURIComponent(redirectTo)}`); - } - return redirect('/'); - } - return fetcher( - `/v1/logs/${march}/${pkg}.log`, - session.token, - headers(), - { - method: 'GET', - }, - session.server, - 'text' - ) - .then(text => (strip ? stripAnsi(text) : text)) - .catch(() => ''); -} - -export async function addPackage(_: unknown, formData: FormData) { - const session = await getSession(); - const pkgURL = formData.get('pkgURL')?.toString().trim() ?? ''; - if (!pkgURL || !isURL(pkgURL)) { - return { - errorPkgURL: 'Invalid package URL.', - success: false, - }; - } - const res = await fetcher<{success: boolean}>( - '/v1/packages', - session.token, - headers(), - { - body: JSON.stringify({ - url: pkgURL, - }), - method: 'POST', - }, - session.server - ).catch(() => {}); - if (!res?.success) { - return { - errorPkgURL: 'Invalid package URL.', - success: false, - }; - } - return { - errorPkgURL: '', - success: true, - }; -} - -export async function rebuildPackage(_: unknown, formData: FormData) { - const session = await getSession(); - const march = formData.get('march')?.toString().trim() ?? ''; - const repository = formData.get('repository')?.toString().trim() ?? ''; - const pkgbase = formData.get('pkgbase')?.toString().trim() ?? ''; - if ( - !march || - !repository || - !pkgbase || - !Object.values(BuilderPackageArchitecture).includes( - march as BuilderPackageArchitecture - ) || - !Object.values(BuilderPackageRepository).includes( - repository as BuilderPackageRepository - ) - ) { - return redirect('/dashboard'); - } - const res = await fetcher<{track_id: string}>( - `/v1/rebuild/${march}/${repository}/${pkgbase}`, - session.token, - headers(), - { - method: 'PUT', - }, - session.server - ).catch(() => {}); - if (!res?.track_id) { - return { - success: false, - }; - } - return { - success: true, - }; -} - -export async function bulkRebuildPackages(packages: BaseBuilderPackage[]) { - const session = await getSession(); - if (!Array.isArray(packages) || !packages.length) { - return { - success: false, - }; - } - const res = await fetcher( - '/v1/bulk-rebuild', - session.token, - headers(), - { - body: JSON.stringify(packages), - method: 'PUT', - }, - session.server - ).catch(() => []); - return { - success: !!res.length, - }; -} - -export async function getAuditLogs() { - const session = await getSession(); - if (!session.isLoggedIn) { - return redirect('/'); - } - return fetcher( - '/v1/audit-logs', - session.token, - headers(), - {}, - session.server - ).catch(() => []); -} diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx deleted file mode 100644 index efcaa0a..0000000 --- a/app/dashboard/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import AdminShell from '@/components/AdminShell'; -import {redirect} from 'next/navigation'; - -import {getSession} from '../actions'; - -export default async function Dashboard() { - const user = await getSession(); - if (!user.isLoggedIn) { - return redirect('/'); - } - return ; -} diff --git a/app/globals.css b/app/globals.css deleted file mode 100644 index b5c61c9..0000000 --- a/app/globals.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/app/logs/[march]/[pkgbase]/page.tsx b/app/logs/[march]/[pkgbase]/page.tsx deleted file mode 100644 index 2f3211a..0000000 --- a/app/logs/[march]/[pkgbase]/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Loader from '@/components/Loader'; -import {BuilderPackageArchitecture} from '@/types/BuilderPackage'; -import dynamic from 'next/dynamic'; - -const TerminalComponent = dynamic( - () => import('@/components/TerminalComponent'), - { - loading: () => , - ssr: false, - } -); - -export default function LogsPage({ - params, -}: Readonly<{ - params: { - march: BuilderPackageArchitecture; - pkgbase: string; - }; -}>) { - const {march, pkgbase} = params; - if (!march || !pkgbase) { - return ; - } - if (!Object.values(BuilderPackageArchitecture).includes(march)) { - return ( - - ); - } - return ( -
- -
- ); -} diff --git a/app/page.tsx b/app/page.tsx deleted file mode 100644 index 84c1369..0000000 --- a/app/page.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import LoginForm from '@/components/LoginForm'; -import {Card} from '@tremor/react'; - -import {getSession} from './actions'; - -export default async function LoginPage() { - const user = await getSession(); - return ( - - - - ); -} diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..b533c5e --- /dev/null +++ b/bun.lock @@ -0,0 +1,1148 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "cachyos-builder-dashboard", + "dependencies": { + "@hookform/resolvers": "^5.2.0", + "@marsidev/react-turnstile": "1.1.0", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-popover": "^1.1.14", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tooltip": "^1.2.7", + "@tabler/icons-react": "3.34.1", + "@tanstack/react-table": "^8.21.3", + "@xterm/addon-fit": "0.10.0", + "@xterm/addon-search": "0.15.0", + "@xterm/addon-web-links": "0.11.0", + "@xterm/addon-webgl": "0.18.0", + "ansi-styles": "6.2.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "iron-session": "8.0.4", + "lucide-react": "^0.526.0", + "next": "15.4.4", + "next-themes": "^0.4.6", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-hook-form": "7.61.1", + "recharts": "^3.1.0", + "sonner": "^2.0.6", + "strip-ansi": "7.1.0", + "tailwind-merge": "^3.3.1", + "tailwind-variants": "1.0.0", + "use-debounce": "10.0.5", + "zod": "^4.0.10", + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@tailwindcss/postcss": "^4.1.11", + "@types/node": "^24.1.0", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "eslint": "^9.32.0", + "eslint-config-next": "15.4.4", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-perfectionist": "^4.15.0", + "eslint-plugin-prettier": "^5.5.3", + "prettier": "^3.6.2", + "tailwindcss": "^4.1.11", + "tw-animate-css": "^1.3.6", + "typescript": "^5.8.3", + }, + }, + }, + "trustedDependencies": [ + "@tailwindcss/oxide", + "unrs-resolver", + ], + "packages": { + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + + "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], + + "@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" } }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.3.0", "", {}, "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw=="], + + "@eslint/core": ["@eslint/core@0.15.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], + + "@eslint/js": ["@eslint/js@9.32.0", "", {}, "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.4", "", { "dependencies": { "@eslint/core": "^0.15.1", "levn": "^0.4.1" } }, "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw=="], + + "@floating-ui/core": ["@floating-ui/core@1.7.2", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.2", "", { "dependencies": { "@floating-ui/core": "^1.7.2", "@floating-ui/utils": "^0.2.10" } }, "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.4", "", { "dependencies": { "@floating-ui/dom": "^1.7.2" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], + + "@hookform/resolvers": ["@hookform/resolvers@5.2.0", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-3YI+VqxJQH6ryRWG+j3k+M19Wf37LeSKJDg6Vdjq6makLOqZGYn77iTaYLMLpVi/uHc1N6OTCmcxJwhOQV979g=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.0" }, "os": "darwin", "cpu": "x64" }, "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.0" }, "os": "linux", "cpu": "arm" }, "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.0" }, "os": "linux", "cpu": "arm64" }, "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.0" }, "os": "linux", "cpu": "ppc64" }, "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.0" }, "os": "linux", "cpu": "s390x" }, "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.0" }, "os": "linux", "cpu": "x64" }, "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" }, "os": "linux", "cpu": "arm64" }, "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.3", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.0" }, "os": "linux", "cpu": "x64" }, "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.3", "", { "dependencies": { "@emnapi/runtime": "^1.4.4" }, "cpu": "none" }, "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.3", "", { "os": "win32", "cpu": "x64" }, "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g=="], + + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.4", "", {}, "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], + + "@marsidev/react-turnstile": ["@marsidev/react-turnstile@1.1.0", "", { "peerDependencies": { "react": "^17.0.2 || ^18.0.0 || ^19.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0" } }, "sha512-X7bP9ZYutDd+E+klPYF+/BJHqEyyVkN4KKmZcNRr84zs3DcMoftlMAuoKqNSnqg0HE7NQ1844+TLFSJoztCdSA=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], + + "@next/env": ["@next/env@15.4.4", "", {}, "sha512-SJKOOkULKENyHSYXE5+KiFU6itcIb6wSBjgM92meK0HVKpo94dNOLZVdLLuS7/BxImROkGoPsjR4EnuDucqiiA=="], + + "@next/eslint-plugin-next": ["@next/eslint-plugin-next@15.4.4", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-1FDsyN//ai3Jd97SEd7scw5h1yLdzDACGOPRofr2GD3sEFsBylEEoL0MHSerd4n2dq9Zm/mFMqi4+NRMOreOKA=="], + + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.4.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eVG55dnGwfUuG+TtnUCt+mEJ+8TGgul6nHEvdb8HEH7dmJIFYOCApAaFrIrxwtEq2Cdf+0m5sG1Np8cNpw9EAw=="], + + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.4.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zqG+/8apsu49CltEj4NAmCGZvHcZbOOOsNoTVeIXphYWIbE4l6A/vuQHyqll0flU2o3dmYCXsBW5FmbrGDgljQ=="], + + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.4.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-LRD4l2lq4R+2QCHBQVC0wjxxkLlALGJCwigaJ5FSRSqnje+MRKHljQNZgDCaKUZQzO/TXxlmUdkZP/X3KNGZaw=="], + + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.4.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-LsGUCTvuZ0690fFWerA4lnQvjkYg9gHo12A3wiPUR4kCxbx/d+SlwmonuTH2SWZI+RVGA9VL3N0S03WTYv6bYg=="], + + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.4.4", "", { "os": "linux", "cpu": "x64" }, "sha512-aOy5yNRpLL3wNiJVkFYl6w22hdREERNjvegE6vvtix8LHRdsTHhWTpgvcYdCK7AIDCQW5ATmzr9XkPHvSoAnvg=="], + + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.4.4", "", { "os": "linux", "cpu": "x64" }, "sha512-FL7OAn4UkR8hKQRGBmlHiHinzOb07tsfARdGh7v0Z0jEJ3sz8/7L5bR23ble9E6DZMabSStqlATHlSxv1fuzAg=="], + + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.4.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-eEdNW/TXwjYhOulQh0pffTMMItWVwKCQpbziSBmgBNFZIIRn2GTXrhrewevs8wP8KXWYMx8Z+mNU0X+AfvtrRg=="], + + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.4.4", "", { "os": "win32", "cpu": "x64" }, "sha512-SE5pYNbn/xZKMy1RE3pAs+4xD32OI4rY6mzJa4XUkp/ItZY+OMjIgilskmErt8ls/fVJ+Ihopi2QIeW6O3TrMw=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], + + "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], + + "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], + + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], + + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA=="], + + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg=="], + + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], + + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], + + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw=="], + + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], + + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ=="], + + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ=="], + + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA=="], + + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-CPYZ24Mhirm+g6D8jArmLzjYu4Eyg3TTUHswR26QgzXBHBe64BO/RHOJKzmF/Dxb4y4f9PKyJdwm/O/AhNkb+Q=="], + + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], + + "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], + + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.10", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew=="], + + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw=="], + + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="], + + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q=="], + + "@radix-ui/react-select": ["@radix-ui/react-select@2.2.5", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA=="], + + "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ=="], + + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw=="], + + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], + + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], + + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], + + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + + "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], + + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], + + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], + + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], + + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], + + "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + + "@reduxjs/toolkit": ["@reduxjs/toolkit@2.8.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-MYlOhQ0sLdw4ud48FoC5w0dH9VfWQjtCjreKwYTT3l+r427qYC5Y8PihNutepr8XrNaBUDQo9khWUwQxZaqt5A=="], + + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + + "@rushstack/eslint-patch": ["@rushstack/eslint-patch@1.12.0", "", {}, "sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + + "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], + + "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + + "@tabler/icons": ["@tabler/icons@3.34.1", "", {}, "sha512-9gTnUvd7Fd/DmQgr3MKY+oJLa1RfNsQo8c/ir3TJAWghOuZXodbtbVp0QBY2DxWuuvrSZFys0HEbv1CoiI5y6A=="], + + "@tabler/icons-react": ["@tabler/icons-react@3.34.1", "", { "dependencies": { "@tabler/icons": "3.34.1" }, "peerDependencies": { "react": ">= 16" } }, "sha512-Ld6g0NqOO05kyyHsfU8h787PdHBm7cFmOycQSIrGp45XcXYDuOK2Bs0VC4T2FWSKZ6bx5g04imfzazf/nqtk1A=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.1.11", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.11" } }, "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.11", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.11", "@tailwindcss/oxide-darwin-arm64": "4.1.11", "@tailwindcss/oxide-darwin-x64": "4.1.11", "@tailwindcss/oxide-freebsd-x64": "4.1.11", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", "@tailwindcss/oxide-linux-x64-musl": "4.1.11", "@tailwindcss/oxide-wasm32-wasi": "4.1.11", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" } }, "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.11", "", { "os": "android", "cpu": "arm64" }, "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11", "", { "os": "linux", "cpu": "arm" }, "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.11", "", { "os": "linux", "cpu": "x64" }, "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.11", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.11", "", { "os": "win32", "cpu": "x64" }, "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg=="], + + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.11", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "postcss": "^8.4.41", "tailwindcss": "4.1.11" } }, "sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA=="], + + "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="], + + "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="], + + "@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="], + + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + + "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], + + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + + "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], + + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + + "@types/d3-shape": ["@types/d3-shape@3.1.7", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg=="], + + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + + "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], + + "@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="], + + "@types/react-dom": ["@types/react-dom@19.1.6", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw=="], + + "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.38.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/type-utils": "8.38.0", "@typescript-eslint/utils": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.38.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.38.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.38.0", "@typescript-eslint/types": "^8.38.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0" } }, "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.38.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/utils": "8.38.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.38.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.38.0", "@typescript-eslint/tsconfig-utils": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.38.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g=="], + + "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], + + "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="], + + "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g=="], + + "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ=="], + + "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.11.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw=="], + + "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw=="], + + "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw=="], + + "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ=="], + + "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w=="], + + "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA=="], + + "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ=="], + + "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew=="], + + "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.11.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg=="], + + "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w=="], + + "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA=="], + + "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.11.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ=="], + + "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw=="], + + "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ=="], + + "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], + + "@xterm/addon-fit": ["@xterm/addon-fit@0.10.0", "", { "peerDependencies": { "@xterm/xterm": "^5.0.0" } }, "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ=="], + + "@xterm/addon-search": ["@xterm/addon-search@0.15.0", "", { "peerDependencies": { "@xterm/xterm": "^5.0.0" } }, "sha512-ZBZKLQ+EuKE83CqCmSSz5y1tx+aNOCUaA7dm6emgOX+8J9H1FWXZyrKfzjwzV+V14TV3xToz1goIeRhXBS5qjg=="], + + "@xterm/addon-web-links": ["@xterm/addon-web-links@0.11.0", "", { "peerDependencies": { "@xterm/xterm": "^5.0.0" } }, "sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q=="], + + "@xterm/addon-webgl": ["@xterm/addon-webgl@0.18.0", "", { "peerDependencies": { "@xterm/xterm": "^5.0.0" } }, "sha512-xCnfMBTI+/HKPdRnSOHaJDRqEpq2Ugy8LEj9GiY4J3zJObo3joylIFaMvzBwbYRg8zLtkO0KQaStCeSfoaI2/w=="], + + "@xterm/xterm": ["@xterm/xterm@5.5.0", "", {}, "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], + + "ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], + + "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], + + "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], + + "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-shim-unscopables": "^1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], + + "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], + + "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], + + "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], + + "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + + "ast-types-flow": ["ast-types-flow@0.0.8", "", {}, "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ=="], + + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "axe-core": ["axe-core@4.10.3", "", {}, "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001727", "", {}, "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="], + + "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + + "d3-format": ["d3-format@3.1.0", "", {}, "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="], + + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + + "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], + + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + + "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], + + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + + "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], + + "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], + + "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], + + "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], + + "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + + "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + + "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], + + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], + + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "enhanced-resolve": ["enhanced-resolve@5.18.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ=="], + + "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], + + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + + "es-toolkit": ["es-toolkit@1.39.8", "", {}, "sha512-A8QO9TfF+rltS8BXpdu8OS+rpGgEdnRhqIVxO/ZmNvnXBYgOdSsxukT55ELyP94gZIntWJ+Li9QRrT2u1Kitpg=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.32.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.32.0", "@eslint/plugin-kit": "^0.3.4", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg=="], + + "eslint-config-next": ["eslint-config-next@15.4.4", "", { "dependencies": { "@next/eslint-plugin-next": "15.4.4", "@rushstack/eslint-patch": "^1.10.3", "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^5.0.0" }, "peerDependencies": { "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-sK/lWLUVF5om18O5w76Jt3F8uzu/LP5mVa6TprCMWkjWHUmByq80iHGHcdH7k1dLiJlj+DRIWf98d5piwRsSuA=="], + + "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], + + "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="], + + "eslint-import-resolver-typescript": ["eslint-import-resolver-typescript@3.10.1", "", { "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "^4.4.0", "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", "tinyglobby": "^0.2.13", "unrs-resolver": "^1.6.2" }, "peerDependencies": { "eslint": "*", "eslint-plugin-import": "*", "eslint-plugin-import-x": "*" }, "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] }, "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ=="], + + "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], + + "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", "array.prototype.findlastindex": "^1.2.6", "array.prototype.flat": "^1.3.3", "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.1", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], + + "eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="], + + "eslint-plugin-perfectionist": ["eslint-plugin-perfectionist@4.15.0", "", { "dependencies": { "@typescript-eslint/types": "^8.34.1", "@typescript-eslint/utils": "^8.34.1", "natural-orderby": "^5.0.0" }, "peerDependencies": { "eslint": ">=8.45.0" } }, "sha512-pC7PgoXyDnEXe14xvRUhBII8A3zRgggKqJFx2a82fjrItDs1BSI7zdZnQtM2yQvcyod6/ujmzb7ejKPx8lZTnw=="], + + "eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.3", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w=="], + + "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], + + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], + + "fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], + + "fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], + + "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], + + "get-intrinsic": ["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" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], + + "get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], + + "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "immer": ["immer@10.1.1", "", {}, "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + + "iron-session": ["iron-session@8.0.4", "", { "dependencies": { "cookie": "^0.7.2", "iron-webcrypto": "^1.2.1", "uncrypto": "^0.1.3" } }, "sha512-9ivNnaKOd08osD0lJ3i6If23GFS2LsxyMU8Gf/uBUEgm8/8CC1hrrCHFDpMo3IFbpBgwoo/eairRsaD3c5itxA=="], + + "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], + + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], + + "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], + + "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], + + "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], + + "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], + + "is-bun-module": ["is-bun-module@2.0.0", "", { "dependencies": { "semver": "^7.7.1" } }, "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], + + "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], + + "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], + + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + + "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], + + "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], + + "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], + + "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], + + "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], + + "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], + + "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], + + "jiti": ["jiti@2.5.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], + + "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="], + + "language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "lucide-react": ["lucide-react@0.526.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-uGWG/2RKuDLeQHCodn5cmJ9Zij80EstOdcBP+j//B2sr78w7woiEL4aMu6CRlRkyOyJ8sZry8QLhQTmZjynLdA=="], + + "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="], + + "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "napi-postinstall": ["napi-postinstall@0.3.2", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "natural-orderby": ["natural-orderby@5.0.0", "", {}, "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg=="], + + "next": ["next@15.4.4", "", { "dependencies": { "@next/env": "15.4.4", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.4.4", "@next/swc-darwin-x64": "15.4.4", "@next/swc-linux-arm64-gnu": "15.4.4", "@next/swc-linux-arm64-musl": "15.4.4", "@next/swc-linux-x64-gnu": "15.4.4", "@next/swc-linux-x64-musl": "15.4.4", "@next/swc-win32-arm64-msvc": "15.4.4", "@next/swc-win32-x64-msvc": "15.4.4", "sharp": "^0.34.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-kNcubvJjOL9yUOfwtZF3HfDhuhp+kVD+FM2A6Tyua1eI/xfmY4r/8ZS913MMz+oWKDlbps/dQOWdDricuIkXLw=="], + + "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], + + "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], + + "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], + + "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], + + "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], + + "prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="], + + "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="], + + "react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="], + + "react-hook-form": ["react-hook-form@7.61.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-2vbXUFDYgqEgM2RcXcAT2PwDW/80QARi+PKmHy5q2KhuKvOlG8iIYgf7eIlIANR5trW9fJbP4r5aub3a4egsew=="], + + "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="], + + "react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + + "recharts": ["recharts@3.1.0", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-NqAqQcGBmLrfDs2mHX/bz8jJCQtG2FeXfE0GqpZmIuXIjkpIwj8sd9ad0WyvKiBKPd8ZgNG0hL85c8sFDwascw=="], + + "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], + + "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], + + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + + "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], + + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], + + "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], + + "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + + "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], + + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], + + "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], + + "sharp": ["sharp@0.34.3", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3", "@img/sharp-darwin-x64": "0.34.3", "@img/sharp-libvips-darwin-arm64": "1.2.0", "@img/sharp-libvips-darwin-x64": "1.2.0", "@img/sharp-libvips-linux-arm": "1.2.0", "@img/sharp-libvips-linux-arm64": "1.2.0", "@img/sharp-libvips-linux-ppc64": "1.2.0", "@img/sharp-libvips-linux-s390x": "1.2.0", "@img/sharp-libvips-linux-x64": "1.2.0", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", "@img/sharp-libvips-linuxmusl-x64": "1.2.0", "@img/sharp-linux-arm": "0.34.3", "@img/sharp-linux-arm64": "0.34.3", "@img/sharp-linux-ppc64": "0.34.3", "@img/sharp-linux-s390x": "0.34.3", "@img/sharp-linux-x64": "0.34.3", "@img/sharp-linuxmusl-arm64": "0.34.3", "@img/sharp-linuxmusl-x64": "0.34.3", "@img/sharp-wasm32": "0.34.3", "@img/sharp-win32-arm64": "0.34.3", "@img/sharp-win32-ia32": "0.34.3", "@img/sharp-win32-x64": "0.34.3" } }, "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="], + + "sonner": ["sonner@2.0.6", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-yHFhk8T/DK3YxjFQXIrcHT1rGEeTLliVzWbO0xN8GberVun2RiBnxAjXAYpZrqwEVHBG9asI/Li8TAAhN9m59Q=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], + + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + + "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], + + "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], + + "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], + + "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], + + "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], + + "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + + "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="], + + "tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="], + + "tailwind-variants": ["tailwind-variants@1.0.0", "", { "dependencies": { "tailwind-merge": "3.0.2" }, "peerDependencies": { "tailwindcss": "*" } }, "sha512-2WSbv4ulEEyuBKomOunut65D8UZwxrHoRfYnxGcQNnHqlSCp2+B7Yz2W+yrNDrxRodOXtGD/1oCcKGNBnUqMqA=="], + + "tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="], + + "tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="], + + "tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], + + "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], + + "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], + + "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tw-animate-css": ["tw-animate-css@1.3.6", "", {}, "sha512-9dy0R9UsYEGmgf26L8UcHiLmSFTHa9+D7+dAt/G/sF5dCnPePZbfgDYinc7/UzAM7g/baVrmS6m9yEpU46d+LA=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + + "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], + + "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], + + "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], + + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + + "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], + + "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], + + "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], + + "use-debounce": ["use-debounce@10.0.5", "", { "peerDependencies": { "react": "*" } }, "sha512-Q76E3lnIV+4YT9AHcrHEHYmAd9LKwUAbPXDm7FlqVGDHiSOhX3RDjT8dm0AxbJup6WgOb1YEcKyCr11kBJR5KQ=="], + + "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + + "use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="], + + "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], + + "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], + + "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], + + "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "zod": ["zod@4.0.10", "", {}, "sha512-3vB+UU3/VmLL2lvwcY/4RV2i9z/YU0DTV/tDuYjrwmx5WeJ7hwy+rGEEx8glHp6Yxw7ibRbKSaIFBgReRPe5KA=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" }, "bundled": true }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.4", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" }, "bundled": true }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "is-bun-module/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + + "sharp/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "tailwind-variants/tailwind-merge": ["tailwind-merge@3.0.2", "", {}, "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="], + + "@typescript-eslint/typescript-estree/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + } +} diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index eeebe17..0000000 Binary files a/bun.lockb and /dev/null differ diff --git a/components.json b/components.json new file mode 100644 index 0000000..ffe928f --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/components/AddPackageModal.tsx b/components/AddPackageModal.tsx deleted file mode 100644 index a1b0be4..0000000 --- a/components/AddPackageModal.tsx +++ /dev/null @@ -1,59 +0,0 @@ -'use client'; - -import {addPackage} from '@/app/actions'; -import {RiLink} from '@remixicon/react'; -import {TextInput} from '@tremor/react'; -import {useEffect} from 'react'; -import {useFormState} from 'react-dom'; -import {toast} from 'react-toastify'; - -import Modal from './Modal'; -import SubmitButton from './SubmitButton'; - -const initialState = { - errorPkgURL: '', - success: false, -}; - -export default function AddPackageModal({ - isOpen, - onClose, -}: Readonly<{ - isOpen: boolean; - onClose: () => void; -}>) { - const [state, formAction] = useFormState(addPackage, initialState); - useEffect(() => { - if (state?.success) { - toast.success('Package added successfully!'); - onClose(); - } - }, [onClose, state?.success]); - return ( - -
-

- Add a new package -

-

- Enter the URL of the package to add it to the CachyOS Builder. -

- - - - -
- ); -} diff --git a/components/AdminShell.tsx b/components/AdminShell.tsx deleted file mode 100644 index 00287ba..0000000 --- a/components/AdminShell.tsx +++ /dev/null @@ -1,182 +0,0 @@ -'use client'; - -import { - getAuditLogs, - getPackages, - getRebuildPackages, - getServerDetails, - getUsername, - logout, -} from '@/app/actions'; -import {BuilderPackageDatabase, getRxDB} from '@/lib/db'; -import {useLogoutShortcutListener} from '@/lib/hooks'; -import {BuilderPackageStatus} from '@/types/BuilderPackage'; -import {RiLogoutBoxLine} from '@remixicon/react'; -import { - Button, - Card, - Select, - SelectItem, - Tab, - TabGroup, - TabList, - TabPanel, - TabPanels, -} from '@tremor/react'; -import {useEffect, useState} from 'react'; -import {toast} from 'react-toastify'; - -import {parseAuditLogEntry} from '@/lib/util'; -import {DistinctAuditLogUsers} from '@/types/AuditLog'; -import AuditLogs from './AuditLogs'; -import KPICards from './KPICards'; -import Loader from './Loader'; -import PackageTable from './PackageTable'; -import RebuildTable from './RebuildTable'; -import Statistics from './Statistics'; - -const list = [ - { - text: 'Package List', - value: '0', - }, - { - text: 'Rebuild Queue', - value: '1', - }, - { - text: 'Audit Logs', - value: '2', - }, - { - text: 'Statistics', - value: '3', - }, -]; - -export default function AdminShell() { - const [name, setName] = useState(''); - const [server, setServer] = useState(''); - const [selectedTab, setSelectedTab] = useState('0'); - const [filterStatus, setFilterStatus] = useState(); - const [db, setDb] = useState(); - useLogoutShortcutListener(() => logout()); - useEffect(() => { - getUsername().then(x => setName(x)); - getServerDetails().then(x => setServer(x.name)); - }, []); - useEffect(() => { - toast.promise( - getRxDB() - .then(x => { - setDb(x); - return x; - }) - .then(x => - Promise.all([ - getPackages().then(data => x.packages.bulkUpsert(data)), - getRebuildPackages().then(data => { - if (data.length) { - return x.rebuild_packages.bulkUpsert(data); - } - }), - getAuditLogs().then(data => { - let users: string[] = []; - if (data.length) { - data.forEach(log => { - if (!users.includes(log.username)) { - users.push(log.username); - } - x.audit_logs.upsert(parseAuditLogEntry(log)); - }); - } - return x.audit_logs.upsertLocal('users', { - users, - }); - }), - ]) - ), - { - error: 'Failed to load packages', - pending: 'Loading packages...', - success: 'Packages loaded!', - } - ); - }, []); - if (!db) { - return ( - - ); - } - return ( - -
-
-
-
-

- CachyOS Builder Dashboard -

-
-
- -
-
-

- Hello {name}, welcome to the CachyOS builder dashboard! You are - currently connected to the {server} server. -

-
-
- -
-
- setFilterStatus(type)} /> - setSelectedTab(index.toString())} - > - - - {list.map(({text, value}) => ( - - {text} - - ))} - - - - - - - - - - - - - - - - -
- ); -} diff --git a/components/AuditLogs.tsx b/components/AuditLogs.tsx deleted file mode 100644 index 4efded4..0000000 --- a/components/AuditLogs.tsx +++ /dev/null @@ -1,379 +0,0 @@ -'use client'; - -import {getAuditLogs} from '@/app/actions'; -import {BuilderPackageDatabase} from '@/lib/db'; -import {parseAuditLogEntry} from '@/lib/util'; -import { - AuditLogEventName, - DistinctAuditLogUsers, - ParsedAuditLogEntry, -} from '@/types/AuditLog'; -import { - BuilderPackageArchitecture, - BuilderPackageRepository, -} from '@/types/BuilderPackage'; -import {RiRefreshLine, RiSearchLine, RiSoundModuleFill} from '@remixicon/react'; -import { - Accordion, - AccordionBody, - AccordionHeader, - AccordionList, - Button, - Card, - Icon, - List, - ListItem, - MultiSelect, - MultiSelectItem, - NumberInput, - TextInput, -} from '@tremor/react'; -import {useEffect, useMemo, useState} from 'react'; -import {toast} from 'react-toastify'; -import {MangoQuery} from 'rxdb'; -import {useRxQuery} from 'rxdb-hooks'; - -export default function AuditLogs({ - db, -}: Readonly<{db: BuilderPackageDatabase}>) { - const [pkgQuery, setPkgQuery] = useState(''); - const [distinctUsers, setDistinctUsers] = useState([]); - const [selectedUser, setSelectedUser] = useState([]); - const [selectedEvents, setSelectedEvents] = useState([]); - const [selectedRepositories, setSelectedRepositories] = useState( - [] - ); - const [selectedMarch, setSelectedMarch] = useState([]); - const [pageSize, setPageSize] = useState(10); - const auditLogCollection = useMemo(() => db.collections.audit_logs, [db]); - useEffect(() => { - auditLogCollection - .getLocal$('users') - .subscribe(data => { - if (data) { - setDistinctUsers(data.get('users') ?? []); - } - }); - }, [db]); - const query = useMemo(() => { - const searchQuery: MangoQuery = { - selector: { - ...(selectedUser.length - ? { - username: { - $in: selectedUser, - }, - } - : {}), - ...(pkgQuery.trim().length - ? { - 'packages.pkgbase': { - $options: 'ig', - $regex: pkgQuery.trim(), - }, - } - : {}), - ...(selectedRepositories.length - ? { - 'packages.repository': { - $in: selectedRepositories, - }, - } - : {}), - ...(selectedMarch.length - ? { - 'packages.march': { - $in: selectedMarch, - }, - } - : {}), - ...(selectedEvents.length - ? { - event_name: { - $in: selectedEvents, - }, - } - : {}), - }, - }; - return auditLogCollection.find(searchQuery).sort({ - updated: 'desc', - }); - }, [ - auditLogCollection, - pkgQuery, - selectedUser, - selectedRepositories, - selectedMarch, - selectedEvents, - ]); - const { - currentPage, - fetchPage, - pageCount, - result: auditLogs, - } = useRxQuery(query, { - pageSize, - pagination: 'Traditional', - }); - return ( - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedEvents(events); - }} - placeholder="Filter by event" - > - {Object.values(AuditLogEventName).map(event => ( - - {event} - - ))} - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedUser(users); - }} - placeholder="Filter by user" - > - {distinctUsers.map(user => ( - - {user} - - ))} - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedRepositories(repositories); - }} - placeholder="Filter by repository" - > - {Object.values(BuilderPackageRepository).map(repo => ( - - {repo} - - ))} - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedMarch(arch); - }} - placeholder="Filter by march" - > - {Object.values(BuilderPackageArchitecture).map(arch => ( - - {arch} - - ))} - -
-
- -
-
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setPkgQuery(value); - }} - placeholder="Search for a package" - value={pkgQuery} - /> -
- - {auditLogs.map(log => ( - - - -
1} - > - x{log.packages.length} -
-
- {log.username} performed {log.event_name} on{' '} - {log.packages.length > 3 - ? `${log.packages - .slice(3) - .map(pkg => pkg.pkgbase) - .join(', ')} and ${log.packages.length - 3} more` - : log.packages.map(pkg => pkg.pkgbase).join(', ')}{' '} - at {new Date(log.updated).toLocaleString()} -
-
- - - - Parsed Event Description - - -
- {log.packages.map(pkg => ( - - - - Package: - - {pkg.pkgbase} - - - - Repository: - - {pkg.repository} - - - - Architecture: - - {pkg.march} - - - - - ))} -
-
-
- - - Raw Event Description - - -

{log.event_desc}

-
-
-
-
- ))} -
-
- -
- {currentPage} / {pageCount} -
- -
-
-
- - - isNaN(value) || value > pageCount ? null : fetchPage(value) - } - placeholder="Page Number" - value={currentPage} - /> - - - isNaN(value) || value > 50 || value < 1 - ? null - : setPageSize(value) - } - placeholder="Page Size" - value={pageSize} - /> -
-
-
- ); -} diff --git a/components/BasePackageList.tsx b/components/BasePackageList.tsx deleted file mode 100644 index 90cfcc1..0000000 --- a/components/BasePackageList.tsx +++ /dev/null @@ -1,67 +0,0 @@ -'use client'; - -import {BaseBuilderPackageWithName} from '@/types/BuilderPackage'; -import { - Button, - Card, - Table, - TableBody, - TableCell, - TableHeaderCell, - TableRow, -} from '@tremor/react'; -import {useMemo, useState} from 'react'; - -export function BasePackageList({ - packages, - title, -}: Readonly<{ - packages: BaseBuilderPackageWithName[]; - title?: string; -}>) { - const [showAll, setShowAll] = useState(false); - const pkgs = useMemo( - () => (showAll ? packages : packages.slice(0, 5)), - [packages, showAll] - ); - return ( - -

- {title} -

- - - - Base (Name) - - - Arch - - - Repository - - - - {pkgs.map(item => ( - - - {item.pkgbase} ({item.pkgname}) - - {item.march} - {item.repository} - - ))} - -
- -
- ); -} diff --git a/components/Checkbox.tsx b/components/Checkbox.tsx deleted file mode 100644 index d358335..0000000 --- a/components/Checkbox.tsx +++ /dev/null @@ -1,60 +0,0 @@ -'use client'; - -import * as CheckboxPrimitives from '@radix-ui/react-checkbox'; -import {ComponentPropsWithoutRef, ElementRef, forwardRef} from 'react'; - -const Checkbox = forwardRef< - ElementRef, - ComponentPropsWithoutRef ->(({checked, className, ...props}, forwardedRef) => { - return ( - - - {checked === 'indeterminate' ? ( - - ) : ( - - - - )} - - - ); -}); -Checkbox.displayName = 'Checkbox'; - -export default Checkbox; diff --git a/components/ConfirmBulkRebuildModal.tsx b/components/ConfirmBulkRebuildModal.tsx deleted file mode 100644 index 1990e75..0000000 --- a/components/ConfirmBulkRebuildModal.tsx +++ /dev/null @@ -1,58 +0,0 @@ -'use client'; - -import {bulkRebuildPackages} from '@/app/actions'; -import {BaseBuilderPackageWithName} from '@/types/BuilderPackage'; -import {Button} from '@tremor/react'; -import {useEffect} from 'react'; -import {useFormState} from 'react-dom'; -import {toast} from 'react-toastify'; - -import {BasePackageList} from './BasePackageList'; -import Modal from './Modal'; -import SubmitButton from './SubmitButton'; - -const initialState = { - success: false, -}; - -export default function ConfirmBulkRebuildModal({ - isOpen, - onClose, - packages, -}: Readonly<{ - isOpen: boolean; - onClose: () => void; - packages: BaseBuilderPackageWithName[]; -}>) { - const [state, formAction] = useFormState( - bulkRebuildPackages.bind(null, packages), - initialState - ); - useEffect(() => { - if (state?.success) { - toast.success('Packages added to rebuild queue successfully!'); - onClose(); - } - }, [onClose, state?.success]); - return ( - -
-

- Rebuild packages? -

-

- Are you sure you want to rebuild the following packages? -

-
- -
-
- - -
-
-
- ); -} diff --git a/components/ConfirmRebuildModal.tsx b/components/ConfirmRebuildModal.tsx deleted file mode 100644 index d9c5b85..0000000 --- a/components/ConfirmRebuildModal.tsx +++ /dev/null @@ -1,54 +0,0 @@ -'use client'; -import {rebuildPackage} from '@/app/actions'; -import {BuilderPackage} from '@/types/BuilderPackage'; -import {Button} from '@tremor/react'; -import {useEffect} from 'react'; -import {useFormState} from 'react-dom'; -import {toast} from 'react-toastify'; - -import Modal from './Modal'; -import SubmitButton from './SubmitButton'; - -const initialState = { - success: false, -}; - -export default function ConfirmRebuildModal({ - isOpen, - onClose, - pkg, -}: Readonly<{ - isOpen: boolean; - onClose: () => void; - pkg: BuilderPackage; -}>) { - const [state, formAction] = useFormState(rebuildPackage, initialState); - useEffect(() => { - if (state?.success) { - toast.success('Package added successfully!'); - onClose(); - } - }, [onClose, state?.success]); - return ( - -
-

- Rebuild package? -

-

- Are you sure you want to rebuild {pkg.pkgname} ({pkg.pkgbase}) ( - {pkg.march})? -

- - - -
- - -
-
-
- ); -} diff --git a/components/KPICards.tsx b/components/KPICards.tsx deleted file mode 100644 index dadb075..0000000 --- a/components/KPICards.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import {BuilderPackageDatabase} from '@/lib/db'; -import {useKpiCards} from '@/lib/hooks'; -import {BuilderPackageStatus} from '@/types/BuilderPackage'; -import {Badge, Card, ProgressCircle} from '@tremor/react'; - -export default function KPICards({ - db, - handleClick, -}: Readonly<{ - db: BuilderPackageDatabase; - handleClick: (type: BuilderPackageStatus) => void; -}>) { - const {kpiCards, total} = useKpiCards(db); - return ( -
- {kpiCards.map(kpi => { - const percentage = total - ? parseFloat(((kpi.current / total) * 100).toFixed(2)) - : 0; - return ( - handleClick(kpi.type)} - > -
-

- - - {kpi.name} - -

- {percentage}% -
-
-

- - {kpi.current} - - {kpi.total ? ( - - /{kpi.total} - - ) : ( - <> - )} -

- - - {percentage}% - - -
-
- ); - })} -
- ); -} diff --git a/components/LoginForm.tsx b/components/LoginForm.tsx deleted file mode 100644 index 83a52b8..0000000 --- a/components/LoginForm.tsx +++ /dev/null @@ -1,121 +0,0 @@ -'use client'; - -import {login} from '@/app/actions'; -import servers, {defaultServer} from '@/lib/servers'; -import {Turnstile} from '@marsidev/react-turnstile'; -import {Select, SelectItem, TextInput} from '@tremor/react'; -import Image from 'next/image'; -import {redirect, useSearchParams} from 'next/navigation'; -import {useFormState} from 'react-dom'; - -import SubmitButton from './SubmitButton'; - -const initialState = { - errorCredentials: '', - errorPassword: '', - errorUsername: '', -}; - -export default function LoginForm({loggedIn}: Readonly<{loggedIn?: boolean}>) { - const [state, formAction] = useFormState(login, initialState); - const query = useSearchParams(); - const redirectTo = query.get('redirect'); - if (loggedIn) { - if (redirectTo?.startsWith('/')) { - return redirect(redirectTo); - } - return redirect('/dashboard'); - } - return ( -
-
-
- CachyOS Logo -
-

- Log in to your CachyOS Builder account -

-
- - - - - - -

Beep boop, boop beep?

- - {redirectTo ? ( - - ) : null} - - -

- {state.errorCredentials} -

-

- By signing in, you agree to data processing and privacy policy. Your - ip address and user agent will be stored for security purposes. -

-
-
- ); -} diff --git a/components/Modal.tsx b/components/Modal.tsx deleted file mode 100644 index 7c2bfb9..0000000 --- a/components/Modal.tsx +++ /dev/null @@ -1,38 +0,0 @@ -'use client'; -import {RiCloseLine} from '@remixicon/react'; -import {Dialog, DialogPanel} from '@tremor/react'; - -export default function Modal({ - children, - isOpen, - large, - onClose, -}: Readonly<{ - children: React.ReactNode; - isOpen: boolean; - large?: boolean; - onClose: () => void; -}>) { - return ( - onClose()} - open={isOpen} - static={true} - > - -
- -
- {children} -
-
- ); -} diff --git a/components/PackageTable.tsx b/components/PackageTable.tsx deleted file mode 100644 index ea0c0a9..0000000 --- a/components/PackageTable.tsx +++ /dev/null @@ -1,537 +0,0 @@ -'use client'; - -import {getPackages} from '@/app/actions'; -import {BuilderPackageDatabase} from '@/lib/db'; -import {getColor} from '@/lib/util'; -import { - BaseBuilderPackageWithName, - BuilderPackageArchitecture, - BuilderPackageRepository, - BuilderPackageStatus, - BuilderPackageWithID, -} from '@/types/BuilderPackage'; -import { - Menu, - MenuButton, - MenuItem, - MenuItems, - Transition, -} from '@headlessui/react'; -import {CheckedState} from '@radix-ui/react-checkbox'; -import { - RiAddLine, - RiArrowDownSLine, - RiArticleLine, - RiRefreshLine, - RiRestartLine, - RiSearchLine, - RiSoundModuleFill, -} from '@remixicon/react'; -import { - Badge, - Button, - Card, - MultiSelect, - MultiSelectItem, - NumberInput, - Table, - TableBody, - TableCell, - TableHead, - TableHeaderCell, - TableRow, - TextInput, -} from '@tremor/react'; -import Link from 'next/link'; -import {Fragment, useEffect, useMemo, useState} from 'react'; -import {toast} from 'react-toastify'; -import {MangoQuery} from 'rxdb'; -import {useRxQuery} from 'rxdb-hooks'; - -import AddPackageModal from './AddPackageModal'; -import Checkbox from './Checkbox'; -import ConfirmBulkRebuildModal from './ConfirmBulkRebuildModal'; -import ConfirmRebuildModal from './ConfirmRebuildModal'; - -export default function PackageTable({ - db, - filterStatus, -}: Readonly<{ - db: BuilderPackageDatabase; - filterStatus?: BuilderPackageStatus; -}>) { - const [selectedPackages, setSelectedPackages] = useState< - BaseBuilderPackageWithName[] - >([]); - const [checked, setChecked] = useState(false); - const [addPkgModalOpen, setAddPkgModalOpen] = useState(false); - const [bulkRebuildModalOpen, setBulkRebuildModalOpen] = useState(false); - const [rebuildPackage, setRebuildPackage] = useState(); - const [pkgQuery, setPkgQuery] = useState(''); - const [selectedBuildStatus, setSelectedBuildStatus] = useState([]); - const [selectedRepositories, setSelectedRepositories] = useState( - [] - ); - const [selectedMarch, setSelectedMarch] = useState([]); - const [pageSize, setPageSize] = useState(10); - useEffect(() => { - if (filterStatus) { - setSelectedBuildStatus([filterStatus]); - } - }, [filterStatus]); - const packageCollection = useMemo(() => db.collections.packages, [db]); - const query = useMemo(() => { - const searchQuery: MangoQuery = { - selector: { - $or: [ - { - ...(selectedBuildStatus.length - ? { - status: { - $in: selectedBuildStatus, - }, - } - : {}), - ...(pkgQuery.trim().length - ? { - pkgname: { - $options: 'ig', - $regex: pkgQuery.trim(), - }, - } - : {}), - ...(selectedRepositories.length - ? { - repository: { - $in: selectedRepositories, - }, - } - : {}), - ...(selectedMarch.length - ? { - march: { - $in: selectedMarch, - }, - } - : {}), - }, - ...(selectedPackages.length - ? [ - { - $or: selectedPackages.map(pkg => ({ - march: pkg.march, - pkgbase: pkg.pkgbase, - repository: pkg.repository, - })), - }, - ] - : []), - ], - }, - }; - return packageCollection.find(searchQuery).sort({ - updated: 'desc', - }); - }, [ - packageCollection, - pkgQuery, - selectedBuildStatus, - selectedRepositories, - selectedMarch, - ]); - const { - currentPage, - fetchPage, - pageCount, - result: packages, - } = useRxQuery(query, { - pageSize, - pagination: 'Traditional', - }); - useEffect(() => { - if (selectedPackages.length === 0) { - setChecked(false); - } else if ( - packages.filter(pkg => - selectedPackages.some( - x => x.pkgbase === pkg.pkgbase && x.march === pkg.march - ) - ).length === packages.length - ) { - setChecked(true); - } else { - setChecked('indeterminate'); - } - }, [packages, selectedPackages]); - return ( - - {bulkRebuildModalOpen ? ( - { - setBulkRebuildModalOpen(false); - setSelectedPackages([]); - }} - packages={selectedPackages} - /> - ) : null} - {addPkgModalOpen ? ( - setAddPkgModalOpen(false)} - /> - ) : null} - {rebuildPackage ? ( - setRebuildPackage(undefined)} - pkg={rebuildPackage} - /> - ) : null} -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedBuildStatus(status); - }} - placeholder="Filter by build status" - value={selectedBuildStatus} - > - {Object.values(BuilderPackageStatus).map(status => ( - - {status} - - ))} - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedRepositories(repositories); - }} - placeholder="Filter by repository" - value={selectedRepositories} - > - {Object.values(BuilderPackageRepository).map(repo => ( - - {repo} - - ))} - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedMarch(arch); - }} - placeholder="Filter by march" - value={selectedMarch} - > - {Object.values(BuilderPackageArchitecture).map(arch => ( - - {arch} - - ))} - -
-
- - - -
- - Options - -
- - -
- - - -
-
-
-
-
-
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setPkgQuery(value); - }} - placeholder="Search for a package" - value={pkgQuery} - /> -
- - - - - { - if (status === true) { - setSelectedPackages( - selectedPackages.concat( - packages.map(pkg => ({ - march: pkg.march, - pkgbase: pkg.pkgbase, - pkgname: pkg.pkgname, - repository: pkg.repository, - })) - ) - ); - } else if (status === false) { - setSelectedPackages( - selectedPackages.filter( - x => - packages.findIndex( - pkg => - x.pkgbase === pkg.pkgbase && x.march === pkg.march - ) === -1 - ) - ); - } - }} - /> - - - Name - - - Arch - - - Version - - - Repository - - - Status - - - Updated At - - - Build Log - - - Raw Build Log - - - Rebuild - - - - - {packages.map(pkg => ( - - - x.pkgbase === pkg.pkgbase && x.march === pkg.march - )} - onCheckedChange={checked => - setSelectedPackages( - checked - ? [ - ...selectedPackages, - { - march: pkg.march, - pkgbase: pkg.pkgbase, - pkgname: pkg.pkgname, - repository: pkg.repository, - }, - ] - : selectedPackages.filter( - x => - x.pkgbase !== pkg.pkgbase || x.march !== pkg.march - ) - ) - } - /> - - - {pkg.pkgname} ({pkg.pkgbase}) - - {pkg.march} - {pkg.version} - {pkg.repository} - - {pkg.status} - - - {new Date(pkg.updated * 1000).toLocaleString()} - - - - - - - - - - - - - - - - ))} - -
-
- -
- {currentPage} / {pageCount} -
- -
-
-
- - - isNaN(value) || value > pageCount ? null : fetchPage(value) - } - placeholder="Page Number" - value={currentPage} - /> - - - isNaN(value) || value > 50 || value < 1 - ? null - : setPageSize(value) - } - placeholder="Page Size" - value={pageSize} - /> -
-
-
- ); -} diff --git a/components/RebuildTable.tsx b/components/RebuildTable.tsx deleted file mode 100644 index ee30c82..0000000 --- a/components/RebuildTable.tsx +++ /dev/null @@ -1,333 +0,0 @@ -'use client'; - -import {getRebuildPackages} from '@/app/actions'; -import {BuilderPackageDatabase} from '@/lib/db'; -import {getColor} from '@/lib/util'; -import { - BuilderPackageArchitecture, - BuilderPackageRepository, - BuilderPackageStatus, - BuilderRebuildPackageWithID, -} from '@/types/BuilderPackage'; -import { - RiArticleLine, - RiRefreshLine, - RiSearchLine, - RiSoundModuleFill, -} from '@remixicon/react'; -import { - Badge, - Button, - Card, - MultiSelect, - MultiSelectItem, - NumberInput, - Table, - TableBody, - TableCell, - TableHead, - TableHeaderCell, - TableRow, - TextInput, -} from '@tremor/react'; -import Link from 'next/link'; -import {useMemo, useState} from 'react'; -import {toast} from 'react-toastify'; -import {MangoQuery} from 'rxdb'; -import {useRxQuery} from 'rxdb-hooks'; - -export default function RebuildTable({ - db, -}: Readonly<{db: BuilderPackageDatabase}>) { - const [pkgQuery, setPkgQuery] = useState(''); - const [selectedBuildStatus, setSelectedBuildStatus] = useState([]); - const [selectedRepositories, setSelectedRepositories] = useState( - [] - ); - const [selectedMarch, setSelectedMarch] = useState([]); - const [pageSize, setPageSize] = useState(10); - const packageCollection = useMemo( - () => db.collections.rebuild_packages, - [db] - ); - const query = useMemo(() => { - const searchQuery: MangoQuery = { - selector: { - ...(selectedBuildStatus.length - ? { - status: { - $in: selectedBuildStatus, - }, - } - : {}), - ...(pkgQuery.trim().length - ? { - pkgbase: { - $options: 'ig', - $regex: pkgQuery.trim(), - }, - } - : {}), - ...(selectedRepositories.length - ? { - repository: { - $in: selectedRepositories, - }, - } - : {}), - ...(selectedMarch.length - ? { - march: { - $in: selectedMarch, - }, - } - : {}), - }, - }; - return packageCollection.find(searchQuery).sort({ - updated: 'desc', - }); - }, [ - packageCollection, - pkgQuery, - selectedBuildStatus, - selectedRepositories, - selectedMarch, - ]); - const { - currentPage, - fetchPage, - pageCount, - result: packages, - } = useRxQuery(query, { - pageSize, - pagination: 'Traditional', - }); - return ( - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedBuildStatus(status); - }} - placeholder="Filter by build status" - > - {Object.values(BuilderPackageStatus).map(status => ( - - {status} - - ))} - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedRepositories(repositories); - }} - placeholder="Filter by repository" - > - {Object.values(BuilderPackageRepository).map(repo => ( - - {repo} - - ))} - -
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setSelectedMarch(arch); - }} - placeholder="Filter by march" - > - {Object.values(BuilderPackageArchitecture).map(arch => ( - - {arch} - - ))} - -
-
- -
-
-
- { - if (currentPage !== 1) { - fetchPage(1); - } - setPkgQuery(value); - }} - placeholder="Search for a package" - value={pkgQuery} - /> -
- - - - - Base - - - Arch - - - Repository - - - Status - - - Updated At - - - Build Log - - - Raw Build Log - - - - - {packages.map(pkg => ( - - {pkg.pkgbase} - {pkg.march} - {pkg.repository} - - {pkg.status} - - - {new Date(pkg.updated / 1000000).toLocaleString()} - - - - - - - - - - - - - ))} - -
-
- -
- {currentPage} / {pageCount} -
- -
-
-
- - - isNaN(value) || value > pageCount ? null : fetchPage(value) - } - placeholder="Page Number" - value={currentPage} - /> - - - isNaN(value) || value > 50 || value < 1 - ? null - : setPageSize(value) - } - placeholder="Page Size" - value={pageSize} - /> -
-
-
- ); -} diff --git a/components/Statistics.tsx b/components/Statistics.tsx deleted file mode 100644 index f72d797..0000000 --- a/components/Statistics.tsx +++ /dev/null @@ -1,217 +0,0 @@ -'use client'; - -import {BuilderPackageDatabase} from '@/lib/db'; -import {useKpiCards} from '@/lib/hooks'; -import {getClassByColor} from '@/lib/util'; -import {BuilderPackage, BuilderPackageStatus} from '@/types/BuilderPackage'; -import {AreaChart, Card, DonutChart, List, ListItem} from '@tremor/react'; -import {useEffect, useMemo, useState} from 'react'; -import {toast} from 'react-toastify'; - -type StatsData = {[K in BuilderPackageStatus]?: number} & {monthYear: string}; - -const numberFormatter = (number: number) => - Intl.NumberFormat('us').format(number).toString(); - -const handleStats = ( - packages: BuilderPackage[], - callback: (stats: StatsData[]) => void -) => { - if (!packages.length) { - return; - } - const minDate = new Date(packages[0].updated * 1000); - const maxDate = new Date(packages[packages.length - 1].updated * 1000); - const data: { - [monthYear: string]: { - [status: string]: number; - }; - } = {}; - const monthStatusCounts = packages.reduce((acc, doc) => { - const date = new Date(doc.updated * 1000); - const monthYear = `${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getFullYear()}`; - const {status} = doc; - if (!acc[monthYear]) { - acc[monthYear] = {}; - } - if (!acc[monthYear][status]) { - acc[monthYear][status] = 0; - } - acc[monthYear][status]++; - return acc; - }, data); - const currentDate = new Date(minDate.getFullYear(), minDate.getMonth()); - while (currentDate <= maxDate) { - const monthYear = `${(currentDate.getMonth() + 1).toString().padStart(2, '0')}-${currentDate.getFullYear()}`; - if (!monthStatusCounts[monthYear]) { - monthStatusCounts[monthYear] = {}; - } - currentDate.setMonth(currentDate.getMonth() + 1); - } - const monthStatusCountsArray = Object.entries(monthStatusCounts).map( - ([monthYear, statusCounts]) => { - return { - monthYear, - ...statusCounts, - }; - } - ); - callback(monthStatusCountsArray); -}; - -const colors = ['green', 'amber', 'blue', 'red', 'sky', 'violet', 'pink']; - -export default function Statistics({ - db, -}: Readonly<{db: BuilderPackageDatabase}>) { - const [stats, setStats] = useState([]); - const {extraKpiCards, kpiCards} = useKpiCards(db); - const data = useMemo( - () => - [...kpiCards, ...extraKpiCards].map(x => ({ - amount: x.current, - color: x.color, - name: x.name, - share: ((x.current / x.total) * 100).toFixed(2) + '%', - })), - [extraKpiCards, kpiCards] - ); - const packageCollection = useMemo(() => db.collections.packages, [db]); - const query = useMemo( - () => - packageCollection.find().sort({ - updated: 'asc', - }), - [packageCollection] - ); - useEffect(() => { - const querySubscription = query.$.subscribe(packages => { - if (!packages.length) { - return; - } - const id = toast.loading('Updating statistics...'); - handleStats(packages, computedStats => setStats(computedStats)); - toast.update(id, { - autoClose: 5000, - closeButton: true, - isLoading: false, - render: 'Statistics updated!', - type: 'success', - }); - }); - - return () => { - querySubscription.unsubscribe(); - }; - }, [query]); - return ( - - -

- Total builds by month -

- { - const {active, label, payload} = props; - if (!active || !payload) { - return null; - } - return ( -
-
-
-
- Date: {label} -
-
-
- {payload.map((category, idx) => ( -
-
-
-

- {category.dataKey} -

-

- {category.value} packages -

-
-
- ))} -
- ); - }} - data={stats} - index="monthYear" - noDataText="Crunching the numbers..." - onValueChange={v => v} - showAnimation - showTooltip - yAxisWidth={64} - /> - - -

- Total builds by category -

- v} - showAnimation - valueFormatter={numberFormatter} - /> -

- Category - Amount / Share -

- - {data.map(item => ( - -
- - - {item.name} - -
-
- - {numberFormatter(item.amount)} - - - {item.share} - -
-
- ))} -
-
- - ); -} diff --git a/components/SubmitButton.tsx b/components/SubmitButton.tsx deleted file mode 100644 index a1d461d..0000000 --- a/components/SubmitButton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -'use client'; - -import {Button} from '@tremor/react'; -import {useFormStatus} from 'react-dom'; - -export default function SubmitButton({ - className = 'mt-4 w-full', - disabled = false, - text, -}: Readonly<{className?: string; disabled?: boolean; text: string}>) { - const {pending} = useFormStatus(); - return ( - - ); -} diff --git a/eslint.config.mjs b/eslint.config.mjs index b1903b9..eb9c46c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,22 +1,17 @@ -import js from '@eslint/js'; -import next from '@next/eslint-plugin-next'; +import {FlatCompat} from '@eslint/eslintrc'; import perfectionist from 'eslint-plugin-perfectionist'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; -import tsEslint from 'typescript-eslint'; +import {dirname} from 'path'; +import {fileURLToPath} from 'url'; -export default tsEslint.config( - js.configs.recommended, +const compat = new FlatCompat({ + baseDirectory: dirname(fileURLToPath(import.meta.url)), +}); + +const eslintConfig = [ + ...compat.extends('next/core-web-vitals', 'next/typescript'), perfectionist.configs['recommended-natural'], eslintPluginPrettierRecommended, - ...tsEslint.configs.recommended, - { - files: ['./**/*.ts', './**/*.tsx'], - plugins: { - '@next/next': next, - }, - rules: { - 'no-unused-vars': 'warn', - ...next.configs.recommended.rules, - }, - } -); +]; + +export default eslintConfig; diff --git a/lib/db.ts b/lib/db.ts deleted file mode 100644 index c8d398c..0000000 --- a/lib/db.ts +++ /dev/null @@ -1,232 +0,0 @@ -import {AuditLogEventName, ParsedAuditLogEntry} from '@/types/AuditLog'; -import { - BuilderPackageArchitecture, - BuilderPackageRepository, - BuilderPackageStatus, - BuilderPackageWithID, -} from '@/types/BuilderPackage'; -import { - RxCollection, - RxDatabase, - addRxPlugin, - createRxDatabase, - toTypedRxJsonSchema, -} from 'rxdb'; -import {wrappedKeyCompressionStorage} from 'rxdb/plugins/key-compression'; -import {RxDBLocalDocumentsPlugin} from 'rxdb/plugins/local-documents'; -import {RxDBQueryBuilderPlugin} from 'rxdb/plugins/query-builder'; -import {getRxStorageMemory} from 'rxdb/plugins/storage-memory'; - -const BuilderPackageSchema = toTypedRxJsonSchema({ - indexes: ['pkgbase', 'pkgname', 'repository', 'status'], - keyCompression: true, - primaryKey: { - fields: ['pkgbase', 'pkgname', 'repository', 'march'], - key: 'packageID', - separator: '-', - }, - properties: { - march: { - enum: Object.values(BuilderPackageArchitecture), - maxLength: 10, - type: 'string', - }, - packageID: { - maxLength: 640, - type: 'string', - }, - pkgbase: { - maxLength: 256, - type: 'string', - }, - pkgname: { - maxLength: 256, - type: 'string', - }, - repo_version: { - type: 'string', - }, - repository: { - enum: Object.values(BuilderPackageRepository), - maxLength: 10, - type: 'string', - }, - status: { - enum: Object.values(BuilderPackageStatus), - maxLength: 10, - type: 'string', - }, - updated: { - type: 'number', - }, - version: { - type: 'string', - }, - }, - required: [ - 'march', - 'packageID', - 'pkgbase', - 'pkgname', - 'repo_version', - 'repository', - 'status', - 'updated', - 'version', - ], - title: 'packages', - type: 'object', - version: 0, -}); - -const BuilderRebuildPackageSchema = toTypedRxJsonSchema({ - indexes: ['pkgbase', 'march', 'repository', 'status'], - keyCompression: true, - primaryKey: { - fields: ['pkgbase', 'repository', 'march'], - key: 'packageID', - separator: '-', - }, - properties: { - march: { - enum: Object.values(BuilderPackageArchitecture), - maxLength: 10, - type: 'string', - }, - packageID: { - maxLength: 640, - type: 'string', - }, - pkgbase: { - maxLength: 256, - type: 'string', - }, - repository: { - enum: Object.values(BuilderPackageRepository), - maxLength: 10, - type: 'string', - }, - status: { - enum: Object.values(BuilderPackageStatus), - maxLength: 10, - type: 'string', - }, - updated: { - type: 'number', - }, - }, - required: [ - 'march', - 'packageID', - 'pkgbase', - 'repository', - 'status', - 'updated', - ], - title: 'rebuildPackages', - type: 'object', - version: 0, -}); - -const ParsedAuditLogSchema = toTypedRxJsonSchema({ - indexes: ['updated', 'username', 'event_name'], - keyCompression: true, - primaryKey: 'id', - properties: { - id: { - maxLength: 320, - type: 'string', - }, - event_desc: { - type: 'string', - }, - event_name: { - enum: Object.values(AuditLogEventName), - maxLength: 32, - type: 'string', - }, - packages: { - items: { - properties: { - march: { - enum: Object.values(BuilderPackageArchitecture), - maxLength: 10, - type: 'string', - }, - pkgbase: { - maxLength: 256, - type: 'string', - }, - repository: { - enum: Object.values(BuilderPackageRepository), - maxLength: 10, - type: 'string', - }, - }, - required: ['march', 'pkgbase', 'repository'], - type: 'object', - }, - type: 'array', - }, - updated: { - maximum: Number.MAX_SAFE_INTEGER, - minimum: 0, - multipleOf: 1, - type: 'number', - }, - username: { - maxLength: 256, - type: 'string', - }, - }, - required: ['id', 'event_desc', 'event_name', 'packages', 'updated'], - title: 'auditLogs', - type: 'object', - version: 0, -}); - -export type BuilderPackageCollection = RxCollection; -export type BuilderRebuildPackageCollection = - RxCollection; -export type ParsedAuditLogCollection = RxCollection; -export type BuilderPackageDatabase = RxDatabase<{ - // camelCase is not compatible with RxDB for database and collection names - audit_logs: ParsedAuditLogCollection; - packages: BuilderPackageCollection; - // camelCase is not compatible with RxDB for database and collection names - rebuild_packages: BuilderRebuildPackageCollection; -}>; - -export async function getRxDB() { - if (process.env.NODE_ENV !== 'production') { - await import('rxdb/plugins/dev-mode').then(module => - addRxPlugin(module.RxDBDevModePlugin) - ); - } - addRxPlugin(RxDBQueryBuilderPlugin); - addRxPlugin(RxDBLocalDocumentsPlugin); - const db: BuilderPackageDatabase = await createRxDatabase({ - eventReduce: true, - ignoreDuplicate: process.env.NODE_ENV !== 'production', - multiInstance: false, - name: 'packages', - storage: wrappedKeyCompressionStorage({ - storage: getRxStorageMemory(), - }), - }); - await db.addCollections({ - // camelCase is not compatible with RxDB for database and collection names - audit_logs: { - schema: ParsedAuditLogSchema, - localDocuments: true, - }, - packages: { - schema: BuilderPackageSchema, - }, - // camelCase is not compatible with RxDB for database and collection names - rebuild_packages: { - schema: BuilderRebuildPackageSchema, - }, - }); - return db; -} diff --git a/lib/fetcher.ts b/lib/fetcher.ts deleted file mode 100644 index e4a0dd7..0000000 --- a/lib/fetcher.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {ReadonlyHeaders} from 'next/dist/server/web/spec-extension/adapters/headers'; - -import {defaultServer} from './servers'; - -export type ResponseType = 'json' | 'raw' | 'text'; - -export function processResponse( - response: Response, - mode: ResponseType -): Promise { - switch (mode) { - case 'json': - return response.json() as Promise; - case 'raw': - return response.arrayBuffer() as Promise; - case 'text': - return response.text() as Promise; - } -} - -export default async function fetcher( - path: string, - sessionToken: string, - clientHeaders: ReadonlyHeaders, - init?: RequestInit, - baseURL = defaultServer.url, - responseMode: ResponseType = 'json' -): Promise { - return fetch(`${baseURL}${path}`, { - cache: 'no-store', - headers: { - ...(sessionToken ? {Authorization: `Bearer ${sessionToken}`} : {}), - 'Content-Type': 'application/json', - 'User-Agent': - clientHeaders.get('User-Agent') ?? - 'CachyBuilderDashboardProxyServer/1.0.0', - 'X-Forwarded-For': - clientHeaders.get('CF-Connecting-IP') ?? - clientHeaders.get('X-Forwarded-For') ?? - '', - ...init?.headers, - }, - ...init, - }).then(res => processResponse(res, responseMode)); -} diff --git a/lib/hooks.ts b/lib/hooks.ts deleted file mode 100644 index 5b152e5..0000000 --- a/lib/hooks.ts +++ /dev/null @@ -1,254 +0,0 @@ -'use client'; - -import {BuilderPackageStatus} from '@/types/BuilderPackage'; -import {useEffect, useMemo, useState} from 'react'; - -import {BuilderPackageDatabase} from './db'; -import {getColor} from './util'; - -const clearTimer = (timer: NodeJS.Timeout | null) => { - if (timer) { - clearTimeout(timer); - } -}; - -export function useKpiCards(db: BuilderPackageDatabase) { - const [total, setTotal] = useState(0); - const [queued, setQueued] = useState(0); - const [failed, setFailed] = useState(0); - const [latest, setLatest] = useState(0); - const [building, setBuilding] = useState(0); - const [done, setDone] = useState(0); - const [skipped, setSkipped] = useState(0); - const [unknown, setUnknown] = useState(0); - const kpiCards = useMemo( - () => [ - { - color: getColor(BuilderPackageStatus.LATEST), - current: latest, - id: 1, - name: 'Latest Packages', - total, - type: BuilderPackageStatus.LATEST, - }, - { - color: getColor(BuilderPackageStatus.BUILDING), - current: building, - id: 2, - name: 'Building Packages', - total, - type: BuilderPackageStatus.BUILDING, - }, - { - color: getColor(BuilderPackageStatus.QUEUED), - current: queued, - id: 3, - name: 'Queued Packages', - total, - type: BuilderPackageStatus.QUEUED, - }, - { - color: getColor(BuilderPackageStatus.FAILED), - current: failed, - id: 4, - name: 'Failed Packages', - total, - type: BuilderPackageStatus.FAILED, - }, - ], - [total, queued, failed, latest, building] - ); - const extraKpiCards = useMemo( - () => [ - { - color: getColor(BuilderPackageStatus.DONE), - current: done, - id: 1, - name: 'Done Packages', - total, - type: BuilderPackageStatus.DONE, - }, - { - color: getColor(BuilderPackageStatus.SKIPPED), - current: skipped, - id: 2, - name: 'Skipped Packages', - total, - type: BuilderPackageStatus.SKIPPED, - }, - { - color: getColor(BuilderPackageStatus.UNKNOWN), - current: unknown, - id: 3, - name: 'Unknown Packages', - total, - type: BuilderPackageStatus.UNKNOWN, - }, - ], - [total, done, skipped, unknown] - ); - const packageCollection = useMemo(() => db.collections.packages, [db]); - const totalQuery = useMemo( - () => packageCollection.count({}), - [packageCollection] - ); - const buildingQuery = useMemo( - () => - packageCollection.count({ - selector: { - status: BuilderPackageStatus.BUILDING, - }, - }), - [packageCollection] - ); - const doneQuery = useMemo( - () => - packageCollection.count({ - selector: { - status: BuilderPackageStatus.DONE, - }, - }), - [packageCollection] - ); - const failedQuery = useMemo( - () => - packageCollection.count({ - selector: { - status: BuilderPackageStatus.FAILED, - }, - }), - [packageCollection] - ); - const latestQuery = useMemo( - () => - packageCollection.count({ - selector: { - status: BuilderPackageStatus.LATEST, - }, - }), - [packageCollection] - ); - const queuedQuery = useMemo( - () => - packageCollection.count({ - selector: { - status: BuilderPackageStatus.QUEUED, - }, - }), - [packageCollection] - ); - const skippedQuery = useMemo( - () => - packageCollection.count({ - selector: { - status: BuilderPackageStatus.SKIPPED, - }, - }), - [packageCollection] - ); - const unknownQuery = useMemo( - () => - packageCollection.count({ - selector: { - status: BuilderPackageStatus.UNKNOWN, - }, - }), - [packageCollection] - ); - - useEffect(() => { - totalQuery.exec().then(x => setTotal(x)); - queuedQuery.exec().then(x => setQueued(x)); - failedQuery.exec().then(x => setFailed(x)); - latestQuery.exec().then(x => setLatest(x)); - buildingQuery.exec().then(x => setBuilding(x)); - doneQuery.exec().then(x => setDone(x)); - skippedQuery.exec().then(x => setSkipped(x)); - unknownQuery.exec().then(x => setUnknown(x)); - - const totalSub = totalQuery.$.subscribe(x => setTotal(x)); - const queuedSub = queuedQuery.$.subscribe(x => setQueued(x)); - const failedSub = failedQuery.$.subscribe(x => setFailed(x)); - const latestSub = latestQuery.$.subscribe(x => setLatest(x)); - const buildingSub = buildingQuery.$.subscribe(x => setBuilding(x)); - const doneSub = doneQuery.$.subscribe(x => setDone(x)); - const skippedSub = skippedQuery.$.subscribe(x => setSkipped(x)); - const unknownSub = unknownQuery.$.subscribe(x => setUnknown(x)); - - return () => { - totalSub.unsubscribe(); - queuedSub.unsubscribe(); - failedSub.unsubscribe(); - latestSub.unsubscribe(); - buildingSub.unsubscribe(); - doneSub.unsubscribe(); - skippedSub.unsubscribe(); - unknownSub.unsubscribe(); - }; - }, [ - totalQuery, - queuedQuery, - failedQuery, - latestQuery, - buildingQuery, - doneQuery, - skippedQuery, - unknownQuery, - ]); - return {extraKpiCards, kpiCards, total}; -} - -export function useLogoutShortcutListener(callback: () => void) { - const [colonQPressed, setColonQPressed] = useState(false); - let timer: NodeJS.Timeout | null = null; - - useEffect(() => { - let colonPressed = false; - const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === ':') { - colonPressed = true; - timer = setTimeout(() => { - colonPressed = false; - }, 800); - } else if (colonPressed && event.key.toLowerCase() === 'q') { - setColonQPressed(true); - colonPressed = false; - clearTimer(timer); - } else { - colonPressed = false; - clearTimer(timer); - } - }; - - window.addEventListener('keydown', handleKeyDown); - - return () => { - window.removeEventListener('keydown', handleKeyDown); - clearTimer(timer); - }; - }, []); - - useEffect(() => { - if (colonQPressed) { - callback(); - setColonQPressed(false); - } - }, [callback, colonQPressed]); -} - -export function useCtrlFShortcutListener(callback: () => void) { - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if (event.ctrlKey && event.key.toLowerCase() === 'f') { - event.preventDefault(); - callback(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }); -} diff --git a/lib/servers.ts b/lib/servers.ts deleted file mode 100644 index 8fe0600..0000000 --- a/lib/servers.ts +++ /dev/null @@ -1,17 +0,0 @@ -const servers = [ - { - default: true, - name: 'CachyOS Builder API - STANDARD', - url: 'https://builder-api.cachyos.org/api', - }, - { - default: false, - name: 'CachyOS Builder API - ZEN4', - url: 'https://builder-api-1.cachyos.org/api', - }, -]; - -export const defaultServer = - servers.find(server => server.default) ?? servers[0]; - -export default servers; diff --git a/lib/util.ts b/lib/util.ts deleted file mode 100644 index ec722fe..0000000 --- a/lib/util.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { - AuditLogEntry, - AuditLogEventName, - AuditLogPackageWithPkgName, - ParsedAuditLogEntry, -} from '@/types/AuditLog'; -import {BuilderPackageStatus} from '@/types/BuilderPackage'; - -export function getColor(status: BuilderPackageStatus) { - switch (status) { - case BuilderPackageStatus.FAILED: - return 'red'; - case BuilderPackageStatus.BUILDING: - return 'amber'; - case BuilderPackageStatus.QUEUED: - return 'blue'; - case BuilderPackageStatus.DONE: - case BuilderPackageStatus.SKIPPED: - case BuilderPackageStatus.LATEST: - return 'green'; - case BuilderPackageStatus.UNKNOWN: - default: - return 'gray'; - } -} - -export function getClassByColor(color: string) { - switch (color) { - case 'red': - return 'bg-red-500'; - case 'amber': - return 'bg-yellow-500'; - case 'blue': - return 'bg-blue-500'; - case 'green': - return 'bg-green-500'; - case 'sky': - return 'bg-sky-500'; - case 'violet': - return 'bg-purple-500'; - case 'pink': - return 'bg-pink-500'; - default: - return 'bg-gray-500'; - } -} - -export function parseAuditLogEntry(event: AuditLogEntry): ParsedAuditLogEntry { - if (event.event_name === AuditLogEventName.QPKG_REBUILD) { - return { - ...event, - packages: [ - { - march: event.event_desc.split("'")[5], - pkgbase: event.event_desc.split("'")[1], - repository: event.event_desc.split("'")[3], - }, - ], - updated: event.updated / 1000000, - }; - } else if (event.event_name === AuditLogEventName.BULK_QPKG_REBUILD) { - console.log(event); - let packages: { - march: string; - pkgbase: string; - repository: string; - }[] = []; - const raw_pkgs = event.event_desc - .replace(/'/g, '') - .replace('bulk rebuild queued: ', ''); - if (raw_pkgs.length) { - packages = (JSON.parse(raw_pkgs) as AuditLogPackageWithPkgName[]).map( - x => ({ - march: x.march, - pkgbase: `${x.pkgbase} (${x.pkgname})`, - repository: x.repository, - }) - ); - } - return { - ...event, - packages, - updated: event.updated / 1000000, - }; - } - return { - ...event, - packages: [], - updated: event.updated / 1000000, - }; -} diff --git a/next.config.mjs b/next.config.mjs deleted file mode 100644 index 6f3a4bc..0000000 --- a/next.config.mjs +++ /dev/null @@ -1,27 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { - poweredByHeader: false, - reactStrictMode: false, - async redirects() { - return [ - { - destination: '/api/logs/:arch/:pkgbase', - has: [ - { - key: 'raw', - type: 'query', - }, - ], - permanent: false, - source: '/logs/:arch/:pkgbase', - }, - ]; - }, - experimental: { - turbo: { - useSwcCss: true, - }, - }, -}; - -export default nextConfig; diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..b4fe370 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,31 @@ +import type {NextConfig} from 'next'; + +const nextConfig: NextConfig = { + devIndicators: { + position: 'bottom-right', + }, + poweredByHeader: false, + reactStrictMode: false, + async redirects() { + return [ + { + destination: '/api/logs/:march/:pkgbase', + has: [ + { + key: 'raw', + type: 'query', + }, + ], + permanent: false, + source: '/dashboard/logs/:march/:pkgbase', + }, + { + destination: '/dashboard/package-list', + permanent: false, + source: '/dashboard', + }, + ]; + }, +}; + +export default nextConfig; diff --git a/package.json b/package.json index a96015a..7510f3f 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,73 @@ { "dependencies": { - "@headlessui/react": "2.1.8", - "@headlessui/tailwindcss": "0.2.1", - "@marsidev/react-turnstile": "1.0.2", - "@radix-ui/react-checkbox": "1.1.1", - "@remixicon/react": "4.2.0", - "@tremor/react": "3.18.3", + "@hookform/resolvers": "^5.2.0", + "@marsidev/react-turnstile": "1.1.0", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-popover": "^1.1.14", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tooltip": "^1.2.7", + "@tabler/icons-react": "3.34.1", + "@tanstack/react-table": "^8.21.3", "@xterm/addon-fit": "0.10.0", "@xterm/addon-search": "0.15.0", "@xterm/addon-web-links": "0.11.0", "@xterm/addon-webgl": "0.18.0", - "@xterm/xterm": "5.5.0", "ansi-styles": "6.2.1", - "iron-session": "8.0.3", - "next": "14.2.13", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-toastify": "10.0.5", - "rxdb": "15.33.0", - "rxdb-hooks": "5.0.2", - "sharp": "0.33.5", - "strip-ansi": "7.1.0" + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "iron-session": "8.0.4", + "lucide-react": "^0.526.0", + "next": "15.4.4", + "next-themes": "^0.4.6", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-hook-form": "7.61.1", + "recharts": "^3.1.0", + "sonner": "^2.0.6", + "strip-ansi": "7.1.0", + "tailwind-merge": "^3.3.1", + "tailwind-variants": "1.0.0", + "use-debounce": "10.0.5", + "zod": "^4.0.10" }, "devDependencies": { - "@next/eslint-plugin-next": "^14.2.20", - "@tailwindcss/forms": "0.5.9", - "@types/node": "^22.10.2", - "@types/react": "^18.3.16", - "@types/react-dom": "^18.3.5", - "@types/validator": "13.12.2", - "autoprefixer": "10.4.20", - "eslint": "^9.17.0", - "eslint-config-next": "^14.2.20", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-perfectionist": "^3.9.1", - "eslint-plugin-prettier": "^5.2.1", - "postcss": "8.4.47", - "tailwindcss": "3.4.13", - "typescript": "5.6.2", - "typescript-eslint": "8.7.0" + "@eslint/eslintrc": "^3.3.1", + "@tailwindcss/postcss": "^4.1.11", + "@types/node": "^24.1.0", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "eslint": "^9.32.0", + "eslint-config-next": "15.4.4", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-perfectionist": "^4.15.0", + "eslint-plugin-prettier": "^5.5.3", + "prettier": "^3.6.2", + "tailwindcss": "^4.1.11", + "tw-animate-css": "^1.3.6", + "typescript": "^5.8.3" }, "name": "cachyos-builder-dashboard", + "packageManager": "bun@1.2.19", "private": true, "scripts": { "build": "next build", - "dev": "next dev", + "dev": "next dev --turbopack", "lint": "next lint", "start": "next start" }, - "version": "0.1.0", - "packageManager": "bun@1.1.38", "trustedDependencies": [ - "protobufjs", - "rxdb", - "sharp" - ] + "@tailwindcss/oxide", + "unrs-resolver" + ], + "version": "0.1.0" } diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index 12a703d..0000000 --- a/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..ba720fe --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ['@tailwindcss/postcss'], +}; + +export default config; diff --git a/public/cachyos-logo-white.svg b/public/cachyos-logo-white.svg new file mode 100644 index 0000000..882d3dd --- /dev/null +++ b/public/cachyos-logo-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/cachyos-logo.svg b/public/cachyos-logo.svg new file mode 100644 index 0000000..07c25fc --- /dev/null +++ b/public/cachyos-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/logo.png b/public/logo.png deleted file mode 100644 index 5be51b2..0000000 Binary files a/public/logo.png and /dev/null differ diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 5db72dd..0000000 --- a/renovate.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended" - ] -} diff --git a/src/app/actions.ts b/src/app/actions.ts new file mode 100644 index 0000000..b850766 --- /dev/null +++ b/src/app/actions.ts @@ -0,0 +1,482 @@ +'use server'; + +import {getIronSession} from 'iron-session'; +import {cookies, headers} from 'next/headers'; +import {redirect} from 'next/navigation'; + +import CachyBuilderClient from '@/lib/CachyBuilderClient'; +import {defaultSession, SessionData, sessionOptions} from '@/lib/session'; +import { + BasePackageListSchema, + BasePackageWithIDList, + ListPackagesQuery, + ListRepoActionsQuery, + LoginRequest, + LoginRequestSchema, + PackageMArch, + PackageRepo, + PackageStatsList, + PackageStatsType, + ParsedAuditLogEntry, + ParsedRepoAction, + ProcessedPackageStatsByMonthList, + SearchPackagesQuery, + UserData, + UserProfile, +} from '@/lib/typings'; + +export async function bulkRebuildPackages(packages: BasePackageWithIDList) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const response = await cachyBuilderClient.bulkRebuildPackages( + packages, + await headers() + ); + return response; + } catch (error) { + return { + error: `Failed to bulk rebuild packages: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function changeServer(serverName: string) { + const {session} = await getSession(); + const serverIndex = session.tokens.findIndex( + token => token.name === serverName && token.token !== '' + ); + if (serverIndex === -1) { + return { + error: `Server "${serverName}" not found or is not accessible with the current session.`, + }; + } + session.serverIndex = serverIndex; + await session.save(); + return { + msg: `Switched to server "${serverName}" successfully.`, + }; +} + +export async function getAccessibleServers() { + const {session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + return session.tokens.map((token, index) => ({ + accessible: token.token !== '', + active: index === session.serverIndex, + description: token.description, + name: token.name, + })); +} + +export async function getAuditLogs() { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const logs = await cachyBuilderClient.getAuditLogs(await headers()); + return logs.map(item => { + const description = item.event_desc; + const packages: ParsedAuditLogEntry[] = []; + if (description.startsWith('rebuild queued')) { + const [pkgbase, repository, march] = description + .replace('rebuild queued ', '') + .split("'-'") + .map(part => part.replace(/'/g, '').trim()); + packages.push({ + description: `Package Base: ${pkgbase}, Repository: ${repository}, MArch: ${march}`, + id: `${item.id}-1`, + updated: item.updated, + username: item.username, + }); + } else if (description.startsWith('bulk rebuild queued:')) { + const packagesString = description + .replace('bulk rebuild queued: ', '') + .replace(/'/g, '') + .trim(); + const packagesArray = BasePackageListSchema.safeParse( + JSON.parse(packagesString) + ); + if (packagesArray.success) { + packagesArray.data.forEach((pkg, i) => + packages.push({ + description: `Package Base: ${pkg.pkgbase}, Repository: ${pkg.repository}, MArch: ${pkg.march}`, + id: `${item.id}-${i + 1}`, + updated: item.updated, + username: item.username, + }) + ); + } + } + return { + description: + packages.length > 1 + ? `Bulk Rebuild: ${packages.length} packages` + : packages.shift()!.description, + eventName: item.event_name, + id: item.id, + packages, + updated: item.updated, + username: item.username, + }; + }); + } catch (error) { + return { + error: `Failed to get audit logs: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function getLoggedInUser( + fullProfile: false +): Promise; + +export async function getLoggedInUser( + fullProfile: true +): Promise; + +export async function getLoggedInUser(fullProfile = false) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const user = await cachyBuilderClient.getLoggedInUserProfile( + await headers() + ); + session.displayName = user.display_name ?? user.username; + session.username = user.username; + session.profile_picture_url = + user.profile_picture_url ?? '/cachyos-logo.svg'; + await session.save(); + if (fullProfile) { + return user; + } + return { + displayName: session.displayName, + profile_picture_url: session.profile_picture_url, + username: session.username, + }; + } catch (error) { + return { + error: `Failed to get user profile: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function getPackageLog( + pkg: string, + march: PackageMArch, + strip = false +) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const log = await cachyBuilderClient.getPackageLog( + pkg, + march, + strip, + await headers() + ); + return log; + } catch (error) { + return { + error: `Failed to get package log: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function getPackageStats( + type: PackageStatsType.CATEGORY +): Promise; + +export async function getPackageStats( + type: PackageStatsType.MONTH +): Promise; +export async function getPackageStats( + type: PackageStatsType = PackageStatsType.CATEGORY +): Promise< + PackageStatsList | ProcessedPackageStatsByMonthList | {error: string} +> { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + if (type === PackageStatsType.MONTH) { + const stats = await cachyBuilderClient.listPackageStatsByMonth( + await headers() + ); + return stats.map(stat => ({ + ...stat, + reporting_month: new Date(stat.reporting_month * 1000) + .toISOString() + .slice(0, 7), + })); + } else { + return cachyBuilderClient.listPackageStatsByCategory(await headers()); + } + } catch (error) { + return { + error: `Failed to get package stats: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} +export async function getSession() { + const session = await getIronSession( + await cookies(), + sessionOptions + ); + if (!session.isLoggedIn) { + session.displayName = defaultSession.displayName; + session.isLoggedIn = defaultSession.isLoggedIn; + session.tokens = defaultSession.tokens; + session.createdAt = Date.now(); + session.serverIndex = defaultSession.serverIndex; + } + const cachyBuilderClient = new CachyBuilderClient( + session.serverIndex, + session.tokens[session.serverIndex].token + ); + return { + cachyBuilderClient, + session, + }; +} + +export async function getUser(username: string) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const user = await cachyBuilderClient.getUserProfile( + username, + await headers() + ); + return user; + } catch (error) { + return { + error: `Failed to get user profile: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function isLoggedIn() { + const {session} = await getSession(); + return session.isLoggedIn; +} + +export async function listPackages(query?: ListPackagesQuery) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const packages = await cachyBuilderClient.listPackages( + query, + await headers() + ); + return packages; + } catch (error) { + return { + error: `Failed to list packages: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function listRebuildPackages() { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const packages = await cachyBuilderClient.listRebuildPackages( + await headers() + ); + return packages; + } catch (error) { + return { + error: `Failed to list packages: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function listRepoActions(query?: ListRepoActionsQuery) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const actions = await cachyBuilderClient + .listRepoActions(query, await headers()) + .then(response => { + return { + ...response, + actions: response.actions.map(action => { + const parsedPackages = action.packages + .split(',') + .map(pkg => ({...action, packages: pkg.trim()})); + return { + ...action, + packages: + parsedPackages.length > 1 + ? `${parsedPackages.length} packages` + : parsedPackages.shift()!.packages, + parsedPackages, + } as ParsedRepoAction; + }), + }; + }); + return actions; + } catch (error) { + return { + error: `Failed to list repo actions: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function login(loginRequest: LoginRequest) { + const data = LoginRequestSchema.safeParse(loginRequest); + if (!data.success) { + return { + error: `Invalid login request: ${data.error.issues.map(issue => issue.message).join(', ')}`, + }; + } + + const turnstileResponse = await fetch( + 'https://challenges.cloudflare.com/turnstile/v0/siteverify', + { + body: `secret=${encodeURIComponent(process.env.TURNSTILE_SECRET_KEY!)}&response=${encodeURIComponent(data.data.turnstileToken)}`, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + method: 'POST', + } + ) + .then(res => res.json()) + .then(res => res.success) + .catch(() => false); + + if (!turnstileResponse) { + return { + error: 'Turnstile verification failed. Please try again.', + }; + } + + const {cachyBuilderClient, session} = await getSession(); + try { + const {errors, validServers} = await cachyBuilderClient.login( + data.data, + await headers(), + true + ); + session.isLoggedIn = true; + session.username = data.data.username; + session.tokens = cachyBuilderClient.apiTokens; + session.serverIndex = cachyBuilderClient.serverIdx; + session.profile_picture_url = '/cachyos-logo.svg'; + await session.save(); + return { + success: validServers.length > 0, + warning: + errors.length > 0 + ? `Some servers failed to respond correctly and have been disabled for this session:\n${errors}` + : undefined, + }; + } catch (error) { + return { + error: `Login failed: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function logout() { + const {session} = await getSession(); + session.destroy(); + return redirect('/'); +} + +export async function rebuildPackage( + pkgbase: string, + march: PackageMArch, + repository: PackageRepo +) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const response = await cachyBuilderClient.rebuildPackage( + {march, pkgbase, repository}, + await headers() + ); + return response; + } catch (error) { + return { + error: `Failed to rebuild package: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function searchPackages(query: SearchPackagesQuery) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const packages = await cachyBuilderClient.searchPackages( + query, + await headers() + ); + return packages; + } catch (error) { + return { + error: `Failed to list packages: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} + +export async function updateProfile(profile: UserProfile, updateAll = false) { + const {cachyBuilderClient, session} = await getSession(); + if (!session.isLoggedIn) { + return redirect('/'); + } + try { + const { + errors, + profile: updatedProfile, + validServers, + } = await cachyBuilderClient.updateProfile( + profile, + updateAll, + true, + await headers() + ); + session.displayName = + updatedProfile.display_name ?? updatedProfile.username; + session.profile_picture_url = + updatedProfile.profile_picture_url ?? '/cachyos-logo.svg'; + session.username = updatedProfile.username; + await session.save(); + return { + profile: updatedProfile, + success: validServers.length > 0, + warning: + errors.length > 0 + ? `Failed to update profile on some servers, you can try again later:\n${errors}` + : undefined, + }; + } catch (error) { + return { + error: `Failed to update profile: ${error instanceof Error ? error.message : 'Unknown error'}`, + }; + } +} diff --git a/app/api/logs/[march]/[pkgbase]/route.ts b/src/app/api/logs/[march]/[pkgbase]/route.ts similarity index 56% rename from app/api/logs/[march]/[pkgbase]/route.ts rename to src/app/api/logs/[march]/[pkgbase]/route.ts index 5acccb6..48bc578 100644 --- a/app/api/logs/[march]/[pkgbase]/route.ts +++ b/src/app/api/logs/[march]/[pkgbase]/route.ts @@ -1,24 +1,28 @@ -import {getPackageLog} from '@/app/actions'; -import {BuilderPackageArchitecture} from '@/types/BuilderPackage'; import {NextRequest, NextResponse} from 'next/server'; +import {getPackageLog} from '@/app/actions'; +import {PackageMArch, packageMArchValues} from '@/lib/typings'; + export async function GET( req: NextRequest, context: { - params: { - march: BuilderPackageArchitecture; + params: Promise<{ + march: PackageMArch; pkgbase: string; - }; + }>; } ) { - const {march, pkgbase} = context.params; + const {march, pkgbase} = await context.params; if (!march || !pkgbase) { return new NextResponse('Not found', {status: 404}); } - if (!Object.values(BuilderPackageArchitecture).includes(march)) { + if (!packageMArchValues.includes(march)) { + return new NextResponse('Not found', {status: 404}); + } + const log = await getPackageLog(pkgbase, march, true); + if (typeof log !== 'string') { return new NextResponse('Not found', {status: 404}); } - const log = await getPackageLog(pkgbase, march, true, req.nextUrl.pathname); return new NextResponse(log, { headers: { 'Content-Type': 'text/plain', diff --git a/app/apple-icon.png b/src/app/apple-icon.png similarity index 100% rename from app/apple-icon.png rename to src/app/apple-icon.png diff --git a/src/app/dashboard/audit-logs/page.tsx b/src/app/dashboard/audit-logs/page.tsx new file mode 100644 index 0000000..7485caf --- /dev/null +++ b/src/app/dashboard/audit-logs/page.tsx @@ -0,0 +1,235 @@ +'use client'; + +import {IconRefresh} from '@tabler/icons-react'; +import {ColumnDef, Table} from '@tanstack/react-table'; +import {ChevronDown, Search} from 'lucide-react'; +import {useEffect, useMemo, useState} from 'react'; +import {toast} from 'sonner'; + +import {getAuditLogs, getUser} from '@/app/actions'; +import Loader from '@/components/loader'; +import {Badge} from '@/components/ui/badge'; +import {Card} from '@/components/ui/card'; +import {ComboBox} from '@/components/ui/combobox'; +import {DataTable} from '@/components/ui/data-table'; +import {DataTableColumnHeader} from '@/components/ui/data-table-column-header'; +import {useSidebar} from '@/components/ui/sidebar'; +import {UsernameHoverCard} from '@/components/username-hover-card'; +import {ParsedAuditLogEntryWithPackages, UserProfile} from '@/lib/typings'; + +export default function AuditLogsPage() { + const {activeServer} = useSidebar(); + const [data, setData] = useState( + null + ); + const [users, setUsers] = useState([]); + const [userData, setUserData] = useState>(new Map()); + const [error, setError] = useState(null); + + useEffect(() => { + setError(null); + setData(null); + getAuditLogs() + .then(response => { + if ('error' in response && response.error) { + setError(response.error); + toast.error(`Failed to fetch repo actions: ${response.error}`, { + closeButton: true, + duration: Infinity, + }); + } + if (Array.isArray(response)) { + setData(response); + setUsers(Array.from(new Set(response.map(entry => entry.username)))); + } + }) + .catch(() => { + setError('Failed to fetch repo actions, please try again later.'); + toast.error('Failed to fetch repo actions, please try again later.', { + closeButton: true, + duration: Infinity, + }); + }); + }, [activeServer]); + + useEffect(() => { + if (users.length === 0) { + return; + } + Promise.all(users.map(username => getUser(username))).then(results => { + const userMap = new Map(); + results.forEach(user => { + if ('error' in user && user.error) { + toast.error(`Failed to fetch a user profile: ${user.error}`, { + closeButton: true, + duration: Infinity, + }); + } else if ('username' in user && user.username) { + userMap.set(user.username, user); + } + }); + setUserData(userMap); + }); + }, [users]); + + const columns: ColumnDef[] = useMemo( + () => [ + { + cell: ({row}) => { + return row.getCanExpand() ? ( + + ) : ( + '' + ); + }, + id: 'expander', + }, + { + cell: ({row}) => {row.original.id}, + header: ({column}) => ( + + ), + id: 'ID', + }, + { + accessorKey: 'description', + cell: ({row}) => ( + + ), + header: ({column}) => ( + + ), + id: 'description', + }, + { + accessorKey: 'eventName', + cell: ({row}) => + row.depth === 0 && ( + + + {row.original.eventName} + + ), + header: ({column}) => ( + + ), + id: 'event', + }, + { + accessorKey: 'username', + cell: ({row}) => { + const user = userData.get(row.original.username); + return ( + + ); + }, + filterFn: (row, _, filterValue) => { + if (Array.isArray(filterValue) && filterValue.length) { + return filterValue.includes(row.original.username); + } + return true; + }, + header: ({column}) => ( + + ), + id: 'username', + }, + { + accessorKey: 'updated', + cell: ({row}) => { + const date = new Date(row.original.updated); + return ( + + {date.toLocaleDateString()}, {date.toLocaleTimeString()} + + ); + }, + header: ({column}) => ( + + ), + id: 'updated at', + }, + ], + [userData] + ); + + const filters = useMemo( + () => [ + { + icon: Search, + id: 'description', + isPrimary: true, + placeholder: 'Search description...', + }, + ], + [] + ); + + const customFilters = useMemo( + () => + users.length + ? [ + (table: Table) => ( +
+ + table.getColumn('username')?.setFilterValue(users) + } + searchNoResultsText="No users found" + searchPlaceholder="Search users..." + selectedItems={ + (table.getColumn('username')?.getFilterValue() ?? + []) as string[] + } + title="Username" + /> +
+ ), + ] + : [], + [users] + ); + + return ( + + {data ? ( + row.packages as ParsedAuditLogEntryWithPackages[]} + initialSortingState={[{desc: true, id: 'updated at'}]} + shrinkFirstColumn + /> + ) : ( + + )} + + ); +} diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx new file mode 100644 index 0000000..8e6297f --- /dev/null +++ b/src/app/dashboard/layout.tsx @@ -0,0 +1,37 @@ +import {AppSidebar} from '@/components/app-sidebar'; +import {CommandMenu} from '@/components/command-menu'; +import {HeaderBreadcrumbs} from '@/components/header-breadcrumbs'; +import {Separator} from '@/components/ui/separator'; +import { + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from '@/components/ui/sidebar'; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + +
+
+ + + +
+
+
+ + {children} +
+
+
+ ); +} diff --git a/src/app/dashboard/logs/[march]/[pkgbase]/page.tsx b/src/app/dashboard/logs/[march]/[pkgbase]/page.tsx new file mode 100644 index 0000000..d9b7237 --- /dev/null +++ b/src/app/dashboard/logs/[march]/[pkgbase]/page.tsx @@ -0,0 +1,38 @@ +'use client'; + +import dynamic from 'next/dynamic'; +import {useParams} from 'next/navigation'; + +import Loader from '@/components/loader'; +import {PackageMArch, packageMArchValues} from '@/lib/typings'; + +const TerminalComponent = dynamic( + () => import('@/components/terminal-component'), + { + loading: () => , + ssr: false, + } +); + +export default function LogsPage() { + const {march, pkgbase} = useParams<{ + march: PackageMArch; + pkgbase: string; + }>(); + if (!march || !pkgbase) { + return ; + } + if (!packageMArchValues.includes(march)) { + return ( + + ); + } + return ( +
+ +
+ ); +} diff --git a/src/app/dashboard/package-list/page.tsx b/src/app/dashboard/package-list/page.tsx new file mode 100644 index 0000000..67da4c1 --- /dev/null +++ b/src/app/dashboard/package-list/page.tsx @@ -0,0 +1,504 @@ +'use client'; + +import {ColumnDef} from '@tanstack/react-table'; +import {Ellipsis, Logs, RotateCcw, Search, SquareTerminal} from 'lucide-react'; +import Link from 'next/link'; +import { + Fragment, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import {toast} from 'sonner'; +import {useDebounce} from 'use-debounce'; + +import {listPackages, rebuildPackage, searchPackages} from '@/app/actions'; +import Loader from '@/components/loader'; +import {RebuildPackagesDialog} from '@/components/rebuild-packages-dialog'; +import {StatsKPI} from '@/components/stats-kpi'; +import {Badge} from '@/components/ui/badge'; +import {Button} from '@/components/ui/button'; +import {Card} from '@/components/ui/card'; +import {Checkbox} from '@/components/ui/checkbox'; +import {ComboBox} from '@/components/ui/combobox'; +import {DataTable} from '@/components/ui/data-table'; +import {DataTableColumnHeader} from '@/components/ui/data-table-column-header'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import {Input} from '@/components/ui/input'; +import {useSidebar} from '@/components/ui/sidebar'; +import {useGenericShortcutListener} from '@/hooks/use-keyboard-shortcut-listener'; +import { + BasePackageWithIDList, + ListPackageResponse, + Package, + PackageMArch, + packageMArchValues, + PackageRepo, + packageRepoValues, + PackageStatus, + packageStatusValues, +} from '@/lib/typings'; +import {packageStatusToIcon} from '@/lib/utils'; + +export default function PackageListPage() { + const {activeServer} = useSidebar(); + const [data, setData] = useState(null); + const [error, setError] = useState(null); + const [pageSize, setPageSize] = useState(20); + const [currentPage, setCurrentPage] = useState(1); + const [searchQuery, setSearchQuery] = useState(''); + const [debouncedSearchQuery] = useDebounce(searchQuery, 800); + const [manual, setManual] = useState(true); + const [marchFilter, setMarchFilter] = useState([]); + const [repoFilter, setRepoFilter] = useState([]); + const [statusFilter, setStatusFilter] = useState([]); + const [rebuildPackages, setRebuildPackages] = useState( + [] + ); + const [showRebuildModal, setShowRebuildModal] = useState(false); + const [selectionReset, setSelectionReset] = useState(false); + const onOpenChange = useCallback((state: boolean) => { + if (!state) { + setRebuildPackages([]); + setSelectionReset(old => !old); + } + setShowRebuildModal(state); + }, []); + const primarySearchFilterInputRef = useRef(null); + const primarySearchFilterShortcutCallback = useCallback(() => { + if (primarySearchFilterInputRef.current) { + primarySearchFilterInputRef.current.focus(); + } + }, []); + + useGenericShortcutListener('/', primarySearchFilterShortcutCallback, true); + + const columns: ColumnDef[] = useMemo( + () => [ + { + cell: ({row}) => ( + { + row.toggleSelected(!!value); + if (value === true) { + setRebuildPackages(old => [ + ...old, + { + id: row.id, + march: row.original.march, + pkgbase: row.original.pkgbase, + repository: row.original.repository, + }, + ]); + } else if (value === false) { + setRebuildPackages(old => old.filter(pkg => pkg.id !== row.id)); + } + }} + /> + ), + enableHiding: false, + enableSorting: false, + header: ({table}) => ( + { + table.toggleAllPageRowsSelected(!!value); + if (value === true) { + setRebuildPackages(old => { + const newPkgs: BasePackageWithIDList = []; + table.getCoreRowModel().rows.forEach(row => { + if (old.findIndex(pkg => pkg.id === row.id) === -1) { + newPkgs.push({ + id: row.id, + march: row.original.march, + pkgbase: row.original.pkgbase, + repository: row.original.repository, + }); + } + }); + return [...old, ...newPkgs]; + }); + } else if (value === false) { + const removePkgs = table + .getSelectedRowModel() + .rows.map(row => row.id); + setRebuildPackages(old => + old.filter(pkg => !removePkgs.includes(pkg.id)) + ); + } + }} + /> + ), + id: 'select', + }, + { + cell: ({row}) => ( + + {row.original.pkgname} ({row.original.pkgbase}) + + ), + header: ({column}) => ( + + ), + id: 'name', + }, + { + cell: ({row}) => ( + {row.original.repository} + ), + header: ({column}) => ( + + ), + id: 'repository', + }, + { + cell: ({row}) => ( + {row.original.march} + ), + header: ({column}) => ( + + ), + id: 'arch', + }, + { + cell: ({row}) => ( + {row.original.version} + ), + header: ({column}) => ( + + ), + id: 'version', + }, + { + cell: ({row}) => ( + {row.original.repo_version} + ), + header: ({column}) => ( + + ), + id: 'repo version', + }, + { + cell: ({row}) => ( +
+ + {packageStatusToIcon(row.original.status)} + {row.original.status} + +
+ ), + header: ({column}) => ( + + ), + id: 'status', + }, + { + cell: ({row}) => { + const date = new Date(row.original.updated * 1000); + return ( + + {date.toLocaleDateString()}, {date.toLocaleTimeString()} + + ); + }, + header: ({column}) => ( + + ), + id: 'updated at', + }, + { + cell: ({row}) => ( + + + + + + { + const toastId = toast.loading( + `Requesting rebuild for PkgBase: ${row.original.pkgbase} MArch: ${row.original.march} Repo: ${row.original.repository}...` + ); + rebuildPackage( + row.original.pkgbase, + row.original.march, + row.original.repository + ).then(response => { + if ('error' in response && response.error) { + toast.error( + `Failed to rebuild package: ${response.error}`, + { + closeButton: true, + duration: Infinity, + id: toastId, + } + ); + } else if ('track_id' in response && response.track_id) { + toast.success( + `Rebuild request for PkgBase: ${row.original.pkgbase} MArch: ${row.original.march} Repo: ${row.original.repository} has been queued with Track ID: ${response.track_id}.`, + {id: toastId} + ); + } + }); + }} + variant="destructive" + > + Rebuild + + + + + Get Logs + + + + + Get Raw Logs + + + + + ), + id: 'actions', + }, + ], + [] + ); + + const onMarchFilterUpdate = useCallback( + (marches: PackageMArch[]) => setMarchFilter(marches), + [] + ); + const onRepoFilterUpdate = useCallback( + (repos: PackageRepo[]) => setRepoFilter(repos), + [] + ); + const onStatusFilterUpdate = useCallback( + (statuses: PackageStatus[]) => setStatusFilter(statuses), + [] + ); + const statusFilterUpdate = useCallback( + (status: PackageStatus) => + setStatusFilter(old => { + if (old.includes(status)) { + return old.filter(s => s !== status); + } + return [...old, status]; + }), + [] + ); + + useEffect(() => { + setError(null); + if (debouncedSearchQuery) { + return; + } + listPackages({ + current_page: currentPage, + march_filter: marchFilter, + page_size: pageSize, + repo_filter: repoFilter, + status_filter: statusFilter, + }) + .then(response => { + if ('error' in response && response.error) { + setError(response.error); + toast.error(`Failed to fetch package list: ${response.error}`, { + closeButton: true, + duration: Infinity, + }); + } + if ('packages' in response) { + setManual(true); + setData(response); + } + }) + .catch(() => { + setError('Failed to fetch package list, please try again later.'); + toast.error('Failed to fetch package list, please try again later.', { + closeButton: true, + duration: Infinity, + }); + }); + }, [ + activeServer, + currentPage, + debouncedSearchQuery, + marchFilter, + pageSize, + repoFilter, + statusFilter, + ]); + + useEffect(() => { + setData(null); + setError(null); + setCurrentPage(1); + setSearchQuery(''); + setMarchFilter([]); + setRepoFilter([]); + setStatusFilter([]); + setRebuildPackages([]); + }, [activeServer]); + + useEffect(() => { + setError(null); + if (debouncedSearchQuery) { + searchPackages({ + march_filter: marchFilter, + repo_filter: repoFilter, + search: debouncedSearchQuery, + status_filter: statusFilter, + }).then(response => { + if ('error' in response && response.error) { + setError(response.error); + toast.error(`Failed to search packages: ${response.error}`, { + closeButton: true, + duration: Infinity, + }); + } else if (Array.isArray(response)) { + setManual(false); + setData({ + packages: response, + total_packages: response.length, + total_pages: 1, + }); + } + }); + } + }, [debouncedSearchQuery, marchFilter, repoFilter, statusFilter]); + + return ( + + + + {data ? ( + + `${row.pkgbase}-${row.pkgname}-${row.repository}-${row.march}` + } + itemCount={manual ? data.total_packages : undefined} + manualFiltering={manual} + manualPagination={manual} + onPageChange={pageIndex => setCurrentPage(pageIndex + 1)} + onPageSizeChange={pageSize => { + const currentEntryCutoff = Math.min( + (currentPage - 1) * pageSize + 1, + data.total_packages + ); + setCurrentPage(Math.floor(currentEntryCutoff / pageSize)); + setPageSize(pageSize); + }} + pageCount={manual ? data.total_pages : undefined} + resetSelection={selectionReset} + shrinkFirstColumn + viewOptionsAdditionalItems={ + +
+ setSearchQuery(e.target.value)} + placeholder="Search packages..." + ref={primarySearchFilterInputRef} + type="text" + value={searchQuery} + /> +
+
+ {rebuildPackages.length ? ( +
+ +
+ ) : null} +
+ +
+
+ +
+
+ +
+
+
+ } + /> + ) : ( + + )} +
+ ); +} diff --git a/src/app/dashboard/profile/[username]/page.tsx b/src/app/dashboard/profile/[username]/page.tsx new file mode 100644 index 0000000..03c1b8c --- /dev/null +++ b/src/app/dashboard/profile/[username]/page.tsx @@ -0,0 +1,44 @@ +'use client'; +import {useParams} from 'next/navigation'; +import {useEffect, useState} from 'react'; +import {toast} from 'sonner'; + +import {getUser} from '@/app/actions'; +import Loader from '@/components/loader'; +import {Card} from '@/components/ui/card'; +import {useSidebar} from '@/components/ui/sidebar'; +import {UserProfileForm} from '@/components/user-profile-form'; +import {UserProfile} from '@/lib/typings'; + +export default function UserProfilePage() { + const {username} = useParams<{username: string}>(); + const {activeServer} = useSidebar(); + const [user, setUser] = useState(null); + useEffect(() => { + if (!username) { + return; + } + setUser(null); + getUser(username).then(data => { + if ('error' in data) { + toast.error(data.error, { + closeButton: true, + duration: Infinity, + }); + } else { + setUser(data); + } + }); + }, [activeServer, username]); + return ( + +
+ {user ? ( + {}} user={user} /> + ) : ( + + )} +
+
+ ); +} diff --git a/src/app/dashboard/profile/page.tsx b/src/app/dashboard/profile/page.tsx new file mode 100644 index 0000000..85eaf46 --- /dev/null +++ b/src/app/dashboard/profile/page.tsx @@ -0,0 +1,46 @@ +'use client'; +import {useCallback, useEffect, useState} from 'react'; +import {toast} from 'sonner'; + +import {getLoggedInUser} from '@/app/actions'; +import Loader from '@/components/loader'; +import {Card} from '@/components/ui/card'; +import {useSidebar} from '@/components/ui/sidebar'; +import {UserProfileForm} from '@/components/user-profile-form'; +import {UserProfile} from '@/lib/typings'; + +export default function UserProfilePage() { + const {activeServer, doRefresh} = useSidebar(); + const [user, setUser] = useState(null); + const onUserUpdate = useCallback( + (updatedUser: UserProfile) => { + setUser(updatedUser); + doRefresh(); + }, + [doRefresh] + ); + useEffect(() => { + setUser(null); + getLoggedInUser(true).then(data => { + if ('error' in data) { + toast.error(data.error, { + closeButton: true, + duration: Infinity, + }); + } else { + setUser(data); + } + }); + }, [activeServer]); + return ( + +
+ {user ? ( + + ) : ( + + )} +
+
+ ); +} diff --git a/src/app/dashboard/rebuild-queue/page.tsx b/src/app/dashboard/rebuild-queue/page.tsx new file mode 100644 index 0000000..ac1686f --- /dev/null +++ b/src/app/dashboard/rebuild-queue/page.tsx @@ -0,0 +1,420 @@ +'use client'; + +import {ColumnDef, Table} from '@tanstack/react-table'; +import {Ellipsis, Logs, RotateCcw, Search, SquareTerminal} from 'lucide-react'; +import Link from 'next/link'; +import {useCallback, useEffect, useMemo, useState} from 'react'; +import {toast} from 'sonner'; + +import {listRebuildPackages, rebuildPackage} from '@/app/actions'; +import Loader from '@/components/loader'; +import {RebuildPackagesDialog} from '@/components/rebuild-packages-dialog'; +import {Badge} from '@/components/ui/badge'; +import {Button} from '@/components/ui/button'; +import {Card} from '@/components/ui/card'; +import {Checkbox} from '@/components/ui/checkbox'; +import {ComboBox} from '@/components/ui/combobox'; +import {DataTable} from '@/components/ui/data-table'; +import {DataTableColumnHeader} from '@/components/ui/data-table-column-header'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import {useSidebar} from '@/components/ui/sidebar'; +import { + BasePackageWithIDList, + PackageMArch, + packageMArchValues, + PackageRepo, + packageRepoValues, + PackageStatus, + packageStatusValues, + RebuildPackage, + RebuildPackageList, +} from '@/lib/typings'; +import {packageStatusToIcon} from '@/lib/utils'; + +export default function RebuildQueuePackageListPage() { + const {activeServer} = useSidebar(); + const [data, setData] = useState(null); + const [error, setError] = useState(null); + const [rebuildPackages, setRebuildPackages] = useState( + [] + ); + const [showRebuildModal, setShowRebuildModal] = useState(false); + const [selectionReset, setSelectionReset] = useState(false); + const onOpenChange = useCallback((state: boolean) => { + if (!state) { + setRebuildPackages([]); + setSelectionReset(old => !old); + } + setShowRebuildModal(state); + }, []); + + const columns: ColumnDef[] = useMemo( + () => [ + { + cell: ({row}) => ( + { + row.toggleSelected(!!value); + if (value === true) { + setRebuildPackages(old => [ + ...old, + { + id: row.id, + march: row.original.march, + pkgbase: row.original.pkgbase, + repository: row.original.repository, + }, + ]); + } else if (value === false) { + setRebuildPackages(old => old.filter(pkg => pkg.id !== row.id)); + } + }} + /> + ), + enableHiding: false, + enableSorting: false, + header: ({table}) => ( + { + table.toggleAllPageRowsSelected(!!value); + if (value === true) { + setRebuildPackages(old => { + const newPkgs: BasePackageWithIDList = []; + table.getRowModel().rows.forEach(row => { + if (old.findIndex(pkg => pkg.id === row.id) === -1) { + newPkgs.push({ + id: row.id, + march: row.original.march, + pkgbase: row.original.pkgbase, + repository: row.original.repository, + }); + } + }); + return [...old, ...newPkgs]; + }); + } else if (value === false) { + const removePkgs = table + .getSelectedRowModel() + .rows.map(row => row.id); + setRebuildPackages(old => + old.filter(pkg => !removePkgs.includes(pkg.id)) + ); + } + }} + /> + ), + id: 'select', + }, + { + accessorKey: 'pkgbase', + cell: ({row}) => ( + {row.original.pkgbase} + ), + filterFn: 'includesString', + header: ({column}) => ( + + ), + id: 'pkgbase', + }, + { + cell: ({row}) => ( + {row.original.repository} + ), + filterFn: (row, _, filterValue) => { + if (Array.isArray(filterValue) && filterValue.length) { + return filterValue.includes(row.original.repository); + } + return true; + }, + header: ({column}) => ( + + ), + id: 'repository', + }, + { + cell: ({row}) => ( + {row.original.march} + ), + filterFn: (row, _, filterValue) => { + if (Array.isArray(filterValue) && filterValue.length) { + return filterValue.includes(row.original.march); + } + return true; + }, + header: ({column}) => ( + + ), + id: 'arch', + }, + { + cell: ({row}) => ( +
+ + {packageStatusToIcon(row.original.status)} + {row.original.status} + +
+ ), + filterFn: (row, _, filterValue) => { + if (Array.isArray(filterValue) && filterValue.length) { + return filterValue.includes(row.original.status); + } + return true; + }, + header: ({column}) => ( + + ), + id: 'status', + }, + { + accessorKey: 'updated', + cell: ({row}) => { + const date = new Date(row.original.updated); + return ( + + {date.toLocaleDateString()}, {date.toLocaleTimeString()} + + ); + }, + enableSorting: true, + header: ({column}) => ( + + ), + id: 'updated at', + }, + { + cell: ({row}) => ( + + + + + + { + const toastId = toast.loading( + `Requesting rebuild for PkgBase: ${row.original.pkgbase} MArch: ${row.original.march} Repo: ${row.original.repository}...` + ); + rebuildPackage( + row.original.pkgbase, + row.original.march, + row.original.repository + ).then(response => { + if ('error' in response && response.error) { + toast.error( + `Failed to rebuild package: ${response.error}`, + { + closeButton: true, + duration: Infinity, + id: toastId, + } + ); + } else if ('track_id' in response && response.track_id) { + toast.success( + `Rebuild request for PkgBase: ${row.original.pkgbase} MArch: ${row.original.march} Repo: ${row.original.repository} has been queued with Track ID: ${response.track_id}.`, + {id: toastId} + ); + } + }); + }} + variant="destructive" + > + Rebuild + + + + + Get Logs + + + + + Get Raw Logs + + + + + ), + id: 'actions', + }, + ], + [] + ); + + useEffect(() => { + setError(null); + setData(null); + listRebuildPackages() + .then(response => { + if ('error' in response && response.error) { + setError(response.error); + toast.error(`Failed to fetch package list: ${response.error}`, { + closeButton: true, + duration: Infinity, + }); + } else if (Array.isArray(response)) { + setData(response); + } + }) + .catch(() => { + setError('Failed to fetch package list, please try again later.'); + toast.error('Failed to fetch package list, please try again later.', { + closeButton: true, + duration: Infinity, + }); + }); + }, [activeServer]); + + const customFilters = useMemo( + () => [ + (table: Table) => ( +
+ + table.getColumn('arch')?.setFilterValue(marches) + } + searchNoResultsText="No architectures found" + searchPlaceholder="Search architectures..." + selectedItems={ + (table.getColumn('arch')?.getFilterValue() ?? + []) as PackageMArch[] + } + title="Architecture" + /> +
+ ), + (table: Table) => ( +
+ + table.getColumn('repository')?.setFilterValue(repos) + } + searchNoResultsText="No repositories found" + searchPlaceholder="Search repositories..." + selectedItems={ + (table.getColumn('repository')?.getFilterValue() ?? + []) as PackageRepo[] + } + title="Repository" + /> +
+ ), + (table: Table) => ( +
+ + table.getColumn('status')?.setFilterValue(statuses) + } + searchNoResultsText="No statuses found" + searchPlaceholder="Search statuses..." + selectedItems={ + (table.getColumn('status')?.getFilterValue() ?? + []) as PackageStatus[] + } + title="Status" + /> +
+ ), + ], + [] + ); + const filters = useMemo( + () => [ + { + icon: Search, + id: 'pkgbase', + isPrimary: true, + placeholder: 'Search packages...', + }, + ], + [] + ); + const initialSortingState = useMemo( + () => [ + { + desc: true, + id: 'updated at', + }, + ], + [] + ); + + return ( + + + {data ? ( + + `${row.pkgbase}-${row.pkgbase}-${row.repository}-${row.march}` + } + initialSortingState={initialSortingState} + resetSelection={selectionReset} + shrinkFirstColumn + viewOptionsAdditionalItems={ + rebuildPackages.length ? ( +
+ +
+ ) : null + } + /> + ) : ( + + )} +
+ ); +} diff --git a/src/app/dashboard/repo-actions/page.tsx b/src/app/dashboard/repo-actions/page.tsx new file mode 100644 index 0000000..88242f2 --- /dev/null +++ b/src/app/dashboard/repo-actions/page.tsx @@ -0,0 +1,229 @@ +'use client'; + +import { + IconAlertCircleFilled, + IconCircleCheckFilled, +} from '@tabler/icons-react'; +import {ColumnDef} from '@tanstack/react-table'; +import {ChevronDown} from 'lucide-react'; +import {useCallback, useEffect, useState} from 'react'; +import {toast} from 'sonner'; + +import {listRepoActions} from '@/app/actions'; +import Loader from '@/components/loader'; +import {Badge} from '@/components/ui/badge'; +import {Card} from '@/components/ui/card'; +import {ComboBox} from '@/components/ui/combobox'; +import {DataTable} from '@/components/ui/data-table'; +import {DataTableColumnHeader} from '@/components/ui/data-table-column-header'; +import {useSidebar} from '@/components/ui/sidebar'; +import { + PackageMArch, + packageMArchValues, + PackageRepo, + packageRepoValues, + ParsedRepoAction, + ParsedRepoActionsResponse, +} from '@/lib/typings'; +import {repoActionTypeToIcon} from '@/lib/utils'; + +const columns: ColumnDef[] = [ + { + cell: ({row}) => { + return row.getCanExpand() ? ( + + ) : ( + '' + ); + }, + id: 'expander', + }, + { + cell: ({row}) => ( + + ), + header: ({column}) => ( + + ), + id: 'packages', + }, + { + cell: ({row}) => ( + + {repoActionTypeToIcon(row.original.action_type)}{' '} + {row.original.action_type} + + ), + header: ({column}) => ( + + ), + id: 'action', + }, + { + cell: ({row}) => ( + + {row.original.status ? ( + + ) : ( + + )} + {row.original.status ? 'Success' : 'Failed'} + + ), + header: ({column}) => ( + + ), + id: 'status', + }, + { + cell: ({row}) => ( + {row.original.repository} + ), + header: ({column}) => ( + + ), + id: 'repository', + }, + { + cell: ({row}) => {row.original.march}, + header: ({column}) => ( + + ), + id: 'arch', + }, + { + cell: ({row}) => { + const date = new Date(row.original.updated * 1000); + return ( + + {date.toLocaleDateString()}, {date.toLocaleTimeString()} + + ); + }, + header: ({column}) => ( + + ), + id: 'updated at', + }, +]; + +export default function RepoActionsPage() { + const {activeServer} = useSidebar(); + const [data, setData] = useState(null); + const [error, setError] = useState(null); + const [pageSize, setPageSize] = useState(20); + const [currentPage, setCurrentPage] = useState(1); + const [marchFilter, setMarchFilter] = useState([]); + const [repoFilter, setRepoFilter] = useState([]); + + const onMarchFilterUpdate = useCallback( + (marches: PackageMArch[]) => setMarchFilter(marches), + [] + ); + const onRepoFilterUpdate = useCallback( + (repos: PackageRepo[]) => setRepoFilter(repos), + [] + ); + + useEffect(() => { + setError(null); + listRepoActions({ + current_page: currentPage, + march: marchFilter, + page_size: pageSize, + repo: repoFilter, + }) + .then(response => { + if ('error' in response && response.error) { + setError(response.error); + toast.error(`Failed to fetch repo actions: ${response.error}`, { + closeButton: true, + duration: Infinity, + }); + } + if ('actions' in response) { + setData(response); + } + }) + .catch(() => { + setError('Failed to fetch repo actions, please try again later.'); + toast.error('Failed to fetch repo actions, please try again later.', { + closeButton: true, + duration: Infinity, + }); + }); + }, [activeServer, currentPage, pageSize, marchFilter, repoFilter]); + + useEffect(() => { + setData(null); + setError(null); + setCurrentPage(1); + }, [activeServer]); + + return ( + + {data ? ( + row.parsedPackages as ParsedRepoAction[]} + itemCount={data.total_actions} + manualFiltering + manualPagination + onPageChange={pageIndex => setCurrentPage(pageIndex + 1)} + onPageSizeChange={pageSize => { + const currentEntryCutoff = Math.min( + (currentPage - 1) * pageSize + 1, + data.total_actions + ); + setCurrentPage(Math.floor(currentEntryCutoff / pageSize)); + setPageSize(pageSize); + }} + shrinkFirstColumn + viewOptionsAdditionalItems={ +
+
+ +
+
+ +
+
+ } + /> + ) : ( + + )} +
+ ); +} diff --git a/src/app/dashboard/statistics/page.tsx b/src/app/dashboard/statistics/page.tsx new file mode 100644 index 0000000..d77661c --- /dev/null +++ b/src/app/dashboard/statistics/page.tsx @@ -0,0 +1,159 @@ +'use client'; + +import {useEffect, useMemo, useState} from 'react'; + +import {getPackageStats} from '@/app/actions'; +import { + CategoryStatsDonutChart, + MonthlyStatsAreaChart, +} from '@/components/charts'; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import {useSidebar} from '@/components/ui/sidebar'; +import { + MonthlyChartData, + PackageStatsList, + PackageStatsType, + PackageStatus, +} from '@/lib/typings'; + +export default function StatisticsPage() { + return ( +
+ + +
+ ); +} + +function CategoryChart() { + const {activeServer} = useSidebar(); + const [categoryChartData, setCategoryChartData] = useState( + [] + ); + + useEffect(() => { + setCategoryChartData([]); + getPackageStats(PackageStatsType.CATEGORY).then(response => { + if (Array.isArray(response)) { + setCategoryChartData(response); + } + }); + }, [activeServer]); + + return ( + + +
+ Stats by Month + + Showing total packages status by month + +
+
+ + + +
+ ); +} + +function MonthlyChart() { + const {activeServer} = useSidebar(); + const [selectedYear, setSelectedYear] = useState( + new Date().getFullYear().toString() + ); + const [years, setYears] = useState([]); + const [monthlyChartData, setMonthlyChartData] = useState( + [] + ); + const filteredMonthlyChartData = useMemo( + () => + monthlyChartData.filter(x => x.reporting_month.startsWith(selectedYear)), + [monthlyChartData, selectedYear] + ); + useEffect(() => { + setMonthlyChartData([]); + setYears([]); + setSelectedYear(new Date().getFullYear().toString()); + getPackageStats(PackageStatsType.MONTH).then(response => { + if (Array.isArray(response)) { + const chartDataMap = new Map< + string, + Record & { + reporting_month: string; + } + >(); + const years = new Set(); + + response.forEach(item => { + const month = item.reporting_month; + if (!chartDataMap.has(month)) { + chartDataMap.set(month, { + [PackageStatus.BUILDING]: 0, + [PackageStatus.DONE]: 0, + [PackageStatus.FAILED]: 0, + [PackageStatus.LATEST]: 0, + [PackageStatus.QUEUED]: 0, + [PackageStatus.SKIPPED]: 0, + [PackageStatus.UNKNOWN]: 0, + reporting_month: month, + }); + } + const statusMap = chartDataMap.get(month)!; + statusMap[item.status_name] = item.package_count; + years.add(month.slice(0, 4)); + }); + + setMonthlyChartData( + Array.from(chartDataMap.values()).sort((a, b) => + a.reporting_month.localeCompare(b.reporting_month) + ) + ); + setYears(Array.from(years).sort((a, b) => b.localeCompare(a))); + } + }); + }, [activeServer]); + return ( + + +
+ Stats by Month + + Showing total packages status by month + +
+ +
+ + + +
+ ); +} diff --git a/app/favicon.ico b/src/app/favicon.ico similarity index 100% rename from app/favicon.ico rename to src/app/favicon.ico diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 0000000..77f07b0 --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,165 @@ +@import 'tailwindcss'; +@import 'tw-animate-css'; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --animate-shine: shine var(--duration) infinite linear; + @keyframes shine { + 0% { + background-position: 0% 0%; + } + 50% { + background-position: 100% 100%; + } + to { + background-position: 0% 0%; + } + } + @keyframes shine { + 0% { + background-position: 0% 0%; + } + 50% { + background-position: 100% 100%; + } + to { + background-position: 0% 0%; + } + } +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + + :root { + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --chart-6: oklch(0.488 0.243 264.376); + --chart-7: oklch(0.696 0.17 162.48); + } + + .dark { + --chart-1: oklch(0.68 0.15 237); + --chart-2: oklch(0.59 0.20 277); + --chart-3: oklch(0.66 0.21 354); + --chart-4: oklch(0.70 0.15 162); + --chart-5: oklch(0.80 0.16 86); + --chart-6: oklch(0.70 0.19 48); + --chart-7: oklch(0.71 0.02 261); + } +} diff --git a/app/icon.png b/src/app/icon.png similarity index 100% rename from app/icon.png rename to src/app/icon.png diff --git a/app/layout.tsx b/src/app/layout.tsx similarity index 57% rename from app/layout.tsx rename to src/app/layout.tsx index d28951c..c08695b 100644 --- a/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,12 +1,21 @@ import type {Metadata, Viewport} from 'next'; -import {Inter} from 'next/font/google'; -import {ToastContainer} from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; +import {Geist, Geist_Mono} from 'next/font/google'; + +import {ThemeProvider} from '@/components/theme-provider'; +import {Toaster} from '@/components/ui/sonner'; import './globals.css'; -const inter = Inter({subsets: ['latin']}); +const geistSans = Geist({ + subsets: ['latin'], + variable: '--font-geist-sans', +}); + +const geistMono = Geist_Mono({ + subsets: ['latin'], + variable: '--font-geist-mono', +}); const description = 'CachyOS Builder Dashboard'; const name = 'CachyOS Builder Dashboard'; @@ -44,22 +53,14 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + - - {children} + + {children} + + ); diff --git a/app/manifest.ts b/src/app/manifest.ts similarity index 100% rename from app/manifest.ts rename to src/app/manifest.ts diff --git a/src/app/page.tsx b/src/app/page.tsx new file mode 100644 index 0000000..8c3e680 --- /dev/null +++ b/src/app/page.tsx @@ -0,0 +1,11 @@ +import {LoginForm} from '@/components/login-form'; + +export default function Page() { + return ( +
+
+ +
+
+ ); +} diff --git a/app/robots.ts b/src/app/robots.ts similarity index 100% rename from app/robots.ts rename to src/app/robots.ts diff --git a/src/app/validate/page.tsx b/src/app/validate/page.tsx new file mode 100644 index 0000000..3a92d28 --- /dev/null +++ b/src/app/validate/page.tsx @@ -0,0 +1,22 @@ +'use client'; + +import {useRouter} from 'next/navigation'; +import {useEffect} from 'react'; + +import Loader from '@/components/loader'; + +export default function Page() { + const router = useRouter(); + useEffect(() => { + setTimeout(() => { + router.push('/dashboard/package-list'); + }, 8000); + }, [router]); + return ( +
+
+ +
+
+ ); +} diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx new file mode 100644 index 0000000..7d9520b --- /dev/null +++ b/src/components/app-sidebar.tsx @@ -0,0 +1,91 @@ +'use client'; + +import {Activity, Logs, Package, PieChart, Repeat2} from 'lucide-react'; +import * as React from 'react'; +import {toast} from 'sonner'; + +import {getAccessibleServers, getLoggedInUser} from '@/app/actions'; +import {NavMain} from '@/components/nav-main'; +import {NavUser} from '@/components/nav-user'; +import {ServerSwitcher} from '@/components/server-switcher'; +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarRail, + useSidebar, +} from '@/components/ui/sidebar'; +import CachyBuilderClient from '@/lib/CachyBuilderClient'; +import {UserData} from '@/lib/typings'; + +const items = [ + { + icon: Package, + name: 'Package List', + url: '/dashboard/package-list', + }, + { + icon: Repeat2, + name: 'Rebuild Queue', + url: '/dashboard/rebuild-queue', + }, + { + icon: Logs, + name: 'Audit Logs', + url: '/dashboard/audit-logs', + }, + { + icon: Activity, + name: 'Repo Actions', + url: '/dashboard/repo-actions', + }, + { + icon: PieChart, + name: 'Statistics', + url: '/dashboard/statistics', + }, +]; +export function AppSidebar({...props}: React.ComponentProps) { + const {activeServer, refresh} = useSidebar(); + const [servers, setServers] = React.useState( + CachyBuilderClient.servers.map(server => ({ + accessible: true, + active: server.default, + description: server.description, + name: server.name, + })) + ); + const [user, setUser] = React.useState({ + displayName: 'Loading...', + profile_picture_url: '/cachyos-logo.svg', + username: 'Loading...', + }); + React.useEffect(() => { + getAccessibleServers().then(data => setServers(data)); + getLoggedInUser(false).then(data => { + if ('error' in data) { + toast.error(data.error, { + closeButton: true, + duration: Infinity, + }); + } else { + setUser(data); + } + }); + }, [activeServer, refresh]); + return ( + + + + + + + + + + + + + ); +} diff --git a/src/components/charts.tsx b/src/components/charts.tsx new file mode 100644 index 0000000..8a27a03 --- /dev/null +++ b/src/components/charts.tsx @@ -0,0 +1,170 @@ +'use client'; + +import {useMemo} from 'react'; +import { + Area, + AreaChart, + CartesianGrid, + Label, + Pie, + PieChart, + XAxis, +} from 'recharts'; + +import { + ChartConfig, + ChartConfigValue, + ChartContainer, + ChartLegend, + ChartLegendContent, + ChartTooltip, + ChartTooltipContent, +} from '@/components/ui/chart'; +import { + MonthlyChartData, + PackageStatsList, + PackageStatus, + packageStatusValues, +} from '@/lib/typings'; + +const chartConfig: Record = { + BUILDING: { + color: 'var(--chart-1)', + label: 'Building', + }, + DONE: { + color: 'var(--chart-2)', + label: 'Done', + }, + FAILED: { + color: 'var(--chart-3)', + label: 'Failed', + }, + LATEST: { + color: 'var(--chart-4)', + label: 'Latest', + }, + QUEUED: { + color: 'var(--chart-5)', + label: 'Queued', + }, + SKIPPED: { + color: 'var(--chart-6)', + label: 'Skipped', + }, + UNKNOWN: { + color: 'var(--chart-7)', + label: 'Unknown', + }, +} satisfies ChartConfig; + +export function CategoryStatsDonutChart({ + chartData, +}: Readonly<{chartData: PackageStatsList}>) { + const processedChartData = useMemo( + () => + chartData + .filter(item => item.package_count > 0) + .map(item => ({ + ...item, + fill: chartConfig[item.status_name].color, + })), + [chartData] + ); + const totalPackages = useMemo( + () => chartData.reduce((acc, item) => acc + item.package_count, 0), + [chartData] + ); + return ( + + + } /> + + {totalPackages && ( + + } + /> + + + ); +} + +export function MonthlyStatsAreaChart({ + chartData, +}: Readonly<{ + chartData: MonthlyChartData; +}>) { + return ( + + + + + } cursor={false} /> + + {packageStatusValues.map(status => ( + + + + + ))} + + {packageStatusValues.map(status => ( + + ))} + } /> + + + ); +} diff --git a/src/components/command-menu.tsx b/src/components/command-menu.tsx new file mode 100644 index 0000000..c228da6 --- /dev/null +++ b/src/components/command-menu.tsx @@ -0,0 +1,324 @@ +'use client'; +import { + Loader, + RotateCcw, + ScanSearch, + SquareTerminal, + User, +} from 'lucide-react'; +import {useRouter} from 'next/navigation'; +import { + Fragment, + KeyboardEventHandler, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import {toast} from 'sonner'; +import {useDebounce} from 'use-debounce'; + +import {getUser, rebuildPackage, searchPackages} from '@/app/actions'; +import {Avatar, AvatarFallback, AvatarImage} from '@/components/ui/avatar'; +import { + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandLoading, + CommandSeparator, +} from '@/components/ui/command'; +import {useSidebar} from '@/components/ui/sidebar'; +import {useGenericShortcutListener} from '@/hooks/use-keyboard-shortcut-listener'; +import {Package, PackageList, UserProfile} from '@/lib/typings'; + +enum CommandMenuOptions { + REBUILD_PACKAGE, + NO_OPTION_SELECTED, + GET_PACKAGE_LOGS, + USER_PROFILE, +} + +export function CommandMenu() { + const router = useRouter(); + const {activeServer} = useSidebar(); + const [open, setOpen] = useState(false); + const [loading, setLoading] = useState(false); + const [data, setData] = useState(null); + const [searchQuery, setSearchQuery] = useState(''); + const [debouncedSearchQuery] = useDebounce(searchQuery, 800); + const ref = useRef(null); + const [selectedOption, setSelectedOption] = useState( + CommandMenuOptions.NO_OPTION_SELECTED + ); + const [searchedUser, setSearchedUser] = useState(null); + const placeholder = useMemo(() => { + switch (selectedOption) { + case CommandMenuOptions.GET_PACKAGE_LOGS: + return 'Search for a package to get logs ..'; + case CommandMenuOptions.REBUILD_PACKAGE: + return 'Search for a package to rebuild...'; + case CommandMenuOptions.USER_PROFILE: + return 'Type the username or hit enter to view your profile'; + default: + return 'Type a command or search...'; + } + }, [selectedOption]); + const optionSelectCallback = useCallback( + (option: CommandMenuOptions) => { + if (selectedOption === option) { + setSelectedOption(CommandMenuOptions.NO_OPTION_SELECTED); + } else { + setSelectedOption(option); + } + if (ref.current) { + setSearchQuery(''); + ref.current.focus(); + } + }, + [selectedOption] + ); + const closeCommandMenu = useCallback(() => { + setOpen(false); + setSearchQuery(''); + setSearchedUser(null); + setData(null); + setSelectedOption(CommandMenuOptions.NO_OPTION_SELECTED); + }, []); + const packageSelectCallback = useCallback( + (pkg: Package) => { + if (selectedOption === CommandMenuOptions.GET_PACKAGE_LOGS) { + closeCommandMenu(); + router.push(`/dashboard/logs/${pkg.march}/${pkg.pkgbase}`); + } else if (selectedOption === CommandMenuOptions.REBUILD_PACKAGE) { + const toastId = toast.loading( + `Requesting rebuild for PkgBase: ${pkg.pkgbase} MArch: ${pkg.march} Repo: ${pkg.repository}...` + ); + rebuildPackage(pkg.pkgbase, pkg.march, pkg.repository) + .then(response => { + if ('error' in response && response.error) { + toast.error(`Failed to rebuild package: ${response.error}`, { + closeButton: true, + duration: Infinity, + id: toastId, + }); + } else if ('track_id' in response && response.track_id) { + toast.success( + `Rebuild request for PkgBase: ${pkg.pkgbase} MArch: ${pkg.march} Repo: ${pkg.repository} has been queued with Track ID: ${response.track_id}.`, + {id: toastId} + ); + } + }) + .catch(error => { + toast.error( + `Failed to rebuild package: ${(error as Error)?.message ?? 'Something went wrong, please try again later'}`, + { + closeButton: true, + duration: Infinity, + id: toastId, + } + ); + }); + } + }, + [closeCommandMenu, router, selectedOption] + ); + const userProfileSelectCallback = useCallback( + (user: string) => { + closeCommandMenu(); + router.push(`/dashboard/profile/${user}`); + }, + [closeCommandMenu, router] + ); + const keyDownCallback: KeyboardEventHandler = useCallback( + e => { + if (e.key.toLowerCase() === 'backspace' && !searchQuery) { + setSelectedOption(CommandMenuOptions.NO_OPTION_SELECTED); + } + }, + [searchQuery] + ); + + useEffect(() => { + if ( + debouncedSearchQuery && + selectedOption !== CommandMenuOptions.NO_OPTION_SELECTED && + selectedOption !== CommandMenuOptions.USER_PROFILE + ) { + setLoading(true); + searchPackages({ + search: debouncedSearchQuery, + }) + .then(response => { + if ('error' in response && response.error) { + toast.error(`Failed to search packages: ${response.error}`, { + closeButton: true, + duration: Infinity, + }); + } else if (Array.isArray(response)) { + setData(response); + } + }) + .finally(() => { + setLoading(false); + }); + } else if ( + debouncedSearchQuery && + selectedOption === CommandMenuOptions.USER_PROFILE + ) { + setLoading(true); + getUser(debouncedSearchQuery) + .then(response => { + if ('username' in response && response.username) { + setSearchedUser({ + ...response, + profile_picture_url: + response.profile_picture_url ?? '/cachyos-logo.svg', + }); + } + }) + .finally(() => { + setLoading(false); + }); + } + }, [activeServer, debouncedSearchQuery, selectedOption]); + + useEffect(() => { + if (!debouncedSearchQuery && data) { + setData(null); + } else if (!debouncedSearchQuery && searchedUser) { + setSearchedUser(null); + } + }, [data, debouncedSearchQuery, searchedUser]); + + useEffect(() => { + return () => { + setSearchedUser(null); + setData(null); + setSearchQuery(''); + setSelectedOption(CommandMenuOptions.NO_OPTION_SELECTED); + }; + }, []); + + useGenericShortcutListener('k', () => setOpen(value => !value)); + useGenericShortcutListener('/', () => ref && ref.current?.focus(), true); + + return ( + + + + {!loading && debouncedSearchQuery && ( + No results found. + )} + {!data && selectedOption !== CommandMenuOptions.NO_OPTION_SELECTED && ( + +
+ {loading ? ( + + + + Searching for{' '} + {selectedOption === CommandMenuOptions.USER_PROFILE + ? 'users' + : 'packages'} + ... + + + ) : ( + + + + Start typing to search for{' '} + {selectedOption === CommandMenuOptions.USER_PROFILE + ? 'users' + : 'packages'} + ... + + + )} +
+
+ )} + {data && ( + + {data.map(pkg => ( + packageSelectCallback(pkg)} + value={`${pkg.pkgname} ${pkg.pkgbase} ${pkg.repository} ${pkg.march}`} + > + Package: {pkg.pkgname} ({pkg.pkgbase}) in {pkg.repository} ( + {pkg.march}) + + ))} + + )} + {searchedUser && ( + + userProfileSelectCallback(searchedUser.username)} + value={searchedUser.username} + > + + + + {searchedUser.username + .split(' ') + .map(x => x.at(0)) + .join('') + .toUpperCase()} + + + User: @{searchedUser.username}{' '} + {searchedUser.display_name + ? `(${searchedUser.display_name})` + : ''} + + + )} + + + + optionSelectCallback(CommandMenuOptions.REBUILD_PACKAGE) + } + > + + Rebuild Package + + + optionSelectCallback(CommandMenuOptions.GET_PACKAGE_LOGS) + } + > + + Get Package Logs + + + optionSelectCallback(CommandMenuOptions.USER_PROFILE) + } + > + + User Profile + + +
+
+ ); +} diff --git a/src/components/header-breadcrumbs.tsx b/src/components/header-breadcrumbs.tsx new file mode 100644 index 0000000..d870029 --- /dev/null +++ b/src/components/header-breadcrumbs.tsx @@ -0,0 +1,40 @@ +'use client'; + +import {usePathname} from 'next/navigation'; +import {Fragment, useMemo} from 'react'; + +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from '@/components/ui/breadcrumb'; + +export function HeaderBreadcrumbs() { + const pathname = usePathname(); + const breadCrumbs = useMemo( + () => pathname.replace('/dashboard/', '').split('-').join(' ').split('/'), + [pathname] + ); + + return ( + + + + CachyOS Builder Dashboard + + {breadCrumbs.map(breadCrumb => ( + + + + + {breadCrumb} + + + + ))} + + + ); +} diff --git a/src/components/kpi-card.tsx b/src/components/kpi-card.tsx new file mode 100644 index 0000000..70e2e19 --- /dev/null +++ b/src/components/kpi-card.tsx @@ -0,0 +1,59 @@ +'use client'; + +import {useMemo} from 'react'; + +import {Badge} from '@/components/ui/badge'; +import {Card} from '@/components/ui/card'; +import { + ProgressCircle, + ProgressCircleVariants, +} from '@/components/ui/progress-circle'; + +export interface KPICardProps { + badgeClassName: string; + count: number; + item: T; + maxCount: number; + onClick?: (item: T) => void; + progressCircleVariant: ProgressCircleVariants; +} + +export function KPICard({ + badgeClassName, + count, + item, + maxCount, + onClick, + progressCircleVariant, +}: Readonly>) { + const progress = useMemo( + () => parseFloat(((count / maxCount) * 100).toFixed(2)), + [count, maxCount] + ); + return ( + onClick?.(item)} + > +
+

+ + {item.toLocaleLowerCase()} packages + +

+ {progress}% +
+
+

+ {count} + + /{maxCount} + +

+ + {progress}% + +
+
+ ); +} diff --git a/components/Loader.tsx b/src/components/loader.tsx similarity index 95% rename from components/Loader.tsx rename to src/components/loader.tsx index 7009442..ebef9ca 100644 --- a/components/Loader.tsx +++ b/src/components/loader.tsx @@ -1,19 +1,5 @@ import Image from 'next/image'; -export function LogoLoader({animate = true}: Readonly<{animate?: boolean}>) { - return ( - CachyOS Logo - ); -} - export default function Loader({ animate = true, text, @@ -27,3 +13,17 @@ export default function Loader({
); } + +export function LogoLoader({animate = true}: Readonly<{animate?: boolean}>) { + return ( + CachyOS Logo + ); +} diff --git a/src/components/login-form.tsx b/src/components/login-form.tsx new file mode 100644 index 0000000..fbde444 --- /dev/null +++ b/src/components/login-form.tsx @@ -0,0 +1,241 @@ +'use client'; + +import {zodResolver} from '@hookform/resolvers/zod'; +import {Turnstile} from '@marsidev/react-turnstile'; +import Image from 'next/image'; +import {useRouter} from 'next/navigation'; +import {useCallback, useEffect, useState} from 'react'; +import {useForm} from 'react-hook-form'; +import {toast} from 'sonner'; + +import {isLoggedIn, login} from '@/app/actions'; +import {Button} from '@/components/ui/button'; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form'; +import {Input} from '@/components/ui/input'; +import {LoginRequest, LoginRequestSchema} from '@/lib/typings'; +import {cn} from '@/lib/utils'; + +export function LoginForm({className, ...props}: React.ComponentProps<'div'>) { + const router = useRouter(); + const [error, setError] = useState(null); + const [warning, setWarning] = useState(null); + const [submitting, setSubmitting] = useState(false); + const [canRedirect, setCanRedirect] = useState(false); + useEffect(() => { + isLoggedIn().then(redirect => { + if (redirect) { + router.push('/dashboard/package-list'); + } + }); + }, [router]); + const form = useForm({ + defaultValues: { + password: '', + turnstileToken: '', + username: '', + }, + resolver: zodResolver(LoginRequestSchema), + }); + const onSubmit = useCallback( + (data: LoginRequest) => { + if (submitting) { + return; + } + setSubmitting(true); + setCanRedirect(false); + setError(null); + setWarning(null); + const toastId = toast.loading('Logging in...'); + login(data) + .then(res => { + if (res.error) { + setError(res.error); + toast.error('Failed to login with provided credentials', { + closeButton: true, + duration: Infinity, + id: toastId, + }); + } else if (res.warning) { + setWarning(res.warning); + toast.warning( + 'Some servers are not accessible with provided credentials', + { + closeButton: true, + duration: Infinity, + id: toastId, + } + ); + setCanRedirect(true); + } else { + toast.success('Login successful!', {id: toastId}); + setCanRedirect(true); + router.push('/validate'); + } + }) + .catch(() => { + setError('An unexpected error occurred while logging in.'); + toast.error('An unexpected error occurred while logging in.', { + closeButton: true, + duration: Infinity, + id: toastId, + }); + }) + .finally(() => { + setSubmitting(false); + }); + }, + [submitting, router] + ); + return ( +
+ + + CachyOS Logo + + Login to your CachyOS Builder account + + + Enter your email and password to access the CachyOS Builder + Dashboard. + + + +
+ +
+
+ ( + + Username + + + + + + )} + /> +
+
+ ( + + Password + + + + + + )} + /> +
+
+ ( + + Are you a robot? + + { + field.onChange(''); + }} + onExpire={() => { + field.onChange(''); + }} + onSuccess={token => { + field.onChange(token); + }} + onTimeout={() => { + field.onChange(''); + }} + options={{ + appearance: 'always', + size: 'flexible', + theme: 'auto', + }} + siteKey={ + process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY! + } + {...field} + /> + + + + )} + /> +
+ {error && ( +
+ {error} +
+ )} + {warning && ( +
+ {warning} +
+ )} +
+ {canRedirect ? ( + + ) : ( + + )} +
+
+
+ By signing in, you agree to data processing and privacy policy. + Your ip address and user agent will be stored for security + purposes. +
+
+ +
+
+
+ ); +} diff --git a/src/components/nav-main.tsx b/src/components/nav-main.tsx new file mode 100644 index 0000000..f257a3b --- /dev/null +++ b/src/components/nav-main.tsx @@ -0,0 +1,38 @@ +'use client'; + +import {type LucideIcon} from 'lucide-react'; +import Link from 'next/link'; + +import { + SidebarGroup, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from '@/components/ui/sidebar'; + +export function NavMain({ + items, +}: Readonly<{ + items: { + icon: LucideIcon; + name: string; + url: string; + }[]; +}>) { + return ( + + + {items.map(item => ( + + + + + {item.name} + + + + ))} + + + ); +} diff --git a/src/components/nav-user.tsx b/src/components/nav-user.tsx new file mode 100644 index 0000000..ae5342c --- /dev/null +++ b/src/components/nav-user.tsx @@ -0,0 +1,113 @@ +'use client'; + +import {BadgeCheck, ChevronsUpDown, LogOut} from 'lucide-react'; +import Link from 'next/link'; + +import {logout} from '@/app/actions'; +import {Avatar, AvatarFallback, AvatarImage} from '@/components/ui/avatar'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from '@/components/ui/sidebar'; +import {useGenericVimShortcutListener} from '@/hooks/use-keyboard-shortcut-listener'; +import {UserData} from '@/lib/typings'; + +export function NavUser({ + user, +}: Readonly<{ + user: UserData; +}>) { + const {isMobile} = useSidebar(); + const profileImage = user.profile_picture_url ?? '/cachyos-logo.svg'; + const fallbackName = user.displayName + .split(' ') + .map(n => n.charAt(0)) + .join('') + .toUpperCase(); + + useGenericVimShortcutListener('q', () => logout()); + + return ( + + + + + + + + + {fallbackName} + + +
+ {user.displayName} + {user.username} +
+ +
+
+ + +
+ + + + {fallbackName} + + +
+ + {user.displayName} + + {user.username} +
+
+
+ + + + + + Profile + + + + + logout()}> + + Log out + +
+
+
+
+ ); +} diff --git a/src/components/rebuild-packages-dialog.tsx b/src/components/rebuild-packages-dialog.tsx new file mode 100644 index 0000000..0f903ae --- /dev/null +++ b/src/components/rebuild-packages-dialog.tsx @@ -0,0 +1,110 @@ +'use client'; + +import {ColumnDef} from '@tanstack/react-table'; +import {toast} from 'sonner'; + +import {bulkRebuildPackages} from '@/app/actions'; +import {Button} from '@/components/ui/button'; +import {DataTable} from '@/components/ui/data-table'; +import {DataTableColumnHeader} from '@/components/ui/data-table-column-header'; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import {BasePackageWithID, BasePackageWithIDList} from '@/lib/typings'; + +const columns: ColumnDef[] = [ + { + cell: ({row}) => ( + {row.original.pkgbase} + ), + header: ({column}) => ( + + ), + id: 'pkgbase', + }, + { + cell: ({row}) => ( + {row.original.repository} + ), + header: ({column}) => ( + + ), + id: 'repository', + }, + { + cell: ({row}) => {row.original.march}, + header: ({column}) => ( + + ), + id: 'arch', + }, +]; + +export function RebuildPackagesDialog({ + onOpenChange, + open, + packages, +}: Readonly<{ + onOpenChange: (state: boolean) => void; + open: boolean; + packages: BasePackageWithIDList; +}>) { + return ( + + + + Rebuild Packages + + You are about to rebuild the following packages ({packages.length}): + + +
+ +
+ + + + + + +
+
+ ); +} diff --git a/src/components/server-switcher.tsx b/src/components/server-switcher.tsx new file mode 100644 index 0000000..796f76a --- /dev/null +++ b/src/components/server-switcher.tsx @@ -0,0 +1,173 @@ +'use client'; + +import {ChevronsUpDown} from 'lucide-react'; +import Image from 'next/image'; +import * as React from 'react'; +import {toast} from 'sonner'; + +import {changeServer} from '@/app/actions'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from '@/components/ui/sidebar'; +import { + useNumericKeyShortcutListener, + useNumericKeyVimShortcutListener, +} from '@/hooks/use-keyboard-shortcut-listener'; +import {ServerData} from '@/lib/typings'; + +export function ServerSwitcher({ + servers, +}: Readonly<{ + servers: ServerData[]; +}>) { + const {isMobile, setActiveServer: updateActiveServer} = useSidebar(); + const [activeServer, setActiveServer] = React.useState( + null + ); + + const handleServerChange = React.useCallback( + (server: ServerData) => { + if ( + server.accessible && + activeServer && + server.name !== activeServer.name + ) { + const toastId = toast.loading( + `Switching to server "${server.name}"...` + ); + changeServer(server.name) + .then(res => { + if (res.error) { + toast.error(res.error, { + closeButton: true, + duration: Infinity, + id: toastId, + }); + } else { + setActiveServer(server); + updateActiveServer(server.name); + toast.success(res.msg ?? 'Switched server successfully!', { + id: toastId, + }); + } + }) + .catch(() => { + toast.error('Failed to switch server, please try again later.', { + closeButton: true, + duration: Infinity, + id: toastId, + }); + }); + } + }, + [activeServer, updateActiveServer] + ); + + const handleServerSwitchShortcut = React.useCallback( + (key: number) => { + if (key > servers.length || key < 1) { + return; + } + const server = servers[key - 1]; + if (server && server.accessible) { + handleServerChange(server); + } + }, + [handleServerChange, servers] + ); + + useNumericKeyShortcutListener(handleServerSwitchShortcut); + useNumericKeyVimShortcutListener(handleServerSwitchShortcut); + + React.useEffect(() => { + if (servers.length > 0) { + const defaultServer = servers.find( + server => server.active && server.accessible + ); + if (defaultServer) { + setActiveServer(defaultServer); + } else { + setActiveServer(servers[0]); + } + } + }, [servers]); + + if (!activeServer) { + return null; + } + + return ( + + + + + +
+ CachyOS Logo +
+
+ + {activeServer.name} + + + {activeServer.description} + +
+ +
+
+ + + Build Servers + + {servers.map((server, index) => ( + handleServerChange(server)} + > +
+ CachyOS Logo +
+ {server.name} + ⌘{index + 1} +
+ ))} +
+
+
+
+ ); +} diff --git a/src/components/stats-kpi.tsx b/src/components/stats-kpi.tsx new file mode 100644 index 0000000..9df6fff --- /dev/null +++ b/src/components/stats-kpi.tsx @@ -0,0 +1,61 @@ +'use client'; + +import {useEffect, useMemo, useState} from 'react'; + +import {getPackageStats} from '@/app/actions'; +import {KPICard} from '@/components/kpi-card'; +import {useSidebar} from '@/components/ui/sidebar'; +import {PackageStatsList, PackageStatsType, PackageStatus} from '@/lib/typings'; +import { + getColorClassNameByPackageStatus, + getVariantByPackageStatus, +} from '@/lib/utils'; + +export function StatsKPI({ + statusFilterUpdate, +}: Readonly<{ + statusFilterUpdate: (status: PackageStatus) => void; +}>) { + const {activeServer} = useSidebar(); + const [categoryChartData, setCategoryChartData] = useState( + [] + ); + const processedChartData = useMemo( + () => + categoryChartData.filter( + x => + x.status_name === PackageStatus.LATEST || + x.status_name === PackageStatus.BUILDING || + x.status_name === PackageStatus.QUEUED || + x.status_name === PackageStatus.FAILED + ), + [categoryChartData] + ); + const packageCount = useMemo( + () => categoryChartData.reduce((acc, item) => acc + item.package_count, 0), + [categoryChartData] + ); + useEffect(() => { + setCategoryChartData([]); + getPackageStats(PackageStatsType.CATEGORY).then(response => { + if (Array.isArray(response)) { + setCategoryChartData(response); + } + }); + }, [activeServer]); + return ( +
+ {processedChartData.map(item => ( + + ))} +
+ ); +} diff --git a/components/TerminalComponent.tsx b/src/components/terminal-component.tsx similarity index 77% rename from components/TerminalComponent.tsx rename to src/components/terminal-component.tsx index 8ea3218..8787217 100644 --- a/components/TerminalComponent.tsx +++ b/src/components/terminal-component.tsx @@ -1,20 +1,21 @@ 'use client'; -import {getPackageLog} from '@/app/actions'; -import {useCtrlFShortcutListener} from '@/lib/hooks'; -import {BuilderPackageArchitecture} from '@/types/BuilderPackage'; -import {RiArrowDownLine, RiArrowUpLine, RiSearchLine} from '@remixicon/react'; -import {TextInput} from '@tremor/react'; import {FitAddon} from '@xterm/addon-fit'; import {SearchAddon} from '@xterm/addon-search'; import {WebLinksAddon} from '@xterm/addon-web-links'; import {WebglAddon} from '@xterm/addon-webgl'; import {Terminal} from '@xterm/xterm'; -import '@xterm/xterm/css/xterm.css'; import styles from 'ansi-styles'; +import {ArrowDownIcon, ArrowUpIcon} from 'lucide-react'; import {useEffect, useRef, useState} from 'react'; -import Loader from './Loader'; +import {getPackageLog} from '@/app/actions'; +import Loader from '@/components/loader'; +import {Input} from '@/components/ui/input'; +import {useGenericShortcutListener} from '@/hooks/use-keyboard-shortcut-listener'; +import {PackageMArch} from '@/lib/typings'; + +import '@xterm/xterm/css/xterm.css'; const OSC = '\u001B]'; const BEL = '\u0007'; @@ -24,7 +25,7 @@ export default function TerminalComponent({ march, pkgbase, }: Readonly<{ - march: BuilderPackageArchitecture; + march: PackageMArch; pkgbase: string; }>) { const [loaded, setLoaded] = useState(false); @@ -95,13 +96,10 @@ export default function TerminalComponent({ }); }; useEffect(() => { - if ( - !loaded && - ref.current && - inputRef.current && - arrowUpRef.current && - arrowDownRef.current - ) { + const input = inputRef.current; + const arrowUp = arrowUpRef.current; + const arrowDown = arrowDownRef.current; + if (!loaded && ref.current && input && arrowUp && arrowDown) { setLoaded(true); terminal.open(ref.current); terminal.attachCustomKeyEventHandler(e => { @@ -122,7 +120,18 @@ export default function TerminalComponent({ } return true; }); - getPackageLog(pkgbase, march, true).then(log => + getPackageLog(pkgbase, march, true).then(log => { + if (typeof log === 'object' && 'error' in log) { + terminal.write( + `${styles.redBright.open}Error: ${log.error}${styles.redBright.close}\n` + ); + setTextLoaded(true); + fitAddon.fit(); + inputRef.current?.addEventListener('input', searchEvent); + arrowUpRef.current?.addEventListener('click', arrowUpEvent); + arrowDownRef.current?.addEventListener('click', searchEvent); + return; + } terminal.write( log .replace( @@ -153,7 +162,7 @@ export default function TerminalComponent({ SEP, BEL, ].join('') - ) || + ) ?? `${styles.yellowBright.open}No logs found for this package (Received a blank response).${styles.yellowBright.close}`, () => { setTextLoaded(true); @@ -162,8 +171,8 @@ export default function TerminalComponent({ arrowUpRef.current?.addEventListener('click', arrowUpEvent); arrowDownRef.current?.addEventListener('click', searchEvent); } - ) - ); + ); + }); } return () => { if (loaded) { @@ -172,13 +181,13 @@ export default function TerminalComponent({ webLinksAddon.dispose(); webglAddon.dispose(); terminal.dispose(); - inputRef.current?.removeEventListener('input', searchEvent); - arrowUpRef.current?.removeEventListener('click', arrowUpEvent); - arrowDownRef.current?.removeEventListener('click', searchEvent); + input?.removeEventListener('input', searchEvent); + arrowUp?.removeEventListener('click', arrowUpEvent); + arrowDown?.removeEventListener('click', searchEvent); } }; }, [ref, loaded, inputRef, arrowUpRef, arrowDownRef]); - useCtrlFShortcutListener(() => { + useGenericShortcutListener('f', () => { containerRef.current?.classList.remove('md:hidden'); inputRef.current?.focus(); }); @@ -188,17 +197,16 @@ export default function TerminalComponent({
-
- +
- +
>) { + return {children}; +} diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx new file mode 100644 index 0000000..12ae47b --- /dev/null +++ b/src/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +'use client'; + +import * as AvatarPrimitive from '@radix-ui/react-avatar'; +import * as React from 'react'; + +import {cn} from '@/lib/utils'; + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export {Avatar, AvatarFallback, AvatarImage}; diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 0000000..defd592 --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import {Slot} from '@radix-ui/react-slot'; +import {cva, type VariantProps} from 'class-variance-authority'; +import * as React from 'react'; + +import {cn} from '@/lib/utils'; + +const badgeVariants = cva( + 'inline-flex items-center justify-center rounded-md 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', + { + defaultVariants: { + variant: 'default', + }, + variants: { + variant: { + default: + 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/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', + secondary: + 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90', + }, + }, + } +); + +function Badge({ + asChild = false, + className, + variant, + ...props +}: React.ComponentProps<'span'> & + VariantProps & {asChild?: boolean}) { + const Comp = asChild ? Slot : 'span'; + + return ( + + ); +} + +export {Badge, badgeVariants}; diff --git a/src/components/ui/breadcrumb.tsx b/src/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..e5289a8 --- /dev/null +++ b/src/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import {Slot} from '@radix-ui/react-slot'; +import {ChevronRight, MoreHorizontal} from 'lucide-react'; +import * as React from 'react'; + +import {cn} from '@/lib/utils'; + +function Breadcrumb({...props}: React.ComponentProps<'nav'>) { + return