diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index d03abbcfd4..0000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "image": "mcr.microsoft.com/devcontainers/universal:2", - "hostRequirements": { - "cpus": 4 - }, - "waitFor": "onCreateCommand", - "updateContentCommand": "npm install", - "postCreateCommand": "", - "postAttachCommand": { - "server": "npm start" - }, - "customizations": { - "codespaces": { - "openFiles": [ - "src/App.jsx" - ] - } - }, - "portsAttributes": { - "3000": { - "label": "Application", - "onAutoForward": "openPreview" - } - }, - "forwardPorts": [3000] -} diff --git a/.devcontainer/icon.svg b/.devcontainer/icon.svg deleted file mode 100644 index ea77a618d9..0000000000 --- a/.devcontainer/icon.svg +++ /dev/null @@ -1,9 +0,0 @@ - - React Logo - - - - - - - diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000..e19ec6b2fc --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +# Required in Vercel for higher GitHub rate limits and pinned GraphQL queries +GITHUB_TOKEN= + +# Optional API-level rate limiter using Vercel KV / Upstash REST +KV_REST_API_URL= +KV_REST_API_TOKEN= + +# Optional tuning +RATE_LIMIT_MAX_REQUESTS=30 +RATE_LIMIT_WINDOW_MS=60000 +ANALYSIS_CACHE_TTL_MS=300000 +GITHUB_CACHE_TTL_MS=120000 +GITHUB_REQUEST_TIMEOUT_MS=10000 diff --git a/.gitignore b/.gitignore index 6a1037fdff..169a19e228 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,15 @@ +<<<<<<< HEAD +# system +.DS_Store +Thumbs.db + +# logs +*.log +*.log + +# node (if ever used) +node_modules/ +======= # Logs logs *.log @@ -41,8 +53,8 @@ build/Release node_modules/ jspm_packages/ -# TypeScript v1 declaration files -typings/ +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ # TypeScript cache *.tsbuildinfo @@ -53,11 +65,8 @@ typings/ # Optional eslint cache .eslintcache -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ +# Optional stylelint cache +.stylelintcache # Optional REPL history .node_repl_history @@ -68,15 +77,18 @@ typings/ # Yarn Integrity file .yarn-integrity -# dotenv environment variables file +# dotenv environment variable files .env -.env.test +.env.* +!.env.example # parcel-bundler cache (https://parceljs.org/) .cache +.parcel-cache # Next.js build output .next +out # Nuxt.js build / generate output .nuxt @@ -84,13 +96,29 @@ dist # Gatsby files .cache/ -# Comment in the public line in if your project uses Gatsby and *not* Next.js +# Comment in the public line in if your project uses Gatsby and not Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist +# vuepress v2.x temp and cache directory +.temp +.cache + +# Sveltekit cache directory +.svelte-kit/ + +# vitepress build output +**/.vitepress/dist + +# vitepress cache directory +**/.vitepress/cache + +# Docusaurus cache and generated files +.docusaurus + # Serverless directories .serverless/ @@ -100,28 +128,25 @@ dist # DynamoDB Local files .dynamodb/ +# Firebase cache directory +.firebase/ + # TernJS port file .tern-port -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Vite logs files +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +>>>>>>> 1b8f29e417c50c7b4347e9caa8c70e9123dbbeae diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/18 - Dev Detective Github.iml b/.idea/18 - Dev Detective Github.iml new file mode 100644 index 0000000000..d0f1ed12b9 --- /dev/null +++ b/.idea/18 - Dev Detective Github.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000000..de4660ea6b --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000000..7d3b86a2d8 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000..c4870ec603 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 374d16e506..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Run application", - "type": "node", - "request": "launch", - "cwd": "${workspaceFolder}", - "console": "integratedTerminal", - "runtimeExecutable": "npm", - "runtimeArgs": [ - "run-script", - "start" - ], - "skipFiles": [ - "/**" - ] - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..6f3a2913e1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/Images/android-chrome-192x192.png b/Images/android-chrome-192x192.png new file mode 100644 index 0000000000..1b29de4ba5 Binary files /dev/null and b/Images/android-chrome-192x192.png differ diff --git a/Images/android-chrome-512x512.png b/Images/android-chrome-512x512.png new file mode 100644 index 0000000000..2f39d24f54 Binary files /dev/null and b/Images/android-chrome-512x512.png differ diff --git a/Images/apple-touch-icon.png b/Images/apple-touch-icon.png new file mode 100644 index 0000000000..c850eacad4 Binary files /dev/null and b/Images/apple-touch-icon.png differ diff --git a/Images/company-icon.svg b/Images/company-icon.svg new file mode 100644 index 0000000000..1751a22299 --- /dev/null +++ b/Images/company-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Images/favicon-16x16.png b/Images/favicon-16x16.png new file mode 100644 index 0000000000..f82b01da41 Binary files /dev/null and b/Images/favicon-16x16.png differ diff --git a/Images/favicon-32x32.png b/Images/favicon-32x32.png new file mode 100644 index 0000000000..72dba564af Binary files /dev/null and b/Images/favicon-32x32.png differ diff --git a/Images/favicon.ico b/Images/favicon.ico new file mode 100644 index 0000000000..6d652abe6a Binary files /dev/null and b/Images/favicon.ico differ diff --git a/Images/location-icon.svg b/Images/location-icon.svg new file mode 100644 index 0000000000..533476f007 --- /dev/null +++ b/Images/location-icon.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/Images/logo.png b/Images/logo.png new file mode 100644 index 0000000000..69f428c947 Binary files /dev/null and b/Images/logo.png differ diff --git a/Images/mascot-detective.svg b/Images/mascot-detective.svg new file mode 100644 index 0000000000..4d0a5e4be0 --- /dev/null +++ b/Images/mascot-detective.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Images/moon-icon.svg b/Images/moon-icon.svg new file mode 100644 index 0000000000..998ffd3c76 --- /dev/null +++ b/Images/moon-icon.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/Images/search-icon.svg b/Images/search-icon.svg new file mode 100644 index 0000000000..9cd81ca315 --- /dev/null +++ b/Images/search-icon.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/Images/site.webmanifest b/Images/site.webmanifest new file mode 100644 index 0000000000..45dc8a2065 --- /dev/null +++ b/Images/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/Images/sun-icon.svg b/Images/sun-icon.svg new file mode 100644 index 0000000000..623f241090 --- /dev/null +++ b/Images/sun-icon.svg @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Images/twitter-icon.svg b/Images/twitter-icon.svg new file mode 100644 index 0000000000..f16f42dd3e --- /dev/null +++ b/Images/twitter-icon.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/Images/website-icon.svg b/Images/website-icon.svg new file mode 100644 index 0000000000..92ddd9722d --- /dev/null +++ b/Images/website-icon.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE index fac6e630f9..548454e942 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 GitHub +Copyright (c) 2025 Sudheer Yadav Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f360b3fb1d..02e1df84f7 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,117 @@ -# GitHub Codespaces ♥️ React +# DevDetective - Vercel Production Build -Welcome to your shiny new Codespace running React! We've got everything fired up and running for you to explore React. +DevDetective is a GitHub Portfolio Analyzer & Enhancer optimized for Vercel serverless deployment. +It provides recruiter-style scoring, risk detection, roadmap generation, and downloadable reports using real GitHub data. -You've got a blank canvas to work on from a git perspective as well. There's a single initial commit with the what you're seeing right now - where you go from here is up to you! +## Highlights -Everything you do here is contained within this one codespace. There is no repository on GitHub yet. If and when you’re ready you can click "Publish Branch" and we’ll create your repository and push up your project. If you were just exploring then and have no further need for this code then you can simply delete your codespace and it's gone forever. +- Accepts GitHub username, `@username`, or profile URL +- Uses real GitHub REST/GraphQL data through serverless API +- Objective portfolio score (`0-100`) + weighted category subscores +- Recruiter insights: strengths, red flags, hidden risks +- Hireability score + readiness level +- Top repository ranking and visual analytics dashboard +- Personalized improvement roadmap and career-path recommendation +- Downloadable markdown recruiter report +- Dark/light mode and responsive SaaS-style UI -This project was bootstrapped for you with [Vite](https://vitejs.dev/). +## Vercel-Native Architecture -## Available Scripts +- Static frontend served via Vercel CDN +- Serverless API route: `api/analyze.js` +- Stateless request flow +- Optional distributed rate limiting using Vercel KV / Upstash REST +- API response caching + in-function cache + CDN caching headers +- Request de-duplication for concurrent same-user analysis calls -In the project directory, you can run: +## Project Structure -### `npm start` +```text +. +├── api/ +│ ├── analyze.js +│ └── _lib/ +│ ├── analysis.js +│ ├── github.js +│ ├── rate-limit.js +│ └── utils.js +├── src/ +│ ├── main.js +│ ├── config/constants.js +│ ├── report/markdown.js +│ ├── ui/charts.js +│ ├── ui/elements.js +│ ├── ui/render.js +│ └── utils/core.js +├── index.html +├── style.css +├── sw.js +├── manifest.json +├── vercel.json +└── .env.example +``` -We've already run this for you in the `Codespaces: server` terminal window below. If you need to stop the server for any reason you can just run `npm start` again to bring it back online. +## Environment Variables -Runs the app in the development mode.\ -Open [http://localhost:3000/](http://localhost:3000/) in the built-in Simple Browser (`Cmd/Ctrl + Shift + P > Simple Browser: Show`) to view your running application. +Set in Vercel Project Settings -> Environment Variables. -The page will reload automatically when you make changes.\ -You may also see any lint errors in the console. +### Required (recommended strongly) -### `npm test` +- `GITHUB_TOKEN`: GitHub token for higher rate limits and GraphQL pinned repos -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. +### Optional (for distributed rate limiting) -### `npm run build` +- `KV_REST_API_URL` +- `KV_REST_API_TOKEN` -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. +### Optional tuning -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! +- `RATE_LIMIT_MAX_REQUESTS` (default `30`) +- `RATE_LIMIT_WINDOW_MS` (default `60000`) +- `ANALYSIS_CACHE_TTL_MS` (default `300000`) +- `GITHUB_CACHE_TTL_MS` (default `120000`) +- `GITHUB_REQUEST_TIMEOUT_MS` (default `10000`) -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. +## Deploy on Vercel -## Learn More +1. Import this repository in Vercel. +2. Add environment variables above. +3. Deploy. -You can learn more in the [Vite documentation](https://vitejs.dev/guide/). +Vercel settings: -To learn Vitest, a Vite-native testing framework, go to [Vitest documentation](https://vitest.dev/guide/) +- Build Command: **(none required)** +- Output Directory: **(none required)** +- Framework Preset: **Other** -To learn React, check out the [React documentation](https://reactjs.org/). +`vercel.json` already includes function config and production headers. -### Code Splitting +## Local Run -This section has moved here: [https://sambitsahoo.com/blog/vite-code-splitting-that-works.html](https://sambitsahoo.com/blog/vite-code-splitting-that-works.html) +### Static frontend check -### Analyzing the Bundle Size +```bash +python3 -m http.server 5500 +``` -This section has moved here: [https://github.com/btd/rollup-plugin-visualizer#rollup-plugin-visualizer](https://github.com/btd/rollup-plugin-visualizer#rollup-plugin-visualizer) +Open `http://localhost:5500`. -### Making a Progressive Web App +### Full Vercel-like local run (if Vercel CLI installed) -This section has moved here: [https://dev.to/hamdankhan364/simplifying-progressive-web-app-pwa-development-with-vite-a-beginners-guide-38cf](https://dev.to/hamdankhan364/simplifying-progressive-web-app-pwa-development-with-vite-a-beginners-guide-38cf) +```bash +vercel dev +``` -### Advanced Configuration +## Reliability & Security -This section has moved here: [https://vitejs.dev/guide/build.html#advanced-base-options](https://vitejs.dev/guide/build.html#advanced-base-options) +- Input sanitization for usernames/URLs +- API abuse protection with rate limiting +- 429 responses when limits are exceeded +- Graceful handling for invalid input, not found, network failures, and GitHub upstream failures +- No sensitive token exposed to browser +- Security headers configured via `vercel.json` -### Deployment +## Notes -This section has moved here: [https://vitejs.dev/guide/build.html](https://vitejs.dev/guide/build.html) - -### Troubleshooting - -This section has moved here: [https://vitejs.dev/guide/troubleshooting.html](https://vitejs.dev/guide/troubleshooting.html) +- Commit consistency is approximated via `pushed_at` metadata. +- Deep README/language checks are limited to top repos for performance and GitHub quota efficiency. diff --git a/api/_lib/analysis.js b/api/_lib/analysis.js new file mode 100644 index 0000000000..defd0427a4 --- /dev/null +++ b/api/_lib/analysis.js @@ -0,0 +1,1003 @@ +import { WEIGHTS } from "../../src/config/constants.js"; +import { + cap01, + clampToRange, + safeRatio, + scoreFromRatio, + daysSinceDate, + joinRepoNames, + formatPercent, + dedupe +} from "../../src/utils/core.js"; + +export function getNamedSubscore(key) { + const labels = { + documentationQuality: "Documentation Quality", + codeActivityConsistency: "Code Activity / Consistency", + projectPopularity: "Project Popularity", + repositoryCompleteness: "Repository Completeness", + languageDiversity: "Language Diversity", + recentActivity: "Recent Activity", + impactSignals: "Impact Signals" + }; + + return labels[key] || key; +} + +export function preRankImportanceScore(repo) { + const days = daysSinceDate(repo.pushed_at); + const freshness = days <= 30 ? 10 : days <= 90 ? 6 : days <= 180 ? 3 : 0; + + return ( + (Number(repo.stargazers_count) || 0) * 3 + + (Number(repo.forks_count) || 0) * 2 + + (Number(repo.watchers_count) || 0) + + freshness + ); +} + +export function buildAnalysisResult({ profile, scorableRepos, contributions, partial, pinnedFromGraphql }) { + const now = Date.now(); + const scorableCount = scorableRepos.length; + + const totalStars = scorableRepos.reduce((sum, repo) => sum + (Number(repo.stargazers_count) || 0), 0); + const totalForks = scorableRepos.reduce((sum, repo) => sum + (Number(repo.forks_count) || 0), 0); + const totalWatchers = scorableRepos.reduce((sum, repo) => sum + (Number(repo.watchers_count) || 0), 0); + + const descriptionCoverage = safeRatio( + scorableRepos.filter((repo) => Boolean((repo.description || "").trim())).length, + scorableCount + ); + + const readmeScannedRepos = scorableRepos.filter((repo) => repo._readmeChecked); + const readmeCoverage = safeRatio( + readmeScannedRepos.filter((repo) => repo._hasReadme === true).length, + readmeScannedRepos.length + ); + + const nonEmptyRepoRatio = safeRatio( + scorableRepos.filter((repo) => (Number(repo.size) || 0) > 0).length, + scorableCount + ); + + const homepageRatio = safeRatio( + scorableRepos.filter((repo) => Boolean((repo.homepage || "").trim())).length, + scorableCount + ); + + const topicsRatio = safeRatio( + scorableRepos.filter((repo) => Array.isArray(repo.topics) && repo.topics.length > 0).length, + scorableCount + ); + + const pushedDays = scorableRepos + .map((repo) => daysSinceDate(repo.pushed_at, now)) + .filter((days) => Number.isFinite(days)); + + const reposUpdated30d = pushedDays.filter((days) => days <= 30).length; + const reposUpdated90d = pushedDays.filter((days) => days <= 90).length; + const reposInactive180d = pushedDays.filter((days) => days > 180).length; + + const activityBuckets = { + updated30d: pushedDays.filter((days) => days <= 30).length, + updated31to90d: pushedDays.filter((days) => days > 30 && days <= 90).length, + updated91to180d: pushedDays.filter((days) => days > 90 && days <= 180).length, + updated181plus: pushedDays.filter((days) => days > 180).length + }; + + const lastPushRepo = [...scorableRepos] + .filter((repo) => repo.pushed_at) + .sort((a, b) => new Date(b.pushed_at).getTime() - new Date(a.pushed_at).getTime())[0] || null; + + const daysSinceLastPush = lastPushRepo ? daysSinceDate(lastPushRepo.pushed_at, now) : 9999; + + const activity = computeActivityInLastSixMonths(scorableRepos); + const activeMonthsLast6Ratio = activity.ratio; + + const starsPerRepo = scorableCount ? totalStars / scorableCount : 0; + const forksPerRepo = scorableCount ? totalForks / scorableCount : 0; + const watchersPerRepo = scorableCount ? totalWatchers / scorableCount : 0; + + const languageTotals = aggregateLanguageTotals(scorableRepos); + const languageEntries = Object.entries(languageTotals).sort((a, b) => b[1] - a[1]); + const uniqueLanguages = languageEntries.length; + const normalizedShannonEntropy = computeNormalizedEntropy(languageTotals); + const totalLanguageBytes = languageEntries.reduce((sum, [, bytes]) => sum + (Number(bytes) || 0), 0); + const dominantLanguage = languageEntries[0] ? languageEntries[0][0] : "Unknown"; + const dominantLanguageShare = + totalLanguageBytes > 0 && languageEntries[0] ? cap01((Number(languageEntries[0][1]) || 0) / totalLanguageBytes) : 0; + const topLanguages = languageEntries.slice(0, 5).map(([language]) => language); + + const topRepoByStars = [...scorableRepos].sort( + (a, b) => (Number(b.stargazers_count) || 0) - (Number(a.stargazers_count) || 0) + )[0] || null; + + const topRepoStars = topRepoByStars ? Number(topRepoByStars.stargazers_count) || 0 : 0; + + const reposUpdated90dRatio = safeRatio(reposUpdated90d, scorableCount); + const reposUpdated30dRatio = safeRatio(reposUpdated30d, scorableCount); + const recencyBucket = getRecencyBucket(daysSinceLastPush); + + const subscores = { + documentationQuality: scoreFromRatio(0.75 * readmeCoverage + 0.25 * descriptionCoverage), + codeActivityConsistency: scoreFromRatio(0.6 * activeMonthsLast6Ratio + 0.4 * reposUpdated90dRatio), + projectPopularity: scoreFromRatio( + 0.6 * cap01(starsPerRepo / 50) + + 0.25 * cap01(forksPerRepo / 20) + + 0.15 * cap01(watchersPerRepo / 20) + ), + repositoryCompleteness: scoreFromRatio( + 0.5 * nonEmptyRepoRatio + + 0.3 * homepageRatio + + 0.2 * topicsRatio + ), + languageDiversity: scoreFromRatio( + 0.7 * cap01(uniqueLanguages / 8) + + 0.3 * normalizedShannonEntropy + ), + recentActivity: scoreFromRatio(0.7 * recencyBucket + 0.3 * reposUpdated30dRatio), + impactSignals: scoreFromRatio( + 0.35 * cap01(topRepoStars / 300) + + 0.25 * cap01((Number(profile.followers) || 0) / 500) + + 0.25 * cap01(contributions.prCount / 200) + + 0.15 * cap01(contributions.issueCount / 100) + ) + }; + + const overallScore = clampToRange( + Math.round( + (subscores.documentationQuality * WEIGHTS.documentationQuality + + subscores.codeActivityConsistency * WEIGHTS.codeActivityConsistency + + subscores.projectPopularity * WEIGHTS.projectPopularity + + subscores.repositoryCompleteness * WEIGHTS.repositoryCompleteness + + subscores.languageDiversity * WEIGHTS.languageDiversity + + subscores.recentActivity * WEIGHTS.recentActivity + + subscores.impactSignals * WEIGHTS.impactSignals) / 100 + ), + 0, + 100 + ); + + const rankedRepos = buildRankedRepositories(scorableRepos); + + const pinnedRepos = pinnedFromGraphql && pinnedFromGraphql.length + ? { + source: "graphql", + items: pinnedFromGraphql + } + : { + source: "fallback", + items: rankedRepos.slice(0, 6).map((repo) => ({ + name: repo.name, + url: repo.url, + stars: repo.stars + })) + }; + + const metrics = { + scorableRepoCount: scorableCount, + totalStars, + totalForks, + totalWatchers, + readmeCoverage, + reposUpdated30d, + reposUpdated90d, + daysSinceLastPush, + authoredPRCount: contributions.prCount, + authoredIssueCount: contributions.issueCount, + uniqueLanguages, + topLanguages, + dominantLanguage, + dominantLanguageShare, + + descriptionCoverage, + descriptionlessRatio: cap01(1 - descriptionCoverage), + activeMonthsLast6: activity.activeMonths, + activeMonthsLast6Ratio, + reposInactive180d, + reposInactive180dRatio: safeRatio(reposInactive180d, scorableCount), + emptyRepoRatio: cap01(1 - nonEmptyRepoRatio), + nonEmptyRepoRatio, + homepageRatio, + topicsRatio, + starsPerRepo, + forksPerRepo, + watchersPerRepo, + reposUpdated30dRatio, + reposUpdated90dRatio, + recencyBucket, + topRepoStars, + normalizedShannonEntropy, + readmeSampleSize: readmeScannedRepos.length, + lastPushDate: lastPushRepo ? lastPushRepo.pushed_at : null, + partialReadmeFailures: partial.readmeFailures, + partialLanguageFailures: partial.languageFailures, + deepRepoCount: partial.deepRepoCount, + activityBuckets + }; + + const strengths = buildStrengths(subscores, metrics, rankedRepos); + const redFlags = buildRedFlags(subscores, metrics); + const suggestions = buildSuggestions(subscores, metrics, rankedRepos, pinnedRepos); + const hiddenRisks = buildHiddenRisks(subscores, metrics, rankedRepos); + const hireabilityScore = calculateHireabilityScore(subscores, overallScore, hiddenRisks); + const readiness = classifyReadiness(hireabilityScore, overallScore); + const careerPath = buildCareerPathRecommendation(metrics, rankedRepos, subscores); + const improvementRoadmap = buildImprovementRoadmap(subscores, metrics, rankedRepos, careerPath, hiddenRisks); + const recruiterSimulation = buildRecruiterSimulation({ + overallScore, + hireabilityScore, + readiness, + subscores, + metrics, + strengths, + redFlags, + hiddenRisks, + rankedRepos + }); + + const grade = scoreToGrade(overallScore); + const scoreSummary = buildScoreSummary(overallScore, grade, subscores, metrics, hireabilityScore, readiness.label); + + return { + profile: { + login: profile.login, + name: profile.name || profile.login, + htmlUrl: profile.html_url, + followers: Number(profile.followers) || 0, + following: Number(profile.following) || 0, + publicRepos: Number(profile.public_repos) || 0, + avatarUrl: profile.avatar_url, + bio: profile.bio || "No bio provided.", + createdAt: profile.created_at, + updatedAt: profile.updated_at + }, + generatedAt: new Date().toISOString(), + weights: WEIGHTS, + subscores, + overallScore, + hireabilityScore, + readiness, + readinessLevel: readiness.label, + metrics, + strengths, + redFlags, + suggestions, + hiddenRisks, + recruiterSimulation, + careerPath, + improvementRoadmap, + pinnedRepos, + rankedRepos: rankedRepos.map((repo) => ({ + name: repo.name, + url: repo.url, + importance: repo.importance, + stars: repo.stars, + forks: repo.forks, + watchers: repo.watchers, + pushedAt: repo.pushedAt, + hasReadme: repo.hasReadme, + language: repo.language, + homepage: repo.homepage, + topicsCount: repo.topicsCount, + hasDescription: repo.hasDescription, + isEmpty: repo.isEmpty, + readmeKnown: repo.readmeKnown + })), + languageTotals, + grade, + scoreSummary + }; +} + +function aggregateLanguageTotals(repos) { + const totals = {}; + + repos.forEach((repo) => { + let hasDetailedBreakdown = false; + + if (repo._languageBytes && typeof repo._languageBytes === "object") { + const entries = Object.entries(repo._languageBytes); + if (entries.length) { + entries.forEach(([language, bytes]) => { + totals[language] = (totals[language] || 0) + (Number(bytes) || 0); + }); + hasDetailedBreakdown = true; + } + } + + if (!hasDetailedBreakdown && repo.language) { + totals[repo.language] = (totals[repo.language] || 0) + 1000; + } + }); + + return totals; +} + +function computeNormalizedEntropy(totals) { + const values = Object.values(totals).filter((value) => value > 0); + const total = values.reduce((sum, value) => sum + value, 0); + + if (total <= 0 || values.length <= 1) { + return 0; + } + + const entropy = values.reduce((sum, value) => { + const p = value / total; + return sum - p * Math.log2(p); + }, 0); + + const maxEntropy = Math.log2(values.length); + return maxEntropy > 0 ? entropy / maxEntropy : 0; +} + +function buildRankedRepositories(repos) { + if (!repos.length) { + return []; + } + + const ranked = repos.map((repo) => { + const ageDays = daysSinceDate(repo.pushed_at); + + const recencyBoost = ageDays <= 30 ? 15 : ageDays <= 90 ? 8 : ageDays <= 180 ? 4 : 0; + const readmeBoost = repo._hasReadme === true ? 8 : 0; + const homepageBoost = (repo.homepage || "").trim() ? 4 : 0; + const topicsBoost = Array.isArray(repo.topics) && repo.topics.length > 0 ? 3 : 0; + const descriptionBoost = (repo.description || "").trim() ? 3 : 0; + const sizeBoost = (Number(repo.size) || 0) > 0 ? 2 : 0; + + const rawImportance = + (Number(repo.stargazers_count) || 0) * 4 + + (Number(repo.forks_count) || 0) * 3 + + (Number(repo.watchers_count) || 0) * 2 + + recencyBoost + + readmeBoost + + homepageBoost + + topicsBoost + + descriptionBoost + + sizeBoost; + + return { + name: repo.name, + url: repo.html_url, + rawImportance, + stars: Number(repo.stargazers_count) || 0, + forks: Number(repo.forks_count) || 0, + watchers: Number(repo.watchers_count) || 0, + pushedAt: repo.pushed_at, + hasReadme: repo._hasReadme === true, + readmeKnown: Boolean(repo._readmeChecked), + language: repo.language || "Unknown", + homepage: (repo.homepage || "").trim(), + topicsCount: Array.isArray(repo.topics) ? repo.topics.length : 0, + hasDescription: Boolean((repo.description || "").trim()), + isEmpty: (Number(repo.size) || 0) === 0 + }; + }); + + const maxRaw = Math.max(...ranked.map((repo) => repo.rawImportance), 1); + + ranked.forEach((repo) => { + repo.importance = clampToRange(Math.round((repo.rawImportance / maxRaw) * 100), 0, 100); + }); + + return ranked.sort((a, b) => b.importance - a.importance || b.stars - a.stars); +} + +function buildStrengths(subscores, metrics, rankedRepos) { + const strengths = []; + + if (subscores.codeActivityConsistency >= 70) { + strengths.push( + `Strong activity consistency with ${metrics.activeMonthsLast6}/6 active months and ${metrics.reposUpdated90d} repositories updated in the last 90 days.` + ); + } + + if (subscores.projectPopularity >= 70) { + const top = rankedRepos[0]; + strengths.push( + `Good popularity signals: ${metrics.totalStars} total stars and ${top ? `${top.name} as a leading project` : "multiple visible projects"}.` + ); + } + + if (subscores.languageDiversity >= 70) { + strengths.push(`Diverse technical stack with ${metrics.uniqueLanguages} detected languages.`); + } + + if (subscores.recentActivity >= 70) { + strengths.push(`Recent contribution momentum: latest push was ${metrics.daysSinceLastPush} day(s) ago.`); + } + + if (subscores.documentationQuality >= 70) { + strengths.push( + `Documentation quality is strong with ${(metrics.readmeCoverage * 100).toFixed(0)}% README coverage in sampled repositories.` + ); + } + + if (subscores.impactSignals >= 70) { + strengths.push( + `Impact signals are healthy with ${metrics.authoredPRCount} authored PRs and ${metrics.authoredIssueCount} authored issues.` + ); + } + + if (!strengths.length) { + strengths.push( + `Public portfolio is visible (${metrics.scorableRepoCount} non-fork repositories) but still needs stronger recruiter-facing signals.` + ); + } + + return strengths.slice(0, 6); +} + +function buildRedFlags(subscores, metrics) { + const redFlags = []; + + if (metrics.readmeCoverage < 0.5) { + redFlags.push( + `Low README coverage (${(metrics.readmeCoverage * 100).toFixed(0)}%) in sampled repositories makes project intent harder to evaluate.` + ); + } + + if (metrics.reposInactive180dRatio > 0.5) { + redFlags.push( + `${metrics.reposInactive180d} of ${metrics.scorableRepoCount} repositories have been inactive for more than 180 days.` + ); + } + + if (metrics.emptyRepoRatio > 0.3) { + redFlags.push( + `${(metrics.emptyRepoRatio * 100).toFixed(0)}% of repositories look empty or near-empty based on repository size.` + ); + } + + if (metrics.descriptionlessRatio > 0.4) { + redFlags.push( + `${(metrics.descriptionlessRatio * 100).toFixed(0)}% of repositories have missing descriptions, which weakens recruiter readability.` + ); + } + + if (metrics.daysSinceLastPush > 90) { + redFlags.push(`No recent pushes in the last 90 days (latest push was ${metrics.daysSinceLastPush} day(s) ago).`); + } + + if (subscores.impactSignals < 40) { + redFlags.push( + `Impact signals are weak (${subscores.impactSignals}/100) due to low follower, PR, issue, or top-repo traction.` + ); + } + + if (!redFlags.length) { + redFlags.push("No major red flags detected from the available public signals."); + } + + return redFlags.slice(0, 6); +} + +function buildSuggestions(subscores, metrics, rankedRepos, pinnedRepos) { + const suggestions = []; + + const missingReadmeRepos = rankedRepos + .filter((repo) => repo.readmeKnown && !repo.hasReadme) + .slice(0, 3) + .map((repo) => repo.name); + + const staleRepos = rankedRepos + .filter((repo) => daysSinceDate(repo.pushedAt) > 180) + .slice(0, 3) + .map((repo) => repo.name); + + const noHomepageRepos = rankedRepos + .filter((repo) => !repo.homepage) + .slice(0, 3) + .map((repo) => repo.name); + + const emptyRepos = rankedRepos + .filter((repo) => repo.isEmpty) + .slice(0, 3) + .map((repo) => repo.name); + + const missingDescriptionRepos = rankedRepos + .filter((repo) => !repo.hasDescription) + .slice(0, 3) + .map((repo) => repo.name); + + if (missingReadmeRepos.length) { + suggestions.push({ + priority: 120 - subscores.documentationQuality, + text: `Add README files to ${joinRepoNames(missingReadmeRepos)} with problem statement, setup, usage, and outcomes.` + }); + } + + if (staleRepos.length) { + suggestions.push({ + priority: 120 - subscores.recentActivity, + text: `Update or archive stale repositories (${joinRepoNames(staleRepos)}) so recruiters see a maintained portfolio.` + }); + } + + if (noHomepageRepos.length) { + suggestions.push({ + priority: 110 - subscores.repositoryCompleteness, + text: `Add live demo or homepage links for ${joinRepoNames(noHomepageRepos)} to improve project completeness.` + }); + } + + if (emptyRepos.length) { + suggestions.push({ + priority: 108 - subscores.repositoryCompleteness, + text: `Complete or archive near-empty repositories (${joinRepoNames(emptyRepos)}) to reduce noise in your public profile.` + }); + } + + if (missingDescriptionRepos.length || metrics.descriptionlessRatio > 0.4) { + const target = missingDescriptionRepos.length ? joinRepoNames(missingDescriptionRepos) : "your weakest repos"; + suggestions.push({ + priority: 109 - subscores.documentationQuality, + text: `Improve project descriptions for ${target} with concise problem, stack, and outcomes so recruiters can scan faster.` + }); + } + + if (subscores.codeActivityConsistency < 70) { + suggestions.push({ + priority: 105 - subscores.codeActivityConsistency, + text: "Improve commit consistency: target at least 1 meaningful commit per week for 8 weeks and aim for 4/6 active months." + }); + } + + if (subscores.impactSignals < 70) { + suggestions.push({ + priority: 105 - subscores.impactSignals, + text: "Increase impact signals by targeting 2 authored PRs and 2 authored issues per month on relevant repositories." + }); + } + + if (pinnedRepos.source === "fallback") { + const suggestedPins = rankedRepos.slice(0, 3).map((repo) => repo.name); + suggestions.push({ + priority: 102, + text: `Pin your strongest repositories (${joinRepoNames(suggestedPins)}) so recruiters immediately see your best work.` + }); + } + + if (metrics.topicsRatio < 0.5) { + suggestions.push({ + priority: 95, + text: "Add GitHub topics/tags to your key repositories to improve discovery and communicate stack relevance quickly." + }); + } + + if (metrics.uniqueLanguages < 3) { + suggestions.push({ + priority: 88, + text: "Showcase at least one additional production-quality project in a different language or framework to broaden stack signals." + }); + } + + const sorted = suggestions + .sort((a, b) => b.priority - a.priority) + .map((entry) => entry.text) + .filter((text, index, arr) => arr.indexOf(text) === index); + + const defaults = [ + `Raise README coverage from ${(metrics.readmeCoverage * 100).toFixed(0)}% to at least 80% in your top repositories.`, + "Set a monthly maintenance pass to close stale issues and refresh pinned projects with recent commits.", + "Improve repository completeness by ensuring every flagship repo has README, topics, and a demo/homepage link.", + "Create a monthly portfolio changelog in one pinned repository to highlight recent improvements and impact.", + "Publish measurable project outcomes (users, performance, business value) in your top README files." + ]; + + while (sorted.length < 5 && defaults.length) { + sorted.push(defaults.shift()); + } + + return sorted.slice(0, 7); +} + +function buildHiddenRisks(subscores, metrics, rankedRepos) { + const risks = []; + + if (metrics.dominantLanguageShare > 0.78 && metrics.uniqueLanguages >= 2) { + risks.push( + `Stack concentration risk: ${metrics.dominantLanguage} accounts for ${formatPercent(metrics.dominantLanguageShare)} of detected language volume.` + ); + } + + const topWithoutHomepage = rankedRepos + .slice(0, 5) + .filter((repo) => !repo.homepage) + .map((repo) => repo.name); + + if (topWithoutHomepage.length >= 3) { + risks.push( + `Conversion risk: ${topWithoutHomepage.length} of your top repositories lack demo/homepage links (${joinRepoNames(topWithoutHomepage.slice(0, 3))}).` + ); + } + + const starConcentration = metrics.totalStars > 0 ? metrics.topRepoStars / metrics.totalStars : 0; + if (starConcentration > 0.85 && metrics.totalStars >= 20 && rankedRepos.length >= 4) { + risks.push( + `Brand concentration risk: one repository drives ${formatPercent(starConcentration)} of total stars, so portfolio impact is overly dependent on a single project.` + ); + } + + if (metrics.authoredPRCount < 5 && metrics.scorableRepoCount >= 10) { + risks.push( + `Collaboration signal risk: only ${metrics.authoredPRCount} authored PRs across a portfolio of ${metrics.scorableRepoCount} repositories.` + ); + } + + if (metrics.reposUpdated90dRatio > 0.45 && metrics.reposUpdated30dRatio < 0.15) { + risks.push( + "Momentum decay risk: older recent activity exists, but updates in the last 30 days are sparse." + ); + } + + if (subscores.repositoryCompleteness < 50 && metrics.topicsRatio < 0.35) { + risks.push( + "Discoverability risk: weak metadata coverage (topics and project links) can reduce recruiter confidence during quick profile scans." + ); + } + + if (!risks.length) { + risks.push("No hidden structural risks detected beyond the visible red flags."); + } + + return risks.slice(0, 6); +} + +function calculateHireabilityScore(subscores, overallScore, hiddenRisks) { + const riskCount = hiddenRisks.filter((item) => !/^No hidden/i.test(item)).length; + const penalty = Math.min(riskCount * 4, 16); + + const raw = + overallScore * 0.45 + + subscores.impactSignals * 0.2 + + subscores.recentActivity * 0.15 + + subscores.documentationQuality * 0.1 + + subscores.repositoryCompleteness * 0.1; + + return clampToRange(Math.round(raw - penalty), 0, 100); +} + +function classifyReadiness(hireabilityScore, overallScore) { + const blended = clampToRange(Math.round((hireabilityScore + overallScore) / 2), 0, 100); + + if (blended >= 85) { + return { + label: "Recruiter-Ready", + severity: "good", + percent: blended, + summary: "Portfolio can usually pass recruiter screens without major concerns." + }; + } + + if (blended >= 70) { + return { + label: "Interview-Ready", + severity: "good", + percent: blended, + summary: "Strong enough for interview pipelines with minor polish opportunities." + }; + } + + if (blended >= 55) { + return { + label: "Emerging", + severity: "warn", + percent: blended, + summary: "Promising portfolio that needs stronger consistency and presentation signals." + }; + } + + return { + label: "Foundation Stage", + severity: "risk", + percent: blended, + summary: "Core work is visible, but recruiter confidence is currently limited." + }; +} + +function buildRecruiterSimulation({ + overallScore, + hireabilityScore, + readiness, + subscores, + metrics, + strengths, + redFlags, + hiddenRisks, + rankedRepos +}) { + let verdict = "Not Ready for Interview Loop"; + let level = "risk"; + + if (hireabilityScore >= 82) { + verdict = "Strong Consider"; + level = "good"; + } else if (hireabilityScore >= 68) { + verdict = "Proceed to Technical Screen"; + level = "warn"; + } else if (hireabilityScore >= 52) { + verdict = "Potential with Portfolio Polish"; + level = "warn"; + } + + const leadingRepo = rankedRepos[0]; + const summary = `${verdict}: overall ${overallScore}/100 and hireability ${hireabilityScore}/100. Current readiness is ${readiness.label}. ${ + leadingRepo ? `Top signal comes from ${leadingRepo.name} (${leadingRepo.importance}/100 importance).` : "No standout repository identified yet." + }`; + + const signals = []; + if (strengths[0]) { + signals.push(`Positive signal: ${strengths[0]}`); + } + if (metrics.totalStars > 0) { + signals.push(`Market traction: ${metrics.totalStars} total stars across ${metrics.scorableRepoCount} scored repositories.`); + } else { + signals.push("Market traction is minimal; add demos and visibility to increase external validation."); + } + const firstRedFlag = redFlags.find((item) => !/No major red flags/i.test(item)); + if (firstRedFlag) { + signals.push(`Primary concern: ${firstRedFlag}`); + } + const firstHiddenRisk = hiddenRisks.find((item) => !/^No hidden/i.test(item)); + if (firstHiddenRisk) { + signals.push(`Hidden concern: ${firstHiddenRisk}`); + } + if (subscores.impactSignals < 60) { + signals.push("Interview risk: impact signals are below benchmark for competitive product roles."); + } + + return { + verdict, + level, + summary, + signals: signals.slice(0, 6) + }; +} + +function buildCareerPathRecommendation(metrics, rankedRepos, subscores) { + const languages = (metrics.topLanguages || []).map((lang) => lang.toLowerCase()); + const hasAnyLanguage = (list) => list.some((lang) => languages.includes(lang)); + + let title = "Generalist Software Engineer"; + let summary = "Your repositories indicate broad engineering capability across multiple project types."; + let nextSkills = [ + "Create 2 case-study READMEs that highlight architecture decisions and measurable outcomes.", + "Add live demos to your top projects to improve recruiter conversion.", + "Contribute at least 2 PRs/month to repositories related to your target role." + ]; + + if (hasAnyLanguage(["javascript", "typescript"])) { + title = "Full-Stack JavaScript Engineer"; + summary = "Your language mix and repository profile align best with product-focused full-stack roles."; + nextSkills = [ + "Ship one end-to-end project with production deployment, auth, and monitoring.", + "Document system architecture and tradeoffs for your top JavaScript/TypeScript repositories.", + "Add test coverage and CI status badges to your top 3 repositories." + ]; + } else if (hasAnyLanguage(["python"])) { + title = "Data / AI Engineer"; + summary = "Python-heavy activity indicates strong alignment with data and AI engineering tracks."; + nextSkills = [ + "Publish one reproducible ML/data project with dataset, metrics, and inference/demo endpoint.", + "Add evaluation methodology and model limitations to README docs.", + "Showcase pipeline automation and observability in at least one repository." + ]; + } else if (hasAnyLanguage(["java", "kotlin", "scala"])) { + title = "Backend Platform Engineer"; + summary = "JVM-oriented repositories and contribution signals fit backend and platform engineering roles."; + nextSkills = [ + "Demonstrate API design quality with versioned contracts and load/performance notes.", + "Add reliability signals: retries, circuit breakers, and structured logging.", + "Publish a backend project with deployment and scalability benchmarks." + ]; + } else if (hasAnyLanguage(["go", "rust", "c", "c++"])) { + title = "Systems / Infrastructure Engineer"; + summary = "Your dominant languages suggest strongest fit for systems and infrastructure engineering paths."; + nextSkills = [ + "Build one performance-focused project with clear latency/throughput benchmarks.", + "Document low-level design choices and profiling evidence in README.", + "Add automation scripts for build/test/release workflows." + ]; + } else if (hasAnyLanguage(["swift", "objective-c", "dart"])) { + title = "Mobile Application Engineer"; + summary = "Language signals indicate strongest fit for modern mobile development roles."; + nextSkills = [ + "Publish a shipped-quality mobile app with store-ready documentation and screenshots.", + "Add crash/error monitoring strategy and release notes cadence.", + "Showcase offline support and performance considerations." + ]; + } + + const confidence = clampToRange( + Math.round( + 52 + + metrics.dominantLanguageShare * 18 + + Math.min(metrics.uniqueLanguages, 5) * 4 + + (subscores.codeActivityConsistency >= 70 ? 6 : 0) + + (subscores.impactSignals >= 60 ? 6 : 0) + ), + 35, + 95 + ); + + const weakestSubscore = Object.entries(subscores).sort((a, b) => a[1] - b[1])[0][0]; + const weakestAdviceMap = { + documentationQuality: "Strengthen documentation quality to make your projects legible to non-engineers.", + codeActivityConsistency: "Establish a visible weekly commit cadence to reduce perceived delivery risk.", + projectPopularity: "Increase visibility through demos, developer posts, and open-source collaboration.", + repositoryCompleteness: "Add project metadata (description, topics, demos) to boost portfolio clarity.", + languageDiversity: "Add one adjacent-stack project to signal broader technical range.", + recentActivity: "Prioritize recent updates in top repositories to maintain recruiter confidence.", + impactSignals: "Increase authored PR and issue activity in relevant external repositories." + }; + + nextSkills.push(weakestAdviceMap[weakestSubscore]); + + if (rankedRepos[0] && rankedRepos[0].importance >= 80) { + nextSkills.push(`Position \`${rankedRepos[0].name}\` as flagship project with a complete case-study README.`); + } + + return { + title, + confidence, + summary, + nextSkills: dedupe(nextSkills).slice(0, 6) + }; +} + +function buildImprovementRoadmap(subscores, metrics, rankedRepos, careerPath, hiddenRisks) { + const roadmap = []; + const missingReadmeRepos = rankedRepos + .filter((repo) => repo.readmeKnown && !repo.hasReadme) + .slice(0, 2) + .map((repo) => repo.name); + const noHomepageRepos = rankedRepos + .filter((repo) => !repo.homepage) + .slice(0, 2) + .map((repo) => repo.name); + const staleRepos = rankedRepos + .filter((repo) => daysSinceDate(repo.pushedAt) > 180) + .slice(0, 2) + .map((repo) => repo.name); + + roadmap.push( + "Week 1: Set portfolio baseline by updating profile bio, pinning top repositories, and documenting measurable outcomes." + ); + + const deficitOrder = Object.entries(subscores) + .sort((a, b) => a[1] - b[1]) + .map(([key]) => key); + + deficitOrder.forEach((key) => { + if (key === "documentationQuality" && missingReadmeRepos.length) { + roadmap.push( + `Week 1-2: Add structured README files to ${joinRepoNames(missingReadmeRepos)} with problem, architecture, setup, and results.` + ); + } else if (key === "recentActivity" || key === "codeActivityConsistency") { + roadmap.push( + "Week 2-5: Maintain weekly commits (minimum 1 meaningful update/week) across at least 4 core repositories." + ); + } else if (key === "repositoryCompleteness" && noHomepageRepos.length) { + roadmap.push( + `Week 2-3: Add demo/homepage links and GitHub topics for ${joinRepoNames(noHomepageRepos)}.` + ); + } else if (key === "impactSignals") { + roadmap.push( + "Week 3-6: Target 8 authored PRs and 6 authored issues in repositories aligned to your target role." + ); + } else if (key === "projectPopularity") { + roadmap.push( + "Week 4: Publish concise demo posts and architecture threads to improve repository discoverability and star velocity." + ); + } else if (key === "languageDiversity" && metrics.uniqueLanguages < 4) { + roadmap.push( + "Week 5-7: Build one production-quality project in an adjacent stack to expand technical breadth signals." + ); + } + }); + + if (staleRepos.length) { + roadmap.push(`Week 3: Refresh or archive stale repositories (${joinRepoNames(staleRepos)}) to reduce portfolio noise.`); + } + + const firstHiddenRisk = hiddenRisks.find((item) => !/^No hidden/i.test(item)); + if (firstHiddenRisk) { + roadmap.push(`Week 4: Resolve hidden risk identified by analysis: ${firstHiddenRisk}`); + } + + roadmap.push( + `Week 8: Repackage top 3 projects for ${careerPath.title} positioning with recruiter-focused case studies and outcomes.` + ); + + const defaults = [ + "Set a monthly portfolio review reminder to keep all flagship repositories active and complete.", + "Add short demo videos/GIFs to your top repositories for faster recruiter evaluation." + ]; + + const uniqueRoadmap = dedupe(roadmap); + while (uniqueRoadmap.length < 5 && defaults.length) { + uniqueRoadmap.push(defaults.shift()); + } + + return uniqueRoadmap.slice(0, 7); +} + +function buildScoreSummary(overallScore, grade, subscores, metrics, hireabilityScore, readinessLabel) { + const strongest = getNamedSubscore(Object.entries(subscores).sort((a, b) => b[1] - a[1])[0][0]); + const weakest = getNamedSubscore(Object.entries(subscores).sort((a, b) => a[1] - b[1])[0][0]); + + let summary = `Score ${overallScore}/100 (${grade}), hireability ${hireabilityScore}/100 (${readinessLabel}). Strongest area: ${strongest}. Biggest gap: ${weakest}.`; + + if (metrics.partialLanguageFailures || metrics.partialReadmeFailures) { + summary += ` Partial data warning: ${metrics.partialLanguageFailures + metrics.partialReadmeFailures} deep checks failed due to API limits or transient errors.`; + } + + return summary; +} + +function computeActivityInLastSixMonths(repos) { + const now = new Date(); + const monthKeys = []; + + for (let i = 0; i < 6; i += 1) { + const date = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - i, 1)); + monthKeys.push(`${date.getUTCFullYear()}-${date.getUTCMonth() + 1}`); + } + + const activeSet = new Set(); + + repos.forEach((repo) => { + if (!repo.pushed_at) { + return; + } + + const pushed = new Date(repo.pushed_at); + const key = `${pushed.getUTCFullYear()}-${pushed.getUTCMonth() + 1}`; + if (monthKeys.includes(key)) { + activeSet.add(key); + } + }); + + const activeMonths = activeSet.size; + return { + activeMonths, + ratio: activeMonths / 6 + }; +} + +function getRecencyBucket(daysSinceLastPush) { + if (daysSinceLastPush <= 7) { + return 1; + } + if (daysSinceLastPush <= 30) { + return 0.8; + } + if (daysSinceLastPush <= 90) { + return 0.6; + } + if (daysSinceLastPush <= 180) { + return 0.3; + } + return 0.1; +} + +function scoreToGrade(score) { + if (score >= 90) { + return "A+"; + } + if (score >= 80) { + return "A"; + } + if (score >= 70) { + return "B"; + } + if (score >= 60) { + return "C"; + } + if (score >= 45) { + return "D"; + } + return "E"; +} diff --git a/api/_lib/github.js b/api/_lib/github.js new file mode 100644 index 0000000000..258cdd0f9c --- /dev/null +++ b/api/_lib/github.js @@ -0,0 +1,448 @@ +import { buildAnalysisResult, preRankImportanceScore } from "./analysis.js"; +import { mapWithConcurrency, withTimeout } from "./utils.js"; + +const GITHUB_API_ROOT = "https://api.github.com"; +const GITHUB_GRAPHQL_ENDPOINT = "https://api.github.com/graphql"; + +const MAX_REPO_PAGES = 3; +const MAX_DEEP_REPOS = 30; +const CONCURRENCY_LIMIT = 5; +const REQUEST_TIMEOUT_MS = Number(process.env.GITHUB_REQUEST_TIMEOUT_MS || 10_000); +const GITHUB_CACHE_TTL_MS = Number(process.env.GITHUB_CACHE_TTL_MS || 120_000); + +const githubResponseCache = new Map(); + +export class GitHubError extends Error { + constructor(type, message, details = {}) { + super(message); + this.name = "GitHubError"; + this.type = type; + this.details = details; + } +} + +export function parseProfileInput(rawInput) { + const value = (rawInput || "").trim(); + + if (!value) { + return { ok: false, error: "Enter a GitHub username or profile URL." }; + } + + let candidate = value; + + if (/github\.com\//i.test(candidate) && !/^https?:\/\//i.test(candidate)) { + candidate = `https://${candidate}`; + } + + if (/^https?:\/\//i.test(candidate)) { + try { + const url = new URL(candidate); + const host = url.hostname.toLowerCase(); + if (host !== "github.com" && host !== "www.github.com") { + return { ok: false, error: "URL must be a valid github.com profile URL." }; + } + + const segments = url.pathname.split("/").filter(Boolean); + if (!segments.length) { + return { ok: false, error: "GitHub URL is missing a username." }; + } + + candidate = segments[0]; + } catch { + return { ok: false, error: "Invalid URL format. Use a username or github.com profile URL." }; + } + } + + candidate = candidate.replace(/^@+/, "").trim(); + if (candidate.endsWith(".git")) { + candidate = candidate.slice(0, -4); + } + + const isValid = /^[A-Za-z0-9-]{1,39}$/.test(candidate) && !candidate.startsWith("-") && !candidate.endsWith("-"); + + if (!isValid) { + return { ok: false, error: "Invalid GitHub username format." }; + } + + return { ok: true, username: candidate.toLowerCase() }; +} + +export async function runAnalysisPipeline(username, token, signal) { + const profileResponse = await githubRequest(`/users/${encodeURIComponent(username)}`, { token, signal }); + const profile = profileResponse.data; + + const allRepos = await fetchAllRepositories(profile.login, token, signal); + const scorableRepos = allRepos.filter((repo) => !repo.fork); + + const deepEnrichment = await enrichTopRepositories(profile.login, scorableRepos, token, signal); + const deepMap = new Map(deepEnrichment.items.map((item) => [item.id, item])); + + const enrichedScorableRepos = scorableRepos.map((repo) => { + const extra = deepMap.get(repo.id); + return { + ...repo, + _languageBytes: extra ? extra.languageBytes : null, + _languageChecked: extra ? extra.languageChecked : false, + _hasReadme: extra ? extra.hasReadme : null, + _readmeChecked: extra ? extra.readmeChecked : false + }; + }); + + const contributions = await fetchContributionSignals(profile.login, token, signal); + const pinnedFromGraphql = token ? await fetchPinnedRepositories(profile.login, token, signal) : null; + + return buildAnalysisResult({ + profile, + scorableRepos: enrichedScorableRepos, + contributions, + partial: deepEnrichment.partial, + pinnedFromGraphql + }); +} + +async function fetchAllRepositories(username, token, signal) { + const repos = []; + + for (let page = 1; page <= MAX_REPO_PAGES; page += 1) { + const path = `/users/${encodeURIComponent(username)}/repos?type=owner&sort=updated&per_page=100&page=${page}`; + const response = await githubRequest(path, { token, signal }); + const data = Array.isArray(response.data) ? response.data : []; + + repos.push(...data); + + if (data.length < 100) { + break; + } + } + + return repos; +} + +async function enrichTopRepositories(owner, scorableRepos, token, signal) { + const candidates = [...scorableRepos] + .sort((a, b) => preRankImportanceScore(b) - preRankImportanceScore(a)) + .slice(0, MAX_DEEP_REPOS); + + const partial = { + deepRepoCount: candidates.length, + languageChecked: 0, + readmeChecked: 0, + languageFailures: 0, + readmeFailures: 0 + }; + + const items = await mapWithConcurrency(candidates, CONCURRENCY_LIMIT, async (repo) => { + return fetchRepoDeepMeta(owner, repo, token, signal, partial); + }); + + return { items, partial }; +} + +async function fetchRepoDeepMeta(owner, repo, token, signal, partial) { + const details = { + id: repo.id, + languageBytes: null, + languageChecked: false, + hasReadme: null, + readmeChecked: false + }; + + try { + const languagesResponse = await githubRequest( + `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo.name)}/languages`, + { token, signal } + ); + details.languageBytes = languagesResponse.data && typeof languagesResponse.data === "object" ? languagesResponse.data : {}; + details.languageChecked = true; + partial.languageChecked += 1; + } catch (error) { + if (error.name === "AbortError") { + throw error; + } + partial.languageFailures += 1; + } + + try { + await githubRequest( + `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo.name)}/readme`, + { token, signal } + ); + details.hasReadme = true; + details.readmeChecked = true; + partial.readmeChecked += 1; + } catch (error) { + if (error.name === "AbortError") { + throw error; + } + + if (error instanceof GitHubError && error.type === "NotFound") { + details.hasReadme = false; + details.readmeChecked = true; + partial.readmeChecked += 1; + } else { + partial.readmeFailures += 1; + } + } + + return details; +} + +async function fetchContributionSignals(username, token, signal) { + const [prCount, issueCount] = await Promise.all([ + fetchSearchCount(`author:${username} type:pr`, token, signal), + fetchSearchCount(`author:${username} type:issue`, token, signal) + ]); + + return { prCount, issueCount }; +} + +async function fetchSearchCount(query, token, signal) { + const path = `/search/issues?q=${encodeURIComponent(query)}&per_page=1`; + const response = await githubRequest(path, { token, signal }); + return Number(response.data && response.data.total_count) || 0; +} + +async function fetchPinnedRepositories(username, token, signal) { + const query = ` + query ($login: String!) { + user(login: $login) { + pinnedItems(first: 6, types: REPOSITORY) { + nodes { + ... on Repository { + name + url + stargazerCount + } + } + } + } + } + `; + + try { + const data = await githubGraphQL(query, { login: username }, token, signal); + const nodes = data && data.user && data.user.pinnedItems ? data.user.pinnedItems.nodes : []; + + if (!Array.isArray(nodes)) { + return null; + } + + return nodes + .filter((node) => node && node.name && node.url) + .map((node) => ({ + name: node.name, + url: node.url, + stars: Number(node.stargazerCount) || 0 + })); + } catch (error) { + if (error.name === "AbortError") { + throw error; + } + return null; + } +} + +async function githubRequest(path, options = {}) { + const { + token = "", + method = "GET", + signal, + retry = 1, + body, + accept = "application/vnd.github+json" + } = options; + + const url = path.startsWith("http") ? path : `${GITHUB_API_ROOT}${path}`; + const cacheKey = method === "GET" && !body ? url : null; + + if (cacheKey) { + const cached = getFromCache(cacheKey); + if (cached) { + return cached; + } + } + + let attempt = 0; + while (attempt <= retry) { + attempt += 1; + + const timeout = withTimeout(signal, REQUEST_TIMEOUT_MS); + + try { + const response = await fetch(url, { + method, + signal: timeout.signal, + headers: { + Accept: accept, + "X-GitHub-Api-Version": "2022-11-28", + ...(token ? { Authorization: `Bearer ${token}` } : {}) + }, + ...(body ? { body: JSON.stringify(body) } : {}) + }); + + const rateInfo = extractRateInfo(response.headers); + const contentType = response.headers.get("content-type") || ""; + + if (!response.ok) { + let errorPayload = null; + try { + errorPayload = contentType.includes("application/json") + ? await response.json() + : { message: await response.text() }; + } catch { + errorPayload = { message: `GitHub API error (${response.status})` }; + } + + const message = + (errorPayload && typeof errorPayload.message === "string" && errorPayload.message.trim()) || + `GitHub API error (${response.status})`; + + if (response.status === 404) { + throw new GitHubError("NotFound", message, { status: response.status, rateInfo }); + } + + if (response.status === 401) { + throw new GitHubError("Unauthorized", message, { status: response.status, rateInfo }); + } + + const rateLimited = + response.status === 429 || + (response.status === 403 && (rateInfo.remaining === 0 || /rate limit/i.test(message))); + + if (rateLimited) { + throw new GitHubError("RateLimited", message, { + status: response.status, + resetAt: rateInfo.resetAt, + rateInfo + }); + } + + throw new GitHubError("Api", message, { status: response.status, rateInfo }); + } + + if (response.status === 204) { + const result = { data: null, headers: response.headers, rateInfo }; + if (cacheKey) { + setToCache(cacheKey, result); + } + return result; + } + + const data = contentType.includes("application/json") ? await response.json() : await response.text(); + const result = { data, headers: response.headers, rateInfo }; + if (cacheKey) { + setToCache(cacheKey, result); + } + + return result; + } catch (error) { + if (error.name === "AbortError") { + throw error; + } + + if (error instanceof GitHubError) { + throw error; + } + + if (attempt > retry) { + throw new GitHubError("Network", "Failed to reach GitHub API.", { cause: error }); + } + } finally { + timeout.dispose(); + } + } + + throw new GitHubError("Network", "Failed to reach GitHub API."); +} + +async function githubGraphQL(query, variables, token, signal) { + if (!token) { + throw new GitHubError("Unauthorized", "GitHub token is required for GraphQL requests."); + } + + const timeout = withTimeout(signal, REQUEST_TIMEOUT_MS); + + let response; + try { + response = await fetch(GITHUB_GRAPHQL_ENDPOINT, { + method: "POST", + signal: timeout.signal, + headers: { + Accept: "application/vnd.github+json", + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + "X-GitHub-Api-Version": "2022-11-28" + }, + body: JSON.stringify({ query, variables }) + }); + } catch (error) { + if (error.name === "AbortError") { + throw error; + } + throw new GitHubError("Network", "Failed to reach GitHub GraphQL API.", { cause: error }); + } finally { + timeout.dispose(); + } + + const rateInfo = extractRateInfo(response.headers); + const payload = await response.json(); + + if (!response.ok) { + if (response.status === 401) { + throw new GitHubError("Unauthorized", "GitHub token is invalid for GraphQL API.", { + status: response.status, + rateInfo + }); + } + + const message = (payload && payload.message) || `GitHub GraphQL error (${response.status})`; + throw new GitHubError("Api", message, { status: response.status, rateInfo }); + } + + if (payload.errors && payload.errors.length) { + throw new GitHubError("Api", payload.errors[0].message || "GraphQL query failed.", { + errors: payload.errors, + rateInfo + }); + } + + return payload.data; +} + +function extractRateInfo(headers) { + const remaining = Number(headers.get("x-ratelimit-remaining")); + const resetEpoch = Number(headers.get("x-ratelimit-reset")); + + return { + remaining: Number.isFinite(remaining) ? remaining : null, + resetAt: Number.isFinite(resetEpoch) && resetEpoch > 0 ? new Date(resetEpoch * 1000).toISOString() : null + }; +} + +function getFromCache(key) { + const item = githubResponseCache.get(key); + if (!item) { + return null; + } + + if (Date.now() > item.expiresAt) { + githubResponseCache.delete(key); + return null; + } + + return item.value; +} + +function setToCache(key, value) { + githubResponseCache.set(key, { + value, + expiresAt: Date.now() + GITHUB_CACHE_TTL_MS + }); + + if (githubResponseCache.size > 500) { + const oldestKey = githubResponseCache.keys().next().value; + if (oldestKey) { + githubResponseCache.delete(oldestKey); + } + } +} diff --git a/api/_lib/rate-limit.js b/api/_lib/rate-limit.js new file mode 100644 index 0000000000..0e06605d2b --- /dev/null +++ b/api/_lib/rate-limit.js @@ -0,0 +1,92 @@ +import { getClientIp } from "./utils.js"; + +const memoryBuckets = new Map(); + +const DEFAULT_WINDOW_MS = Number(process.env.RATE_LIMIT_WINDOW_MS || 60_000); +const DEFAULT_MAX_REQUESTS = Number(process.env.RATE_LIMIT_MAX_REQUESTS || 30); + +export async function enforceRateLimit(req) { + const ip = getClientIp(req); + const now = Date.now(); + + const windowMs = Number.isFinite(DEFAULT_WINDOW_MS) ? DEFAULT_WINDOW_MS : 60_000; + const maxRequests = Number.isFinite(DEFAULT_MAX_REQUESTS) ? DEFAULT_MAX_REQUESTS : 30; + + const kvUrl = process.env.KV_REST_API_URL; + const kvToken = process.env.KV_REST_API_TOKEN; + + if (kvUrl && kvToken) { + try { + return await enforceKvRateLimit({ kvUrl, kvToken, ip, now, windowMs, maxRequests }); + } catch { + // fall through to memory limiter + } + } + + return enforceMemoryRateLimit({ ip, now, windowMs, maxRequests }); +} + +async function enforceKvRateLimit({ kvUrl, kvToken, ip, now, windowMs, maxRequests }) { + const windowId = Math.floor(now / windowMs); + const key = `rl:${ip}:${windowId}`; + const resetAt = new Date((windowId + 1) * windowMs).toISOString(); + + const response = await fetch(`${kvUrl}/pipeline`, { + method: "POST", + headers: { + Authorization: `Bearer ${kvToken}`, + "Content-Type": "application/json" + }, + body: JSON.stringify([ + ["INCR", key], + ["PEXPIRE", key, windowMs] + ]) + }); + + if (!response.ok) { + throw new Error("KV rate limit request failed."); + } + + const payload = await response.json(); + const results = Array.isArray(payload?.result) ? payload.result : []; + const first = results[0]; + const count = Number(first?.result ?? first ?? 0); + + return { + allowed: count <= maxRequests, + count, + maxRequests, + resetAt, + source: "kv" + }; +} + +function enforceMemoryRateLimit({ ip, now, windowMs, maxRequests }) { + const bucket = memoryBuckets.get(ip); + + if (!bucket || now >= bucket.expiresAt) { + const next = { + count: 1, + expiresAt: now + windowMs + }; + memoryBuckets.set(ip, next); + return { + allowed: true, + count: next.count, + maxRequests, + resetAt: new Date(next.expiresAt).toISOString(), + source: "memory" + }; + } + + bucket.count += 1; + memoryBuckets.set(ip, bucket); + + return { + allowed: bucket.count <= maxRequests, + count: bucket.count, + maxRequests, + resetAt: new Date(bucket.expiresAt).toISOString(), + source: "memory" + }; +} diff --git a/api/_lib/utils.js b/api/_lib/utils.js new file mode 100644 index 0000000000..4e8adedbc6 --- /dev/null +++ b/api/_lib/utils.js @@ -0,0 +1,52 @@ +export function mapWithConcurrency(items, concurrency, worker) { + if (!items.length) { + return Promise.resolve([]); + } + + const results = new Array(items.length); + let currentIndex = 0; + + const runner = async () => { + while (currentIndex < items.length) { + const index = currentIndex; + currentIndex += 1; + results[index] = await worker(items[index], index); + } + }; + + const workers = []; + const count = Math.min(concurrency, items.length); + for (let i = 0; i < count; i += 1) { + workers.push(runner()); + } + + return Promise.all(workers).then(() => results); +} + +export function withTimeout(signal, ms) { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), ms); + + if (signal) { + signal.addEventListener("abort", () => controller.abort(), { once: true }); + } + + return { + signal: controller.signal, + dispose: () => clearTimeout(timer) + }; +} + +export function getClientIp(req) { + const forwarded = req.headers["x-forwarded-for"]; + if (typeof forwarded === "string" && forwarded.trim()) { + return forwarded.split(",")[0].trim(); + } + + const realIp = req.headers["x-real-ip"]; + if (typeof realIp === "string" && realIp.trim()) { + return realIp.trim(); + } + + return "unknown"; +} diff --git a/api/analyze.js b/api/analyze.js new file mode 100644 index 0000000000..b6f88538b7 --- /dev/null +++ b/api/analyze.js @@ -0,0 +1,213 @@ +import { enforceRateLimit } from "./_lib/rate-limit.js"; +import { GitHubError, parseProfileInput, runAnalysisPipeline } from "./_lib/github.js"; + +export const config = { + runtime: "nodejs" +}; + +const ANALYSIS_CACHE_TTL_MS = Number(process.env.ANALYSIS_CACHE_TTL_MS || 300_000); + +const analysisCache = new Map(); +const inflight = new Map(); + +export default async function handler(req, res) { + setBaseHeaders(res); + + if (req.method !== "GET") { + return sendJson(res, 405, { + ok: false, + error: { + type: "MethodNotAllowed", + message: "Only GET is supported." + } + }); + } + + const rate = await enforceRateLimit(req); + res.setHeader("X-RateLimit-Limit", String(rate.maxRequests)); + res.setHeader("X-RateLimit-Remaining", String(Math.max(0, rate.maxRequests - rate.count))); + res.setHeader("X-RateLimit-Reset-At", rate.resetAt); + + if (!rate.allowed) { + res.setHeader("Retry-After", String(Math.max(1, Math.ceil((new Date(rate.resetAt).getTime() - Date.now()) / 1000)))); + return sendJson(res, 429, { + ok: false, + error: { + type: "RateLimited", + message: "Too many requests. Please retry later.", + resetAt: rate.resetAt + } + }); + } + + const rawInput = normalizeQueryValue(req.query?.username); + const parsed = parseProfileInput(rawInput); + + if (!parsed.ok) { + return sendJson(res, 400, { + ok: false, + error: { + type: "Validation", + message: parsed.error + } + }); + } + + const username = parsed.username; + const cacheKey = username.toLowerCase(); + + const cached = getAnalysisCache(cacheKey); + if (cached) { + res.setHeader("X-Cache", "HIT"); + res.setHeader("Cache-Control", "public, max-age=60, s-maxage=300, stale-while-revalidate=600"); + return sendJson(res, 200, { ok: true, data: cached }); + } + + const running = inflight.get(cacheKey); + if (running) { + try { + const data = await running; + res.setHeader("X-Cache", "INFLIGHT"); + res.setHeader("Cache-Control", "public, max-age=60, s-maxage=300, stale-while-revalidate=600"); + return sendJson(res, 200, { ok: true, data }); + } catch (error) { + return handleError(error, res); + } + } + + const token = process.env.GITHUB_TOKEN || ""; + + const runPromise = runAnalysisPipeline(username, token) + .then((analysis) => { + setAnalysisCache(cacheKey, analysis); + return analysis; + }) + .finally(() => { + inflight.delete(cacheKey); + }); + + inflight.set(cacheKey, runPromise); + + try { + const data = await runPromise; + res.setHeader("X-Cache", "MISS"); + res.setHeader("Cache-Control", "public, max-age=60, s-maxage=300, stale-while-revalidate=600"); + return sendJson(res, 200, { ok: true, data }); + } catch (error) { + return handleError(error, res); + } +} + +function handleError(error, res) { + if (error instanceof GitHubError) { + if (error.type === "NotFound") { + return sendJson(res, 404, { + ok: false, + error: { + type: "NotFound", + message: "GitHub profile not found." + } + }); + } + + if (error.type === "RateLimited") { + const resetAt = error.details?.resetAt || null; + if (resetAt) { + res.setHeader("X-RateLimit-Reset-At", resetAt); + } + + return sendJson(res, 429, { + ok: false, + error: { + type: "RateLimited", + message: "GitHub upstream API rate limit reached. Retry shortly.", + resetAt + } + }); + } + + if (error.type === "Unauthorized") { + return sendJson(res, 503, { + ok: false, + error: { + type: "Unauthorized", + message: "Server GitHub token is invalid or missing in deployment configuration." + } + }); + } + + if (error.type === "Network") { + return sendJson(res, 502, { + ok: false, + error: { + type: "Network", + message: "Network error while fetching GitHub data." + } + }); + } + + return sendJson(res, 502, { + ok: false, + error: { + type: "Upstream", + message: error.message || "GitHub API request failed." + } + }); + } + + return sendJson(res, 500, { + ok: false, + error: { + type: "Internal", + message: "Unexpected server error while analyzing profile." + } + }); +} + +function setBaseHeaders(res) { + res.setHeader("Content-Type", "application/json; charset=utf-8"); + res.setHeader("X-Content-Type-Options", "nosniff"); + res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin"); +} + +function sendJson(res, status, body) { + res.status(status).json(body); +} + +function normalizeQueryValue(value) { + if (Array.isArray(value)) { + return value[0] || ""; + } + if (typeof value === "string") { + return value; + } + return ""; +} + +function getAnalysisCache(key) { + const hit = analysisCache.get(key); + if (!hit) { + return null; + } + + if (Date.now() > hit.expiresAt) { + analysisCache.delete(key); + return null; + } + + return hit.value; +} + +function setAnalysisCache(key, value) { + analysisCache.set(key, { + value, + expiresAt: Date.now() + ANALYSIS_CACHE_TTL_MS + }); + + if (analysisCache.size > 300) { + const oldestKey = analysisCache.keys().next().value; + if (oldestKey) { + analysisCache.delete(oldestKey); + } + } +} diff --git a/index.html b/index.html index 452ca1f328..1f1e5fff24 100644 --- a/index.html +++ b/index.html @@ -1,35 +1,372 @@ - + - + - - + - - - - React App - - - -
- - - + + + + + + + + + + DevDetective | GitHub Portfolio Analyzer + + + + + + + + + + + + + + + +
+
+
+ +
+

DevDetective

+

GitHub Portfolio Analyzer and Recruiter Insight Engine

+
+
+
+ Serverless API + Rate-Limited + Recruiter Lens +
+
+ +
+
+

Hackathon Edition

+

Turn any GitHub profile into a recruiter-ready portfolio report.

+

+ DevDetective reads live GitHub signals and returns objective scoring, hidden risk detection, + role-fit insights, and a concrete improvement roadmap. +

+
+ Real GitHub Data + Transparent Scoring + Downloadable Report +
+
+ +
+ +
+
+
+ + +

+ Tip: paste a full profile URL and DevDetective extracts the username automatically. +

+
+ +
+ + + +
+
+
+ +
+ + + + +
+ + + +
+
+
+
+ Profile avatar +
+

No profile selected

+

@username

+ Open GitHub Profile +
+
+ +

+ Run an analysis to generate recruiter-style portfolio evaluation. +

+ +
+
Public Repos-
+
Followers-
+
Following-
+
Last Push-
+
Authored PRs-
+
Authored Issues-
+
+
+ +
+
+

Pinned Repositories

+ fallback +
+
    +
    + +
    +

    Search History

    +
    +
    +
    + +
    +
    +
    +
    + -- +
    +
    +

    GitHub Portfolio Score

    +

    Grade -

    +

    + Analyze a profile to generate weighted recruiter evaluation. +

    +
    +
    + +
    +
    + Hireability Score + -- + Weighted recruiter-fit index +
    +
    + Portfolio Readiness + -- + Analyze a profile to classify readiness +
    +
    + + +
    +
    Documentation Quality--
    +
    Code Activity / Consistency--
    +
    Project Popularity--
    +
    Repository Completeness--
    +
    Language Diversity--
    +
    Recent Activity--
    +
    Impact Signals--
    +
    +
    + +
    +

    Scoring Transparency

    +

    + Each subscore is calculated from real GitHub metrics and weighted into the final score. +

    +
    +
    +
    + Documentation Quality (18%) +

    0.75 × README Coverage + 0.25 × Description Coverage

    +
    + -- +
    +
    +
    + Code Activity / Consistency (17%) +

    0.60 × Active Months (last 6) + 0.40 × Repos Updated in 90 Days

    +
    + -- +
    +
    +
    + Project Popularity (15%) +

    0.60 × Stars/Repo + 0.25 × Forks/Repo + 0.15 × Watchers/Repo (capped)

    +
    + -- +
    +
    +
    + Repository Completeness (14%) +

    0.50 × Non-empty + 0.30 × Homepage + 0.20 × Topics

    +
    + -- +
    +
    +
    + Language Diversity (10%) +

    0.70 × Unique Languages + 0.30 × Shannon Entropy

    +
    + -- +
    +
    +
    + Recent Activity (14%) +

    0.70 × Recency Bucket + 0.30 × Repos Updated in 30 Days

    +
    + -- +
    +
    +
    + Impact Signals (12%) +

    0.35 × Top Repo Stars + 0.25 × Followers + 0.25 × PRs + 0.15 × Issues

    +
    + -- +
    +
    +
    + +
    +
    +

    AI Recruiter Simulation

    + Pending +
    +

    + Run an analysis to get recruiter-style interview feedback simulation. +

    +
      +
      + +
      +
      +
      +

      Strengths

      +
        +
        +
        +

        Red Flags

        +
          +
          +
          +

          Actionable Suggestions

          +
            +
            +
            +
            + +
            +

            Hidden Risk Detection

            +
              +
              + +
              +
              +

              Career Path Recommendation

              + -- +
              +

              Run an analysis to generate role fit

              +

              + Role recommendations are inferred from your repository stack, impact signals, and activity profile. +

              +
                +
                + +
                +

                Personalized Improvement Roadmap

                +
                  +
                  + +
                  +

                  Visual Analytics

                  +
                  +
                  +

                  Language Usage

                  + +
                  +
                  +

                  Repository Importance

                  + +
                  +
                  +

                  Portfolio Dimension Radar

                  + +
                  +
                  +

                  Repository Activity Buckets

                  + +
                  +
                  +
                  + +
                  +

                  Top Repository Ranking

                  +
                  + + + + + + + + + + + +
                  RepositoryImportanceStars / Forks / WatchersLast PushREADME
                  +
                  +
                  +
                  +
                  +
                  + + + diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 8e881cf9c2..0000000000 --- a/jsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "node" - } -} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000000..71557ed936 --- /dev/null +++ b/manifest.json @@ -0,0 +1,26 @@ +{ + "name": "DevDetective GitHub Portfolio Analyzer", + "short_name": "DevDetective", + "description": "Recruiter-style GitHub portfolio analyzer with weighted scoring, insights, and actionable suggestions.", + "start_url": "/", + "display": "standalone", + "background_color": "#f3f7ff", + "theme_color": "#1f6feb", + "icons": [ + { + "src": "Images/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "Images/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "Images/apple-touch-icon.png", + "sizes": "180x180", + "type": "image/png" + } + ] +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 76771b4b85..0000000000 --- a/package-lock.json +++ /dev/null @@ -1,5300 +0,0 @@ -{ - "name": "codespaces-react", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "codespaces-react", - "version": "0.1.0", - "dependencies": { - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^14.4.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "web-vitals": "^3.1.0" - }, - "devDependencies": { - "@vitejs/plugin-react": "^6.0.1", - "jsdom": "^26.1.0", - "vite": "^8.0.12", - "vitest": "^4.1.6" - } - }, - "node_modules/@adobe/css-tools": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==" - }, - "node_modules/@asamuzakjp/css-color": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@csstools/css-calc": "^2.1.3", - "@csstools/css-color-parser": "^3.0.9", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" - } - }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@csstools/color-helpers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", - "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", - "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.0.2", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", - "dependencies": { - "jest-get-type": "^29.2.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/schemas/node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" - }, - "node_modules/@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "dependencies": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.129.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz", - "integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz", - "integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz", - "integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz", - "integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz", - "integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz", - "integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz", - "integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz", - "integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz", - "integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz", - "integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz", - "integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz", - "integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz", - "integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz", - "integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==", - "cpu": [ - "wasm32" - ], - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz", - "integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz", - "integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz", - "integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==", - "dev": true - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true - }, - "node_modules/@testing-library/dom": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.1.tgz", - "integrity": "sha512-P6iIPyYQ+qH8CvGauAqanhVnjrnRe0IZFSYCeGkSRW9q3u8bdVn2NPI+lasFyVsEQn1J/IFmp5Aax41+dAP9wg==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@testing-library/user-event": { - "version": "14.4.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", - "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/@types/node": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz", - "integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==", - "dependencies": { - "undici-types": "~7.21.0" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "node_modules/@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" - }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", - "integrity": "sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==", - "dependencies": { - "@types/jest": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", - "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" - }, - "node_modules/@vitejs/plugin-react": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", - "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", - "dev": true, - "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.7" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - } - } - }, - "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.7", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", - "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", - "dev": true - }, - "node_modules/@vitest/expect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz", - "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==", - "dev": true, - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz", - "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==", - "dev": true, - "dependencies": { - "@vitest/spy": "4.1.6", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz", - "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==", - "dev": true, - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz", - "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==", - "dev": true, - "dependencies": { - "@vitest/utils": "4.1.6", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz", - "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==", - "dev": true, - "dependencies": { - "@vitest/pretty-format": "4.1.6", - "@vitest/utils": "4.1.6", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz", - "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==", - "dev": true, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz", - "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==", - "dev": true, - "dependencies": { - "@vitest/pretty-format": "4.1.6", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" - }, - "node_modules/cssstyle": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" - }, - "node_modules/deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", - "dependencies": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.15.tgz", - "integrity": "sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw==" - }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", - "dev": true - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", - "dependencies": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "dependencies": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/jsdom": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.5.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.1.1", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.1", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", - "dev": true, - "license": "MIT" - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ] - }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rolldown": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz", - "integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==", - "dev": true, - "dependencies": { - "@oxc-project/types": "=0.129.0", - "@rolldown/pluginutils": "1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0", - "@rolldown/binding-darwin-arm64": "1.0.0", - "@rolldown/binding-darwin-x64": "1.0.0", - "@rolldown/binding-freebsd-x64": "1.0.0", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0", - "@rolldown/binding-linux-arm64-gnu": "1.0.0", - "@rolldown/binding-linux-arm64-musl": "1.0.0", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0", - "@rolldown/binding-linux-s390x-gnu": "1.0.0", - "@rolldown/binding-linux-x64-gnu": "1.0.0", - "@rolldown/binding-linux-x64-musl": "1.0.0", - "@rolldown/binding-openharmony-arm64": "1.0.0", - "@rolldown/binding-wasm32-wasi": "1.0.0", - "@rolldown/binding-win32-arm64-msvc": "1.0.0", - "@rolldown/binding-win32-x64-msvc": "1.0.0" - } - }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", - "dev": true - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true - }, - "node_modules/tinyexec": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", - "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tldts": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^6.1.86" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^6.1.32" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "optional": true - }, - "node_modules/undici-types": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz", - "integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==" - }, - "node_modules/vite": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz", - "integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==", - "dev": true, - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.14", - "rolldown": "1.0.0", - "tinyglobby": "^0.2.16" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", - "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==", - "dev": true, - "dependencies": { - "@vitest/expect": "4.1.6", - "@vitest/mocker": "4.1.6", - "@vitest/pretty-format": "4.1.6", - "@vitest/runner": "4.1.6", - "@vitest/snapshot": "4.1.6", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.6", - "@vitest/browser-preview": "4.1.6", - "@vitest/browser-webdriverio": "4.1.6", - "@vitest/coverage-istanbul": "4.1.6", - "@vitest/coverage-v8": "4.1.6", - "@vitest/ui": "4.1.6", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/web-vitals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.1.0.tgz", - "integrity": "sha512-zCeQ+bOjWjJbXv5ZL0r8Py3XP2doCQMZXNKlBGfUjPAVZWokApdeF/kFlK1peuKlCt8sL9TFkKzyXE9/cmNJQA==" - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - } - }, - "dependencies": { - "@adobe/css-tools": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==" - }, - "@asamuzakjp/css-color": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, - "requires": { - "@csstools/css-calc": "^2.1.3", - "@csstools/css-color-parser": "^3.0.9", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" - }, - "dependencies": { - "lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - } - } - }, - "@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "requires": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" - }, - "@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", - "requires": { - "regenerator-runtime": "^0.14.0" - } - }, - "@csstools/color-helpers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", - "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", - "dev": true - }, - "@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "requires": {} - }, - "@csstools/css-color-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", - "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", - "dev": true, - "requires": { - "@csstools/color-helpers": "^5.0.2", - "@csstools/css-calc": "^2.1.4" - } - }, - "@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "requires": {} - }, - "@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true - }, - "@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "optional": true, - "requires": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "optional": true, - "requires": { - "tslib": "^2.4.0" - } - }, - "@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "optional": true, - "requires": { - "tslib": "^2.4.0" - } - }, - "@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", - "requires": { - "jest-get-type": "^29.2.0" - } - }, - "@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "requires": { - "@sinclair/typebox": "^0.27.8" - }, - "dependencies": { - "@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" - } - } - }, - "@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "requires": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "optional": true, - "peer": true - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, - "optional": true, - "requires": { - "@tybys/wasm-util": "^0.10.1" - } - }, - "@oxc-project/types": { - "version": "0.129.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz", - "integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==", - "dev": true - }, - "@rolldown/binding-android-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz", - "integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==", - "dev": true, - "optional": true - }, - "@rolldown/binding-darwin-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz", - "integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==", - "dev": true, - "optional": true - }, - "@rolldown/binding-darwin-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz", - "integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==", - "dev": true, - "optional": true - }, - "@rolldown/binding-freebsd-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz", - "integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==", - "dev": true, - "optional": true - }, - "@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz", - "integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==", - "dev": true, - "optional": true - }, - "@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz", - "integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==", - "dev": true, - "optional": true - }, - "@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz", - "integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==", - "dev": true, - "optional": true - }, - "@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz", - "integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==", - "dev": true, - "optional": true - }, - "@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz", - "integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==", - "dev": true, - "optional": true - }, - "@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz", - "integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==", - "dev": true, - "optional": true - }, - "@rolldown/binding-linux-x64-musl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz", - "integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==", - "dev": true, - "optional": true - }, - "@rolldown/binding-openharmony-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz", - "integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==", - "dev": true, - "optional": true - }, - "@rolldown/binding-wasm32-wasi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz", - "integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==", - "dev": true, - "optional": true, - "requires": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - } - }, - "@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz", - "integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==", - "dev": true, - "optional": true - }, - "@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz", - "integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==", - "dev": true, - "optional": true - }, - "@rolldown/pluginutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz", - "integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==", - "dev": true - }, - "@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true - }, - "@testing-library/dom": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.1.tgz", - "integrity": "sha512-P6iIPyYQ+qH8CvGauAqanhVnjrnRe0IZFSYCeGkSRW9q3u8bdVn2NPI+lasFyVsEQn1J/IFmp5Aax41+dAP9wg==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - } - }, - "@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "requires": { - "@adobe/css-tools": "^4.3.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } - } - }, - "@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "requires": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" - } - }, - "@testing-library/user-event": { - "version": "14.4.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", - "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", - "requires": {} - }, - "@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "optional": true, - "requires": { - "tslib": "^2.4.0" - } - }, - "@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" - }, - "@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "requires": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true - }, - "@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - }, - "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - } - } - }, - "@types/node": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz", - "integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==", - "requires": { - "undici-types": "~7.21.0" - } - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" - }, - "@types/testing-library__jest-dom": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", - "integrity": "sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==", - "requires": { - "@types/jest": "*" - } - }, - "@types/yargs": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", - "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" - }, - "@vitejs/plugin-react": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", - "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", - "dev": true, - "requires": { - "@rolldown/pluginutils": "1.0.0-rc.7" - }, - "dependencies": { - "@rolldown/pluginutils": { - "version": "1.0.0-rc.7", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", - "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", - "dev": true - } - } - }, - "@vitest/expect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz", - "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==", - "dev": true, - "requires": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - } - }, - "@vitest/mocker": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz", - "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==", - "dev": true, - "requires": { - "@vitest/spy": "4.1.6", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - } - }, - "@vitest/pretty-format": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz", - "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==", - "dev": true, - "requires": { - "tinyrainbow": "^3.1.0" - } - }, - "@vitest/runner": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz", - "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==", - "dev": true, - "requires": { - "@vitest/utils": "4.1.6", - "pathe": "^2.0.3" - } - }, - "@vitest/snapshot": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz", - "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==", - "dev": true, - "requires": { - "@vitest/pretty-format": "4.1.6", - "@vitest/utils": "4.1.6", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - } - }, - "@vitest/spy": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz", - "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==", - "dev": true - }, - "@vitest/utils": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz", - "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==", - "dev": true, - "requires": { - "@vitest/pretty-format": "4.1.6", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - } - }, - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "optional": true, - "peer": true - }, - "agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "requires": { - "deep-equal": "^2.0.5" - } - }, - "assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" - }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "requires": { - "fill-range": "^7.1.1" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "optional": true, - "peer": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==" - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" - }, - "cssstyle": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", - "dev": true, - "requires": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - } - }, - "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, - "requires": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - } - }, - "debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true - }, - "deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", - "requires": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - } - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true - }, - "diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==" - }, - "dom-accessibility-api": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.15.tgz", - "integrity": "sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw==" - }, - "entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - } - }, - "es-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", - "dev": true - }, - "estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "requires": { - "@types/estree": "^1.0.0" - } - }, - "expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", - "requires": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" - } - }, - "expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true - }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^3.1.1" - } - }, - "http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "requires": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - } - }, - "https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "requires": { - "agent-base": "^7.1.2", - "debug": "4" - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - }, - "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - } - } - }, - "jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==" - }, - "jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - }, - "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - } - } - }, - "jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - }, - "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - } - } - }, - "jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "requires": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "jsdom": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", - "dev": true, - "requires": { - "cssstyle": "^4.2.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.5.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.16", - "parse5": "^7.2.1", - "rrweb-cssom": "^0.8.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.1.1", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.1.1", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - } - }, - "lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "requires": { - "detect-libc": "^2.0.3", - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "dev": true, - "optional": true - }, - "lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "dev": true, - "optional": true - }, - "lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "dev": true, - "optional": true - }, - "lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "dev": true, - "optional": true - }, - "lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "dev": true, - "optional": true - }, - "lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "dev": true, - "optional": true - }, - "lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "dev": true, - "optional": true - }, - "lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "dev": true, - "optional": true - }, - "lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==" - }, - "magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "requires": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - } - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true - }, - "nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", - "dev": true - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true - }, - "parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "requires": { - "entities": "^6.0.0" - } - }, - "pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true - }, - "picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" - }, - "picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==" - }, - "postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - } - } - }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true - }, - "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "rolldown": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz", - "integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==", - "dev": true, - "requires": { - "@oxc-project/types": "=0.129.0", - "@rolldown/binding-android-arm64": "1.0.0", - "@rolldown/binding-darwin-arm64": "1.0.0", - "@rolldown/binding-darwin-x64": "1.0.0", - "@rolldown/binding-freebsd-x64": "1.0.0", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0", - "@rolldown/binding-linux-arm64-gnu": "1.0.0", - "@rolldown/binding-linux-arm64-musl": "1.0.0", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0", - "@rolldown/binding-linux-s390x-gnu": "1.0.0", - "@rolldown/binding-linux-x64-gnu": "1.0.0", - "@rolldown/binding-linux-x64-musl": "1.0.0", - "@rolldown/binding-openharmony-arm64": "1.0.0", - "@rolldown/binding-wasm32-wasi": "1.0.0", - "@rolldown/binding-win32-arm64-msvc": "1.0.0", - "@rolldown/binding-win32-x64-msvc": "1.0.0", - "@rolldown/pluginutils": "1.0.0" - } - }, - "rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "peer": true - } - } - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - } - } - }, - "stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", - "dev": true - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "requires": { - "min-indent": "^1.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true, - "peer": true - } - } - }, - "tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true - }, - "tinyexec": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", - "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", - "dev": true - }, - "tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, - "requires": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "dependencies": { - "fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "requires": {} - }, - "picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true - } - } - }, - "tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true - }, - "tldts": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dev": true, - "requires": { - "tldts-core": "^6.1.86" - } - }, - "tldts-core": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "dev": true, - "requires": { - "tldts": "^6.1.32" - } - }, - "tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "dev": true, - "requires": { - "punycode": "^2.3.1" - } - }, - "tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "optional": true - }, - "undici-types": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz", - "integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==" - }, - "vite": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz", - "integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==", - "dev": true, - "requires": { - "fsevents": "~2.3.3", - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.4.31", - "rolldown": "1.0.0", - "tinyglobby": "^0.2.16" - }, - "dependencies": { - "picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true - } - } - }, - "vitest": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", - "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==", - "dev": true, - "requires": { - "@vitest/expect": "4.1.6", - "@vitest/mocker": "4.1.6", - "@vitest/pretty-format": "4.1.6", - "@vitest/runner": "4.1.6", - "@vitest/snapshot": "4.1.6", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "dependencies": { - "picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true - } - } - }, - "w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "requires": { - "xml-name-validator": "^5.0.0" - } - }, - "web-vitals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.1.0.tgz", - "integrity": "sha512-zCeQ+bOjWjJbXv5ZL0r8Py3XP2doCQMZXNKlBGfUjPAVZWokApdeF/kFlK1peuKlCt8sL9TFkKzyXE9/cmNJQA==" - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true - }, - "whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" - } - }, - "whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true - }, - "whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dev": true, - "requires": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "requires": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - } - }, - "ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - } - } -} diff --git a/package.json b/package.json index 944cb642ab..592a5f428a 100644 --- a/package.json +++ b/package.json @@ -1,49 +1,10 @@ { - "name": "codespaces-react", - "version": "0.1.0", + "name": "dev-detective-vercel", + "version": "1.0.0", "private": true, "type": "module", - "dependencies": { - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^14.4.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "web-vitals": "^3.1.0" - }, - "overrides": { - "@svgr/webpack": "^8.0.1", - "@adobe/css-tools": "^4.3.1", - "postcss": "^8.4.31" - }, "scripts": { - "start": "BROWSER=none WDS_SOCKET_PORT=0 vite --port 3000", - "build": "vite build", - "preview": "vite preview", - "test": "vitest" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "devDependencies": { - "@vitejs/plugin-react": "^6.0.1", - "jsdom": "^26.1.0", - "vite": "^8.0.12", - "vitest": "^4.1.6" + "dev": "vercel dev", + "start": "python3 -m http.server 5500" } } diff --git a/public/Octocat.png b/public/Octocat.png deleted file mode 100644 index 91057da496..0000000000 Binary files a/public/Octocat.png and /dev/null differ diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index a11777cc47..0000000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a379..0000000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/logo512.png b/public/logo512.png deleted file mode 100644 index a4e47a6545..0000000000 Binary files a/public/logo512.png and /dev/null differ diff --git a/public/manifest.json b/public/manifest.json deleted file mode 100644 index 080d6c77ac..0000000000 --- a/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index e9e57dc4d4..0000000000 --- a/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/src/App.css b/src/App.css deleted file mode 100644 index fce9cc9d87..0000000000 --- a/src/App.css +++ /dev/null @@ -1,31 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -.heart { - color: #ff0000; -} - -.small { - font-size: 0.75rem; -} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx deleted file mode 100644 index 8b32d07183..0000000000 --- a/src/App.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import './App.css'; - -function App() { - return ( -
                  -
                  - logo -

                  - GitHub Codespaces ♥️ React -

                  -

                  - Edit src/App.jsx and save to reload. -

                  -

                  - - Learn React - -

                  -
                  -
                  - ); -} - -export default App; diff --git a/src/App.test.jsx b/src/App.test.jsx deleted file mode 100644 index 5e98249332..0000000000 --- a/src/App.test.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import { expect, test } from 'vitest'; -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeDefined(); -}); diff --git a/src/config/constants.js b/src/config/constants.js new file mode 100644 index 0000000000..0314aebdfc --- /dev/null +++ b/src/config/constants.js @@ -0,0 +1,54 @@ +export const CACHE_TTL_MS = 10 * 60 * 1000; +export const HISTORY_LIMIT = 8; +export const ANALYZE_ENDPOINT = "/api/analyze"; + +export const STORAGE_KEYS = Object.freeze({ + history: "devdetective_history", + theme: "devdetective_theme" +}); + +export const CACHE_PREFIX = "devdetective_cache_v4_"; + +export const WEIGHTS = Object.freeze({ + documentationQuality: 18, + codeActivityConsistency: 17, + projectPopularity: 15, + repositoryCompleteness: 14, + languageDiversity: 10, + recentActivity: 14, + impactSignals: 12 +}); + +export const SUBSCORE_ID_MAP = Object.freeze({ + documentationQuality: "subDocumentationQuality", + codeActivityConsistency: "subCodeActivityConsistency", + projectPopularity: "subProjectPopularity", + repositoryCompleteness: "subRepositoryCompleteness", + languageDiversity: "subLanguageDiversity", + recentActivity: "subRecentActivity", + impactSignals: "subImpactSignals" +}); + +export const SCORING_EXPLAIN_ID_MAP = Object.freeze({ + documentationQuality: "explainDocumentationQuality", + codeActivityConsistency: "explainCodeActivityConsistency", + projectPopularity: "explainProjectPopularity", + repositoryCompleteness: "explainRepositoryCompleteness", + languageDiversity: "explainLanguageDiversity", + recentActivity: "explainRecentActivity", + impactSignals: "explainImpactSignals" +}); + +export function getNamedSubscore(key) { + const labels = { + documentationQuality: "Documentation Quality", + codeActivityConsistency: "Code Activity / Consistency", + projectPopularity: "Project Popularity", + repositoryCompleteness: "Repository Completeness", + languageDiversity: "Language Diversity", + recentActivity: "Recent Activity", + impactSignals: "Impact Signals" + }; + + return labels[key] || key; +} diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e8c0..0000000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/src/index.jsx b/src/index.jsx deleted file mode 100644 index d563c0fb10..0000000000 --- a/src/index.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c058c..0000000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000000..dfb27ff2c4 --- /dev/null +++ b/src/main.js @@ -0,0 +1,381 @@ +import { + ANALYZE_ENDPOINT, + CACHE_PREFIX, + CACHE_TTL_MS, + HISTORY_LIMIT, + STORAGE_KEYS +} from "./config/constants.js"; +import { getUiElements } from "./ui/elements.js"; +import { renderInitialState, renderAnalysis, renderHistory } from "./ui/render.js"; +import { renderCharts } from "./ui/charts.js"; +import { buildMarkdownReport } from "./report/markdown.js"; +import { readJsonStorage } from "./utils/core.js"; + +const ui = getUiElements(); + +const state = { + currentUsername: "", + analysisResult: null, + abortController: null, + charts: { + language: null, + importance: null, + subscoreRadar: null, + activity: null + }, + history: readJsonStorage(STORAGE_KEYS.history, []) +}; + +class ApiError extends Error { + constructor(type, message, details = {}) { + super(message); + this.name = "ApiError"; + this.type = type; + this.details = details; + } +} + +init(); + +function init() { + bindEvents(); + + const savedTheme = localStorage.getItem(STORAGE_KEYS.theme) || "light"; + applyTheme(savedTheme); + + renderInitialState(ui); + renderHistory(state.history, ui, handleHistorySelect); + + if (state.history[0]) { + ui.profileInput.value = state.history[0]; + } +} + +function bindEvents() { + ui.analyzeBtn.addEventListener("click", handleAnalyze); + + ui.profileInput.addEventListener("keydown", (event) => { + if (event.key === "Enter") { + handleAnalyze(); + } + }); + + ui.themeToggleBtn.addEventListener("click", () => { + const currentTheme = document.documentElement.getAttribute("data-theme") || "light"; + const nextTheme = currentTheme === "dark" ? "light" : "dark"; + applyTheme(nextTheme); + + if (state.analysisResult) { + renderCharts(state.analysisResult, state, ui); + } + }); + + ui.downloadReportBtn.addEventListener("click", downloadMarkdownReport); +} + +async function handleAnalyze() { + clearBanners(); + + const parsed = parseProfileInput(ui.profileInput.value); + if (!parsed.ok) { + showError(parsed.error); + return; + } + + const username = parsed.username; + state.currentUsername = username; + ui.profileInput.value = username; + + if (state.abortController) { + state.abortController.abort(); + } + + const controller = new AbortController(); + state.abortController = controller; + + setLoading(true, "Preparing analysis..."); + + try { + let analysis = getCachedAnalysis(username); + + if (analysis) { + setLoading(true, "Loaded cached analysis from the last 10 minutes..."); + } else { + setLoading(true, "Analyzing GitHub profile via secure API..."); + analysis = await fetchAnalysisFromApi(username, controller.signal); + setCachedAnalysis(username, analysis); + } + + if (controller.signal.aborted) { + return; + } + + state.analysisResult = analysis; + ui.downloadReportBtn.disabled = false; + + saveHistory(username); + renderHistory(state.history, ui, handleHistorySelect); + + renderAnalysis(analysis, ui); + renderCharts(analysis, state, ui); + } catch (error) { + if (error.name === "AbortError") { + return; + } + handleAnalysisError(error); + } finally { + if (state.abortController === controller) { + state.abortController = null; + } + setLoading(false); + } +} + +async function fetchAnalysisFromApi(username, signal) { + const url = `${ANALYZE_ENDPOINT}?username=${encodeURIComponent(username)}`; + + let response; + try { + response = await fetch(url, { + method: "GET", + signal, + headers: { + Accept: "application/json" + } + }); + } catch (error) { + if (error.name === "AbortError") { + throw error; + } + throw new ApiError("Network", "Failed to reach analysis API.", { cause: error }); + } + + let payload = null; + try { + payload = await response.json(); + } catch { + payload = null; + } + + if (!response.ok || !payload || payload.ok !== true) { + const type = payload && payload.error && payload.error.type ? payload.error.type : mapStatusToType(response.status); + const message = + payload && payload.error && payload.error.message + ? payload.error.message + : `Analysis API failed with status ${response.status}.`; + + throw new ApiError(type, message, { + status: response.status, + resetAt: payload && payload.error ? payload.error.resetAt : response.headers.get("x-ratelimit-reset-at") + }); + } + + return payload.data; +} + +function mapStatusToType(status) { + if (status === 404) { + return "NotFound"; + } + if (status === 429) { + return "RateLimited"; + } + if (status === 400) { + return "Validation"; + } + if (status === 401 || status === 403) { + return "Unauthorized"; + } + return "Api"; +} + +function handleHistorySelect(username) { + ui.profileInput.value = username; + handleAnalyze(); +} + +function handleAnalysisError(error) { + if (!(error instanceof ApiError)) { + showError("Unexpected error while analyzing the profile."); + return; + } + + if (error.type === "NotFound") { + showError("Profile not found. Enter a valid GitHub username or GitHub profile URL."); + return; + } + + if (error.type === "RateLimited") { + showError("Rate limit reached. Please retry in a minute."); + showRateLimit(error.details.resetAt || null); + return; + } + + if (error.type === "Validation") { + showError(error.message || "Invalid username or URL input."); + return; + } + + if (error.type === "Unauthorized") { + showError("Server GitHub token is missing or invalid. Configure deployment environment variables."); + return; + } + + if (error.type === "Network") { + showError("Network issue while contacting analysis API. Please retry."); + return; + } + + showError(error.message || "Analysis request failed."); +} + +function downloadMarkdownReport() { + if (!state.analysisResult) { + showError("Run an analysis before downloading a report."); + return; + } + + const markdown = buildMarkdownReport(state.analysisResult); + const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8" }); + const url = URL.createObjectURL(blob); + + const anchor = document.createElement("a"); + anchor.href = url; + anchor.download = `${state.analysisResult.profile.login}-portfolio-report.md`; + anchor.click(); + + URL.revokeObjectURL(url); +} + +function saveHistory(username) { + const clean = (username || "").trim().toLowerCase(); + if (!clean) { + return; + } + + state.history = [clean, ...state.history.filter((item) => item !== clean)].slice(0, HISTORY_LIMIT); + localStorage.setItem(STORAGE_KEYS.history, JSON.stringify(state.history)); +} + +function setLoading(isLoading, message = "") { + ui.analyzeBtn.disabled = isLoading; + + if (isLoading) { + ui.loadingState.classList.remove("hidden"); + ui.loadingText.textContent = message || "Analyzing profile..."; + } else { + ui.loadingState.classList.add("hidden"); + ui.loadingText.textContent = "Analyzing profile..."; + } +} + +function clearBanners() { + ui.errorBanner.classList.add("hidden"); + ui.errorBanner.textContent = ""; + + ui.rateLimitBanner.classList.add("hidden"); + ui.rateLimitBanner.textContent = ""; +} + +function showError(message) { + ui.errorBanner.textContent = message; + ui.errorBanner.classList.remove("hidden"); +} + +function showRateLimit(resetAt) { + const when = resetAt ? new Date(resetAt).toLocaleString() : "the API reset window"; + ui.rateLimitBanner.textContent = `Rate limited. Retry after ${when}.`; + ui.rateLimitBanner.classList.remove("hidden"); +} + +function applyTheme(theme) { + const normalized = theme === "dark" ? "dark" : "light"; + document.documentElement.setAttribute("data-theme", normalized); + localStorage.setItem(STORAGE_KEYS.theme, normalized); + ui.themeToggleBtn.textContent = normalized === "dark" ? "Switch to Light" : "Switch to Dark"; +} + +function getCachedAnalysis(username) { + const key = `${CACHE_PREFIX}${username.toLowerCase()}`; + const payload = readJsonStorage(key, null); + + if (!payload || typeof payload !== "object") { + return null; + } + + const isFresh = Number(payload.savedAt) && Date.now() - Number(payload.savedAt) <= CACHE_TTL_MS; + + const hasExpectedShape = + payload.analysis && + typeof payload.analysis === "object" && + typeof payload.analysis.overallScore === "number" && + typeof payload.analysis.hireabilityScore === "number" && + payload.analysis.readiness && + payload.analysis.recruiterSimulation && + Array.isArray(payload.analysis.improvementRoadmap); + + if (!isFresh || !hasExpectedShape) { + localStorage.removeItem(key); + return null; + } + + return payload.analysis; +} + +function setCachedAnalysis(username, analysis) { + const key = `${CACHE_PREFIX}${username.toLowerCase()}`; + localStorage.setItem( + key, + JSON.stringify({ + savedAt: Date.now(), + analysis + }) + ); +} + +function parseProfileInput(rawInput) { + const value = (rawInput || "").trim(); + + if (!value) { + return { ok: false, error: "Enter a GitHub username or profile URL to analyze." }; + } + + let candidate = value; + + if (/github\.com\//i.test(candidate) && !/^https?:\/\//i.test(candidate)) { + candidate = `https://${candidate}`; + } + + if (/^https?:\/\//i.test(candidate)) { + try { + const url = new URL(candidate); + const host = url.hostname.toLowerCase(); + if (host !== "github.com" && host !== "www.github.com") { + return { ok: false, error: "URL must be a valid github.com profile URL." }; + } + + const segments = url.pathname.split("/").filter(Boolean); + if (!segments.length) { + return { ok: false, error: "GitHub URL is missing a username." }; + } + + candidate = segments[0]; + } catch { + return { ok: false, error: "Invalid URL format. Use a username or a github.com profile URL." }; + } + } + + candidate = candidate.replace(/^@+/, "").trim(); + + if (candidate.endsWith(".git")) { + candidate = candidate.slice(0, -4); + } + + const isValid = /^[A-Za-z0-9-]{1,39}$/.test(candidate) && !candidate.startsWith("-") && !candidate.endsWith("-"); + + if (!isValid) { + return { ok: false, error: "Invalid GitHub username format." }; + } + + return { ok: true, username: candidate.toLowerCase() }; +} diff --git a/src/report/markdown.js b/src/report/markdown.js new file mode 100644 index 0000000000..4e97ca39b7 --- /dev/null +++ b/src/report/markdown.js @@ -0,0 +1,104 @@ +import { formatDate, formatPercent, escapeMarkdown } from "../utils/core.js"; +import { getNamedSubscore } from "../config/constants.js"; + +export function buildMarkdownReport(result) { + const lines = []; + + lines.push("# GitHub Portfolio Analysis Report"); + lines.push(""); + lines.push(`- Generated: ${new Date(result.generatedAt).toLocaleString()}`); + lines.push(`- Profile: [${result.profile.name} (@${result.profile.login})](${result.profile.htmlUrl})`); + lines.push(`- Overall Score: **${result.overallScore}/100 (${result.grade})**`); + lines.push(`- Hireability Score: **${result.hireabilityScore}/100**`); + lines.push(`- Portfolio Readiness: **${result.readiness.label}**`); + lines.push(""); + + lines.push("## Score Summary"); + lines.push(result.scoreSummary); + lines.push(""); + + lines.push("## Subscores"); + lines.push("| Category | Score | Weight |"); + lines.push("| --- | ---: | ---: |"); + + Object.entries(result.subscores).forEach(([key, score]) => { + lines.push(`| ${escapeMarkdown(getNamedSubscore(key))} | ${score} | ${result.weights[key]}% |`); + }); + + lines.push(""); + lines.push("## Scoring Inputs (Transparency)"); + lines.push(`- Documentation Quality Inputs: README coverage ${formatPercent(result.metrics.readmeCoverage)}, description coverage ${formatPercent(result.metrics.descriptionCoverage)}`); + lines.push(`- Activity Inputs: active months ${result.metrics.activeMonthsLast6}/6, repos updated in 90 days ${formatPercent(result.metrics.reposUpdated90dRatio)}`); + lines.push(`- Popularity Inputs: stars/repo ${result.metrics.starsPerRepo.toFixed(2)}, forks/repo ${result.metrics.forksPerRepo.toFixed(2)}, watchers/repo ${result.metrics.watchersPerRepo.toFixed(2)}`); + lines.push(`- Completeness Inputs: non-empty ${formatPercent(result.metrics.nonEmptyRepoRatio)}, homepage ${formatPercent(result.metrics.homepageRatio)}, topics ${formatPercent(result.metrics.topicsRatio)}`); + lines.push(`- Diversity Inputs: unique languages ${result.metrics.uniqueLanguages}, entropy ${result.metrics.normalizedShannonEntropy.toFixed(2)}`); + lines.push(`- Recency Inputs: days since last push ${result.metrics.daysSinceLastPush}, repos updated in 30 days ${formatPercent(result.metrics.reposUpdated30dRatio)}`); + lines.push(`- Impact Inputs: top repo stars ${result.metrics.topRepoStars}, followers ${result.profile.followers}, PRs ${result.metrics.authoredPRCount}, issues ${result.metrics.authoredIssueCount}`); + + lines.push(""); + lines.push("## Strengths"); + result.strengths.forEach((item) => lines.push(`- ${escapeMarkdown(item)}`)); + + lines.push(""); + lines.push("## Red Flags"); + result.redFlags.forEach((item) => lines.push(`- ${escapeMarkdown(item)}`)); + + lines.push(""); + lines.push("## Actionable Suggestions"); + result.suggestions.forEach((item) => lines.push(`- ${escapeMarkdown(item)}`)); + + lines.push(""); + lines.push("## AI Recruiter Simulation"); + lines.push(`- Verdict: **${escapeMarkdown(result.recruiterSimulation.verdict)}**`); + lines.push(`- Summary: ${escapeMarkdown(result.recruiterSimulation.summary)}`); + lines.push("- Signals:"); + result.recruiterSimulation.signals.forEach((item) => lines.push(` - ${escapeMarkdown(item)}`)); + + lines.push(""); + lines.push("## Hidden Risks"); + result.hiddenRisks.forEach((item) => lines.push(`- ${escapeMarkdown(item)}`)); + + lines.push(""); + lines.push("## Career Path Recommendation"); + lines.push(`- Suggested Path: **${escapeMarkdown(result.careerPath.title)}**`); + lines.push(`- Confidence: ${result.careerPath.confidence}%`); + lines.push(`- Rationale: ${escapeMarkdown(result.careerPath.summary)}`); + lines.push("- Next Skill Targets:"); + result.careerPath.nextSkills.forEach((item) => lines.push(` - ${escapeMarkdown(item)}`)); + + lines.push(""); + lines.push("## Personalized Improvement Roadmap"); + result.improvementRoadmap.forEach((item, index) => lines.push(`${index + 1}. ${escapeMarkdown(item)}`)); + + lines.push(""); + lines.push("## Top Ranked Repositories"); + lines.push("| Repo | Importance | Stars | Forks | Watchers | Last Push | README |"); + lines.push("| --- | ---: | ---: | ---: | ---: | --- | --- |"); + + result.rankedRepos.slice(0, 10).forEach((repo) => { + lines.push( + `| [${escapeMarkdown(repo.name)}](${repo.url}) | ${repo.importance} | ${repo.stars} | ${repo.forks} | ${repo.watchers} | ${formatDate(repo.pushedAt)} | ${repo.readmeKnown ? (repo.hasReadme ? "Yes" : "No") : "Unknown"} |` + ); + }); + + lines.push(""); + lines.push("## Pinned Repositories"); + lines.push(`- Source: ${result.pinnedRepos.source}`); + result.pinnedRepos.items.forEach((repo) => { + lines.push(`- [${escapeMarkdown(repo.name)}](${repo.url}) - ${repo.stars} stars`); + }); + + lines.push(""); + lines.push("## Key Metrics"); + lines.push(`- Scorable repositories: ${result.metrics.scorableRepoCount}`); + lines.push(`- Total stars/forks/watchers: ${result.metrics.totalStars}/${result.metrics.totalForks}/${result.metrics.totalWatchers}`); + lines.push(`- README coverage (sampled): ${(result.metrics.readmeCoverage * 100).toFixed(1)}%`); + lines.push(`- Repositories updated in 30d/90d: ${result.metrics.reposUpdated30d}/${result.metrics.reposUpdated90d}`); + lines.push(`- Days since last push: ${result.metrics.daysSinceLastPush}`); + lines.push(`- Authored PRs/issues: ${result.metrics.authoredPRCount}/${result.metrics.authoredIssueCount}`); + lines.push(`- Unique languages: ${result.metrics.uniqueLanguages}`); + lines.push(`- Dominant language share: ${formatPercent(result.metrics.dominantLanguageShare)} (${result.metrics.dominantLanguage})`); + lines.push(`- Activity buckets (0-30/31-90/91-180/181+ days): ${result.metrics.activityBuckets.updated30d}/${result.metrics.activityBuckets.updated31to90d}/${result.metrics.activityBuckets.updated91to180d}/${result.metrics.activityBuckets.updated181plus}`); + + return lines.join("\n"); +} diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js deleted file mode 100644 index 5253d3ad9e..0000000000 --- a/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/src/setupTests.js b/src/setupTests.js deleted file mode 100644 index 8f2609b7b3..0000000000 --- a/src/setupTests.js +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom'; diff --git a/src/ui/charts.js b/src/ui/charts.js new file mode 100644 index 0000000000..1e24ed9127 --- /dev/null +++ b/src/ui/charts.js @@ -0,0 +1,179 @@ +import { getCssVar } from "../utils/core.js"; +import { getNamedSubscore } from "../config/constants.js"; + +export function renderCharts(result, state, ui) { + if ( + typeof Chart === "undefined" || + !ui.languageChart || + !ui.importanceChart || + !ui.subscoreRadarChart || + !ui.activityChart + ) { + return; + } + + const chartColors = [ + getCssVar("--chart-1"), + getCssVar("--chart-2"), + getCssVar("--chart-3"), + getCssVar("--chart-4"), + getCssVar("--chart-5"), + getCssVar("--chart-6") + ]; + + const axisColor = getCssVar("--muted"); + const borderColor = getCssVar("--border"); + + const languageEntries = Object.entries(result.languageTotals) + .sort((a, b) => b[1] - a[1]) + .slice(0, 8); + + const languageLabels = languageEntries.map(([label]) => label); + const languageValues = languageEntries.map(([, value]) => value); + const hasLanguageData = languageLabels.length > 0; + + const languageData = { + labels: hasLanguageData ? languageLabels : ["No data"], + datasets: [{ + data: hasLanguageData ? languageValues : [1], + backgroundColor: hasLanguageData ? chartColors : [borderColor], + borderWidth: 1, + borderColor + }] + }; + + destroyChart(state.charts.language); + state.charts.language = new Chart(ui.languageChart, { + type: "doughnut", + data: languageData, + options: { + maintainAspectRatio: false, + plugins: { + legend: { + labels: { color: axisColor } + } + } + } + }); + + const importanceRepos = result.rankedRepos.slice(0, 10); + destroyChart(state.charts.importance); + state.charts.importance = new Chart(ui.importanceChart, { + type: "bar", + data: { + labels: importanceRepos.map((repo) => repo.name), + datasets: [{ + label: "Importance", + data: importanceRepos.map((repo) => repo.importance), + backgroundColor: chartColors[0], + borderColor: chartColors[1], + borderWidth: 1 + }] + }, + options: { + maintainAspectRatio: false, + scales: { + x: { + ticks: { color: axisColor }, + grid: { color: borderColor } + }, + y: { + beginAtZero: true, + max: 100, + ticks: { color: axisColor }, + grid: { color: borderColor } + } + }, + plugins: { + legend: { + labels: { color: axisColor } + } + } + } + }); + + const radarLabels = Object.keys(result.subscores).map((key) => getNamedSubscore(key)); + const radarValues = Object.values(result.subscores); + + destroyChart(state.charts.subscoreRadar); + state.charts.subscoreRadar = new Chart(ui.subscoreRadarChart, { + type: "radar", + data: { + labels: radarLabels, + datasets: [{ + label: "Portfolio Dimensions", + data: radarValues, + backgroundColor: `${chartColors[0]}40`, + borderColor: chartColors[0], + borderWidth: 2, + pointBackgroundColor: chartColors[1] + }] + }, + options: { + maintainAspectRatio: false, + scales: { + r: { + min: 0, + max: 100, + ticks: { color: axisColor, backdropColor: "transparent" }, + angleLines: { color: borderColor }, + grid: { color: borderColor }, + pointLabels: { color: axisColor } + } + }, + plugins: { + legend: { + labels: { color: axisColor } + } + } + } + }); + + const bucketLabels = ["0-30d", "31-90d", "91-180d", "181d+"]; + const bucketValues = [ + result.metrics.activityBuckets.updated30d, + result.metrics.activityBuckets.updated31to90d, + result.metrics.activityBuckets.updated91to180d, + result.metrics.activityBuckets.updated181plus + ]; + + destroyChart(state.charts.activity); + state.charts.activity = new Chart(ui.activityChart, { + type: "bar", + data: { + labels: bucketLabels, + datasets: [{ + label: "Repo Count", + data: bucketValues, + backgroundColor: [chartColors[1], chartColors[2], chartColors[3], chartColors[4]], + borderWidth: 1, + borderColor + }] + }, + options: { + maintainAspectRatio: false, + scales: { + x: { + ticks: { color: axisColor }, + grid: { color: borderColor } + }, + y: { + beginAtZero: true, + ticks: { color: axisColor, precision: 0 }, + grid: { color: borderColor } + } + }, + plugins: { + legend: { + labels: { color: axisColor } + } + } + } + }); +} + +function destroyChart(chart) { + if (chart) { + chart.destroy(); + } +} diff --git a/src/ui/elements.js b/src/ui/elements.js new file mode 100644 index 0000000000..2930be0c61 --- /dev/null +++ b/src/ui/elements.js @@ -0,0 +1,62 @@ +export function getUiElements() { + return { + profileInput: document.getElementById("profileInput"), + analyzeBtn: document.getElementById("analyzeBtn"), + themeToggleBtn: document.getElementById("themeToggleBtn"), + downloadReportBtn: document.getElementById("downloadReportBtn"), + + loadingState: document.getElementById("loadingState"), + loadingText: document.getElementById("loadingText"), + errorBanner: document.getElementById("errorBanner"), + rateLimitBanner: document.getElementById("rateLimitBanner"), + + avatarImg: document.getElementById("avatarImg"), + profileName: document.getElementById("profileName"), + profileHandle: document.getElementById("profileHandle"), + profileLink: document.getElementById("profileLink"), + profileBio: document.getElementById("profileBio"), + + statRepos: document.getElementById("statRepos"), + statFollowers: document.getElementById("statFollowers"), + statFollowing: document.getElementById("statFollowing"), + statLastPush: document.getElementById("statLastPush"), + statPrCount: document.getElementById("statPrCount"), + statIssueCount: document.getElementById("statIssueCount"), + + pinnedSourceBadge: document.getElementById("pinnedSourceBadge"), + pinnedReposList: document.getElementById("pinnedReposList"), + historyList: document.getElementById("historyList"), + + overallScoreRing: document.getElementById("overallScoreRing"), + overallScore: document.getElementById("overallScore"), + scoreGrade: document.getElementById("scoreGrade"), + scoreSummary: document.getElementById("scoreSummary"), + hireabilityScore: document.getElementById("hireabilityScore"), + hireabilityHint: document.getElementById("hireabilityHint"), + readinessLevel: document.getElementById("readinessLevel"), + readinessHint: document.getElementById("readinessHint"), + readinessBar: document.getElementById("readinessBar"), + + strengthsList: document.getElementById("strengthsList"), + redFlagsList: document.getElementById("redFlagsList"), + suggestionsList: document.getElementById("suggestionsList"), + hiddenRisksList: document.getElementById("hiddenRisksList"), + + aiRecruiterVerdict: document.getElementById("aiRecruiterVerdict"), + aiRecruiterSummary: document.getElementById("aiRecruiterSummary"), + aiRecruiterSignals: document.getElementById("aiRecruiterSignals"), + + careerPathTitle: document.getElementById("careerPathTitle"), + careerPathSummary: document.getElementById("careerPathSummary"), + careerConfidence: document.getElementById("careerConfidence"), + careerSkillsList: document.getElementById("careerSkillsList"), + roadmapList: document.getElementById("roadmapList"), + + repoRankingTable: document.getElementById("repoRankingTable"), + + languageChart: document.getElementById("languageChart"), + importanceChart: document.getElementById("importanceChart"), + subscoreRadarChart: document.getElementById("subscoreRadarChart"), + activityChart: document.getElementById("activityChart") + }; +} diff --git a/src/ui/render.js b/src/ui/render.js new file mode 100644 index 0000000000..09cb02e7f0 --- /dev/null +++ b/src/ui/render.js @@ -0,0 +1,349 @@ +import { SUBSCORE_ID_MAP, SCORING_EXPLAIN_ID_MAP } from "../config/constants.js"; +import { + clearChildren, + appendEmptyState, + formatCompactNumber, + formatDate, + formatPercent, + getSeverity, + severityToChipClass, + severityColor +} from "../utils/core.js"; + +export function renderInitialState(ui) { + renderPinnedRepos({ source: "fallback", items: [] }, ui); + + renderInsightList(ui.strengthsList, ["No profile analyzed yet."], "neutral"); + renderInsightList(ui.redFlagsList, ["No profile analyzed yet."], "neutral"); + renderInsightList(ui.suggestionsList, ["No profile analyzed yet."], "neutral"); + renderInsightList(ui.hiddenRisksList, ["No hidden risk analysis yet."], "neutral"); + renderInsightList(ui.aiRecruiterSignals, ["Run an analysis to simulate recruiter feedback."], "neutral"); + + renderRoadmap(["Roadmap will appear after analysis."], ui); + renderCareerPath( + { + title: "Run an analysis to generate role fit", + confidence: 0, + summary: "Career path recommendations are generated from your public GitHub portfolio signals.", + nextSkills: ["Add repositories and analyze profile to unlock recommendations."] + }, + ui + ); + + ui.aiRecruiterVerdict.textContent = "Pending"; + ui.aiRecruiterVerdict.className = "chip chip-neutral"; + ui.aiRecruiterSummary.textContent = "Run an analysis to get recruiter-style interview feedback simulation."; + + ui.hireabilityScore.textContent = "--"; + ui.hireabilityHint.textContent = "Weighted recruiter-fit index"; + ui.readinessLevel.textContent = "--"; + ui.readinessHint.textContent = "Analyze a profile to classify readiness"; + ui.readinessBar.style.width = "0%"; +} + +export function renderAnalysis(result, ui) { + renderProfile(result, ui); + renderScore(result, ui); + renderSubscores(result.subscores); + renderScoringTransparency(result); + renderPinnedRepos(result.pinnedRepos, ui); + renderRecruiterSimulation(result.recruiterSimulation, ui); + renderInsightList(ui.strengthsList, result.strengths, "good"); + renderInsightList(ui.redFlagsList, result.redFlags, "risk"); + renderInsightList(ui.suggestionsList, result.suggestions, "warn"); + renderInsightList(ui.hiddenRisksList, result.hiddenRisks, "risk"); + renderCareerPath(result.careerPath, ui); + renderRoadmap(result.improvementRoadmap, ui); + renderRepoRanking(result.rankedRepos, ui); +} + +export function renderHistory(history, ui, onSelect) { + clearChildren(ui.historyList); + + if (!history.length) { + const empty = document.createElement("p"); + empty.className = "empty-state"; + empty.textContent = "No recent searches yet."; + ui.historyList.appendChild(empty); + return; + } + + history.forEach((username) => { + const button = document.createElement("button"); + button.type = "button"; + button.className = "history-chip"; + button.textContent = username; + button.addEventListener("click", () => onSelect(username)); + + ui.historyList.appendChild(button); + }); +} + +function renderProfile(result, ui) { + const profile = result.profile; + const metrics = result.metrics; + + ui.avatarImg.src = profile.avatarUrl || "Images/logo.png"; + ui.avatarImg.alt = `${profile.login} avatar`; + + ui.profileName.textContent = profile.name; + ui.profileHandle.textContent = `@${profile.login}`; + + ui.profileLink.href = profile.htmlUrl; + ui.profileLink.textContent = profile.htmlUrl; + + ui.profileBio.textContent = profile.bio || "No bio provided."; + + ui.statRepos.textContent = String(profile.publicRepos); + ui.statFollowers.textContent = formatCompactNumber(profile.followers); + ui.statFollowing.textContent = formatCompactNumber(profile.following); + ui.statLastPush.textContent = metrics.lastPushDate ? formatDate(metrics.lastPushDate) : "No push data"; + ui.statPrCount.textContent = formatCompactNumber(metrics.authoredPRCount); + ui.statIssueCount.textContent = formatCompactNumber(metrics.authoredIssueCount); +} + +function renderScore(result, ui) { + const severity = getSeverity(result.overallScore); + + ui.overallScore.textContent = String(result.overallScore); + ui.overallScoreRing.style.setProperty("--score-value", String(result.overallScore)); + ui.overallScoreRing.setAttribute("data-level", severity); + ui.scoreGrade.textContent = `Grade ${result.grade}`; + ui.scoreSummary.textContent = result.scoreSummary; + + const hireabilitySeverity = getSeverity(result.hireabilityScore); + ui.hireabilityScore.textContent = `${result.hireabilityScore}/100`; + ui.hireabilityScore.style.color = severityColor(hireabilitySeverity); + ui.hireabilityHint.textContent = "Calibrated from score, impact, recency, and hidden-risk penalties."; + + ui.readinessLevel.textContent = result.readiness.label; + ui.readinessLevel.style.color = severityColor(result.readiness.severity); + ui.readinessHint.textContent = result.readiness.summary; + ui.readinessBar.style.width = `${result.readiness.percent}%`; +} + +function renderSubscores(subscores) { + Object.entries(SUBSCORE_ID_MAP).forEach(([key, elementId]) => { + const element = document.getElementById(elementId); + const value = subscores[key]; + const severity = getSeverity(value); + + element.textContent = `${value}/100`; + element.className = `chip ${severityToChipClass(severity)}`; + }); +} + +function renderScoringTransparency(result) { + const { subscores, metrics } = result; + const details = { + documentationQuality: `README ${formatPercent(metrics.readmeCoverage)}, Desc ${formatPercent(metrics.descriptionCoverage)}`, + codeActivityConsistency: `${metrics.activeMonthsLast6}/6 months, ${formatPercent(metrics.reposUpdated90dRatio)} updated`, + projectPopularity: `Stars ${metrics.starsPerRepo.toFixed(1)}/repo, Forks ${metrics.forksPerRepo.toFixed(1)}/repo`, + repositoryCompleteness: `Non-empty ${formatPercent(metrics.nonEmptyRepoRatio)}, Topics ${formatPercent(metrics.topicsRatio)}`, + languageDiversity: `${metrics.uniqueLanguages} langs, Entropy ${metrics.normalizedShannonEntropy.toFixed(2)}`, + recentActivity: `${metrics.daysSinceLastPush}d last push, ${formatPercent(metrics.reposUpdated30dRatio)} updated`, + impactSignals: `Top repo ⭐ ${metrics.topRepoStars}, PRs ${metrics.authoredPRCount}, Issues ${metrics.authoredIssueCount}` + }; + + Object.entries(SCORING_EXPLAIN_ID_MAP).forEach(([key, elementId]) => { + const element = document.getElementById(elementId); + if (!element) { + return; + } + + const score = subscores[key]; + const severity = getSeverity(score); + element.textContent = `${score}/100 • ${details[key]}`; + element.className = `chip ${severityToChipClass(severity)}`; + }); +} + +function renderRecruiterSimulation(simulation, ui) { + if (!simulation) { + ui.aiRecruiterVerdict.textContent = "Pending"; + ui.aiRecruiterVerdict.className = "chip chip-neutral"; + ui.aiRecruiterSummary.textContent = "Run an analysis to get recruiter-style interview feedback simulation."; + renderInsightList(ui.aiRecruiterSignals, ["No recruiter simulation available."], "neutral"); + return; + } + + ui.aiRecruiterVerdict.textContent = simulation.verdict; + ui.aiRecruiterVerdict.className = `chip ${severityToChipClass(simulation.level || "warn")}`; + ui.aiRecruiterSummary.textContent = simulation.summary; + renderInsightList(ui.aiRecruiterSignals, simulation.signals, simulation.level || "warn"); +} + +function renderCareerPath(careerPath, ui) { + if (!careerPath) { + ui.careerPathTitle.textContent = "No career path recommendation"; + ui.careerPathSummary.textContent = "Run an analysis to unlock role fit recommendations."; + ui.careerConfidence.textContent = "--"; + ui.careerConfidence.className = "chip chip-neutral"; + renderInsightList(ui.careerSkillsList, ["No recommendations yet."], "neutral"); + return; + } + + ui.careerPathTitle.textContent = careerPath.title; + ui.careerPathSummary.textContent = careerPath.summary; + ui.careerConfidence.textContent = `${careerPath.confidence}% confidence`; + ui.careerConfidence.className = `chip ${severityToChipClass(getSeverity(careerPath.confidence))}`; + renderInsightList(ui.careerSkillsList, careerPath.nextSkills, "warn"); +} + +function renderRoadmap(roadmapItems, ui) { + clearChildren(ui.roadmapList); + + if (!Array.isArray(roadmapItems) || !roadmapItems.length) { + const li = document.createElement("li"); + li.textContent = "No roadmap available."; + ui.roadmapList.appendChild(li); + return; + } + + roadmapItems.forEach((item) => { + const li = document.createElement("li"); + li.textContent = item; + ui.roadmapList.appendChild(li); + }); +} + +function renderPinnedRepos(pinnedRepos, ui) { + clearChildren(ui.pinnedReposList); + + ui.pinnedSourceBadge.textContent = pinnedRepos.source; + ui.pinnedSourceBadge.className = `chip ${pinnedRepos.source === "graphql" ? "chip-good" : "chip-warn"}`; + + if (!pinnedRepos.items.length) { + appendEmptyState(ui.pinnedReposList, "No pinned repositories available."); + return; + } + + pinnedRepos.items.forEach((repo) => { + const li = document.createElement("li"); + li.className = "repo-item"; + + const left = document.createElement("div"); + const link = document.createElement("a"); + link.href = repo.url; + link.target = "_blank"; + link.rel = "noopener noreferrer"; + link.textContent = repo.name; + link.className = "repo-link"; + + left.appendChild(link); + + const meta = document.createElement("div"); + meta.className = "repo-item-meta"; + meta.textContent = `Stars: ${formatCompactNumber(repo.stars)}`; + + li.appendChild(left); + li.appendChild(meta); + + ui.pinnedReposList.appendChild(li); + }); +} + +export function renderInsightList(container, items, tone) { + clearChildren(container); + + if (!items || !items.length) { + appendEmptyState(container, "No insights available."); + return; + } + + items.forEach((item) => { + const li = document.createElement("li"); + li.textContent = item; + + if (tone === "good") { + li.classList.add("chip-good"); + } else if (tone === "warn") { + li.classList.add("chip-warn"); + } else if (tone === "risk") { + li.classList.add("chip-risk"); + } + + container.appendChild(li); + }); +} + +function renderRepoRanking(rankedRepos, ui) { + clearChildren(ui.repoRankingTable); + + if (!rankedRepos.length) { + const row = document.createElement("tr"); + const cell = document.createElement("td"); + cell.colSpan = 5; + cell.textContent = "No repositories available for ranking."; + cell.className = "empty-state"; + row.appendChild(cell); + ui.repoRankingTable.appendChild(row); + return; + } + + rankedRepos.slice(0, 15).forEach((repo) => { + const row = document.createElement("tr"); + + const repoCell = document.createElement("td"); + const link = document.createElement("a"); + link.href = repo.url; + link.target = "_blank"; + link.rel = "noopener noreferrer"; + link.textContent = repo.name; + link.className = "repo-link"; + + const langMeta = document.createElement("div"); + langMeta.className = "repo-item-meta"; + langMeta.textContent = repo.language; + + repoCell.appendChild(link); + repoCell.appendChild(langMeta); + + const importanceCell = document.createElement("td"); + const wrap = document.createElement("div"); + wrap.className = "importance-wrap"; + + const meter = document.createElement("div"); + meter.className = "importance-meter"; + const fill = document.createElement("span"); + fill.style.width = `${repo.importance}%`; + meter.appendChild(fill); + + const importanceText = document.createElement("span"); + importanceText.textContent = String(repo.importance); + + wrap.appendChild(meter); + wrap.appendChild(importanceText); + importanceCell.appendChild(wrap); + + const statsCell = document.createElement("td"); + statsCell.textContent = `${repo.stars} / ${repo.forks} / ${repo.watchers}`; + + const pushedCell = document.createElement("td"); + pushedCell.textContent = repo.pushedAt ? formatDate(repo.pushedAt) : "Unknown"; + + const readmeCell = document.createElement("td"); + const readmeChip = document.createElement("span"); + + if (repo.readmeKnown && repo.hasReadme) { + readmeChip.textContent = "Yes"; + readmeChip.className = "chip chip-good"; + } else if (repo.readmeKnown && !repo.hasReadme) { + readmeChip.textContent = "No"; + readmeChip.className = "chip chip-risk"; + } else { + readmeChip.textContent = "Unknown"; + readmeChip.className = "chip chip-neutral"; + } + + readmeCell.appendChild(readmeChip); + + row.appendChild(repoCell); + row.appendChild(importanceCell); + row.appendChild(statsCell); + row.appendChild(pushedCell); + row.appendChild(readmeCell); + + ui.repoRankingTable.appendChild(row); + }); +} diff --git a/src/utils/core.js b/src/utils/core.js new file mode 100644 index 0000000000..44ea19410d --- /dev/null +++ b/src/utils/core.js @@ -0,0 +1,160 @@ +export function cap01(value) { + if (!Number.isFinite(value)) { + return 0; + } + return Math.max(0, Math.min(1, value)); +} + +export function clampToRange(value, min, max) { + return Math.min(max, Math.max(min, value)); +} + +export function safeRatio(numerator, denominator) { + if (!denominator) { + return 0; + } + return numerator / denominator; +} + +export function scoreFromRatio(ratio) { + return clampToRange(Math.round(cap01(ratio) * 100), 0, 100); +} + +export function formatDate(value) { + if (!value) { + return "Unknown"; + } + + const date = new Date(value); + if (Number.isNaN(date.getTime())) { + return "Unknown"; + } + + return date.toLocaleDateString(undefined, { + year: "numeric", + month: "short", + day: "numeric" + }); +} + +export function daysSinceDate(value, nowMs = Date.now()) { + if (!value) { + return Number.POSITIVE_INFINITY; + } + + const date = new Date(value); + if (Number.isNaN(date.getTime())) { + return Number.POSITIVE_INFINITY; + } + + return Math.floor((nowMs - date.getTime()) / 86400000); +} + +export function formatCompactNumber(value) { + const num = Number(value) || 0; + return new Intl.NumberFormat(undefined, { notation: "compact", maximumFractionDigits: 1 }).format(num); +} + +export function formatPercent(value) { + return `${Math.round(cap01(value) * 100)}%`; +} + +export function joinRepoNames(names) { + if (!names.length) { + return "target repositories"; + } + return names.map((name) => `\`${name}\``).join(", "); +} + +export function dedupe(items) { + return items.filter((item, index) => items.indexOf(item) === index); +} + +export function readJsonStorage(key, fallback) { + try { + const raw = localStorage.getItem(key); + if (!raw) { + return fallback; + } + return JSON.parse(raw); + } catch { + return fallback; + } +} + +export function clearChildren(node) { + while (node.firstChild) { + node.removeChild(node.firstChild); + } +} + +export function appendEmptyState(container, text) { + const li = document.createElement("li"); + li.className = "empty-state"; + li.textContent = text; + container.appendChild(li); +} + +export function getCssVar(name) { + return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); +} + +export function escapeMarkdown(text) { + return String(text).replace(/[|]/g, "\\|"); +} + +export function getSeverity(score) { + if (score >= 70) { + return "good"; + } + if (score >= 40) { + return "warn"; + } + return "risk"; +} + +export function severityToChipClass(severity) { + if (severity === "good") { + return "chip-good"; + } + if (severity === "warn") { + return "chip-warn"; + } + return "chip-risk"; +} + +export function severityColor(severity) { + if (severity === "good") { + return getCssVar("--good"); + } + if (severity === "warn") { + return getCssVar("--warn"); + } + return getCssVar("--risk"); +} + +export async function mapWithConcurrency(items, concurrency, worker) { + if (!items.length) { + return []; + } + + const results = new Array(items.length); + let currentIndex = 0; + + const runner = async () => { + while (currentIndex < items.length) { + const index = currentIndex; + currentIndex += 1; + results[index] = await worker(items[index], index); + } + }; + + const workers = []; + const count = Math.min(concurrency, items.length); + for (let i = 0; i < count; i += 1) { + workers.push(runner()); + } + + await Promise.all(workers); + return results; +} diff --git a/style.css b/style.css new file mode 100644 index 0000000000..ab6bd0c694 --- /dev/null +++ b/style.css @@ -0,0 +1,1099 @@ +:root { + --bg: #f1f6ff; + --bg-gradient-a: #f9fcff; + --bg-gradient-b: #e4efff; + --surface: #ffffffcc; + --surface-solid: #ffffff; + --surface-soft: #f3f7ff; + --text: #19253a; + --muted: #5a6f8f; + --border: #d3e0f6; + --accent: #0f67f5; + --accent-strong: #0e4dc8; + --accent-soft: #81bcff; + --accent-glow: rgba(15, 103, 245, 0.24); + --good: #177245; + --warn: #a06000; + --risk: #a3213d; + --shadow: 0 24px 56px rgba(17, 40, 84, 0.12); + --hero-shadow: 0 32px 64px rgba(20, 60, 131, 0.18); + --chart-1: #1f6feb; + --chart-2: #0f9d58; + --chart-3: #f2994a; + --chart-4: #6f42c1; + --chart-5: #e83e8c; + --chart-6: #00838f; +} + +:root[data-theme="dark"] { + --bg: #091321; + --bg-gradient-a: #0e1d33; + --bg-gradient-b: #060d17; + --surface: #15253bcc; + --surface-solid: #15253b; + --surface-soft: #1a304c; + --text: #edf3ff; + --muted: #93aacc; + --border: #28425f; + --accent: #58a6ff; + --accent-strong: #3f8ce8; + --accent-soft: #8ec4ff; + --accent-glow: rgba(88, 166, 255, 0.26); + --good: #4fd694; + --warn: #f0ad4e; + --risk: #ff7b91; + --shadow: 0 28px 64px rgba(0, 0, 0, 0.42); + --hero-shadow: 0 34px 72px rgba(0, 0, 0, 0.5); + --chart-1: #58a6ff; + --chart-2: #4fd694; + --chart-3: #f0ad4e; + --chart-4: #c297ff; + --chart-5: #ff9ccd; + --chart-6: #56cfd6; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + min-height: 100vh; + font-family: "Manrope", "Segoe UI", sans-serif; + color: var(--text); + background: + radial-gradient(circle at 10% -5%, var(--accent-glow), transparent 34%), + radial-gradient(circle at 92% 10%, rgba(22, 190, 255, 0.11), transparent 28%), + linear-gradient(180deg, var(--bg-gradient-a) 0%, var(--bg-gradient-b) 100%); +} + +h1, +h2, +h3, +h4, +button, +input, +code { + font-family: "Space Mono", monospace; +} + +a { + color: var(--accent); +} + +.muted { + color: var(--muted); +} + +.hidden { + display: none !important; +} + +.app-shell { + width: min(1280px, 100% - 2rem); + margin: 1.2rem auto 2.8rem; +} + +.topbar { + margin-bottom: 1rem; + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + flex-wrap: wrap; +} + +.brand { + display: flex; + gap: 1rem; + align-items: center; +} + +.brand-logo { + width: 56px; + height: 56px; + object-fit: contain; + border-radius: 12px; + background: var(--surface); + border: 1px solid var(--border); + box-shadow: var(--shadow); +} + +.brand h1 { + margin: 0; + font-size: clamp(1.2rem, 2vw, 1.6rem); +} + +.brand p { + margin: 0.25rem 0 0; + color: var(--muted); + font-size: 0.9rem; +} + +.topbar-pills { + display: flex; + gap: 0.45rem; + flex-wrap: wrap; +} + +.top-pill { + border-radius: 999px; + border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border)); + background: color-mix(in srgb, var(--accent) 10%, var(--surface-soft)); + color: var(--accent-strong); + font-size: 0.7rem; + padding: 0.22rem 0.58rem; +} + +.hero-shell { + display: grid; + grid-template-columns: minmax(360px, 1.1fr) minmax(260px, 0.75fr); + gap: 0.9rem; + margin-bottom: 0.9rem; +} + +.hero-copy, +.hero-mascot { + position: relative; + overflow: hidden; +} + +.hero-copy::before { + content: ""; + position: absolute; + width: 260px; + height: 260px; + right: -120px; + top: -130px; + border-radius: 50%; + background: radial-gradient(circle, color-mix(in srgb, var(--accent) 20%, transparent), transparent 70%); +} + +.eyebrow { + margin: 0; + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 0.68rem; + color: var(--accent-strong); +} + +.hero-copy h2 { + margin: 0.42rem 0 0; + font-size: clamp(1.35rem, 3vw, 2.2rem); + line-height: 1.18; + max-width: 18ch; +} + +.hero-subtitle { + margin: 0.62rem 0 0; + color: var(--muted); + line-height: 1.5; + max-width: 58ch; + font-size: 0.9rem; +} + +.hero-points { + display: flex; + gap: 0.45rem; + margin-top: 0.85rem; + flex-wrap: wrap; +} + +.hero-chip { + font-size: 0.72rem; + border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--border)); + color: var(--accent-strong); + background: color-mix(in srgb, var(--accent) 10%, var(--surface-soft)); + border-radius: 999px; + padding: 0.28rem 0.62rem; +} + +.hero-mascot { + background: + radial-gradient(circle at 85% 10%, color-mix(in srgb, var(--accent-soft) 38%, transparent), transparent 42%), + linear-gradient(165deg, color-mix(in srgb, var(--surface-soft) 78%, transparent), var(--surface)); + box-shadow: var(--hero-shadow); + display: grid; + place-items: center; + align-content: center; + gap: 0.35rem; +} + +.mascot-wrap { + width: min(240px, 100%); + position: relative; +} + +.mascot-art { + width: 100%; + height: auto; + display: block; + position: relative; + z-index: 1; +} + +.mascot-glow { + position: absolute; + inset: auto 12% -8% 12%; + height: 34px; + border-radius: 50%; + background: color-mix(in srgb, var(--accent) 28%, transparent); + filter: blur(10px); +} + +.mascot-line { + margin: 0; + font-size: 0.76rem; + color: var(--muted); + text-align: center; + max-width: 28ch; +} + +.card { + background: var(--surface); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + border: 1px solid var(--border); + border-radius: 18px; + box-shadow: var(--shadow); + padding: 1rem; + animation: card-in 220ms ease-out; + transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease; +} + +.card:hover { + transform: translateY(-2px); + border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); + box-shadow: 0 30px 58px rgba(16, 38, 83, 0.18); +} + +@keyframes card-in { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.controls-card { + margin-bottom: 0.85rem; + background: + radial-gradient(circle at 85% 0%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 38%), + var(--surface); +} + +.controls-grid { + display: grid; + grid-template-columns: 1fr auto; + gap: 0.8rem; + align-items: end; +} + +.field { + display: flex; + flex-direction: column; + gap: 0.45rem; +} + +.field label { + font-size: 0.78rem; + color: var(--muted); + display: inline-flex; + align-items: center; + gap: 0.36rem; +} + +.tooltip { + width: 17px; + height: 17px; + border-radius: 50%; + display: inline-grid; + place-items: center; + font-size: 0.62rem; + border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border)); + color: var(--accent-strong); + background: color-mix(in srgb, var(--accent) 10%, var(--surface-soft)); + cursor: help; + position: relative; + user-select: none; +} + +.tooltip::after { + content: attr(data-tooltip); + position: absolute; + left: 50%; + bottom: calc(100% + 8px); + transform: translateX(-50%); + min-width: 210px; + max-width: 240px; + border-radius: 10px; + border: 1px solid var(--border); + background: var(--surface-solid); + color: var(--text); + padding: 0.4rem 0.5rem; + font-size: 0.68rem; + line-height: 1.35; + box-shadow: var(--shadow); + opacity: 0; + pointer-events: none; + transition: opacity 140ms ease; + z-index: 3; +} + +.tooltip:hover::after { + opacity: 1; +} + +input { + width: 100%; + border: 1px solid var(--border); + border-radius: 10px; + background: var(--surface-soft); + color: var(--text); + padding: 0.68rem 0.75rem; + font-size: 0.88rem; + transition: border-color 150ms ease, box-shadow 150ms ease, transform 120ms ease; +} + +input:focus { + border-color: var(--accent); + outline: none; + box-shadow: 0 0 0 3px rgba(31, 111, 235, 0.15); +} + +.hint { + margin: 0; + color: var(--muted); + font-size: 0.72rem; + line-height: 1.35; +} + +.button-group { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: flex-end; +} + +.btn { + border: 1px solid var(--border); + background: var(--surface-soft); + color: var(--text); + border-radius: 10px; + font-size: 0.78rem; + padding: 0.62rem 0.82rem; + cursor: pointer; + transition: transform 140ms ease, border-color 140ms ease, box-shadow 140ms ease; +} + +.btn:hover:not(:disabled) { + transform: translateY(-1px); + border-color: var(--accent); + box-shadow: 0 10px 22px color-mix(in srgb, var(--accent) 22%, transparent); +} + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.btn-primary { + background: linear-gradient(120deg, var(--accent), var(--accent-strong)); + border-color: transparent; + color: #ffffff; +} + +.btn-primary:hover:not(:disabled) { + box-shadow: 0 14px 28px color-mix(in srgb, var(--accent) 44%, transparent); +} + +.status-stack { + display: grid; + gap: 0.5rem; + margin-bottom: 0.9rem; +} + +.status { + border-radius: 12px; + padding: 0.65rem 0.8rem; + border: 1px solid; + display: flex; + align-items: center; + gap: 0.55rem; + font-size: 0.82rem; +} + +.status-loading { + color: var(--accent-strong); + background: color-mix(in srgb, var(--accent) 10%, transparent); + border-color: color-mix(in srgb, var(--accent) 28%, var(--border)); +} + +.status-error { + color: var(--risk); + background: color-mix(in srgb, var(--risk) 10%, transparent); + border-color: color-mix(in srgb, var(--risk) 32%, var(--border)); +} + +.status-warn { + color: var(--warn); + background: color-mix(in srgb, var(--warn) 10%, transparent); + border-color: color-mix(in srgb, var(--warn) 32%, var(--border)); +} + +.status-success { + color: var(--good); + background: color-mix(in srgb, var(--good) 10%, transparent); + border-color: color-mix(in srgb, var(--good) 34%, var(--border)); +} + +.skeleton-panel { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.8rem; + margin-bottom: 0.9rem; +} + +.skeleton-card { + border: 1px solid var(--border); + border-radius: 16px; + background: var(--surface); + padding: 0.85rem; + box-shadow: var(--shadow); + display: grid; + gap: 0.6rem; +} + +.skeleton-line, +.skeleton-pill { + border-radius: 8px; + position: relative; + overflow: hidden; + background: color-mix(in srgb, var(--surface-soft) 65%, var(--border)); +} + +.skeleton-line::after, +.skeleton-pill::after { + content: ""; + position: absolute; + inset: 0; + transform: translateX(-100%); + background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent-soft) 34%, transparent), transparent); + animation: shimmer 1.2s infinite; +} + +.skeleton-line { + height: 12px; +} + +.skeleton-line-lg { + height: 18px; + width: 72%; +} + +.skeleton-line-sm { + width: 42%; +} + +.skeleton-grid-mini { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.5rem; +} + +.skeleton-pill { + height: 28px; +} + +@keyframes shimmer { + 100% { + transform: translateX(100%); + } +} + +.spinner { + width: 14px; + height: 14px; + border-radius: 50%; + border: 2px solid transparent; + border-top-color: currentColor; + border-right-color: currentColor; + animation: spin 0.9s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.layout { + display: grid; + grid-template-columns: minmax(300px, 0.9fr) minmax(420px, 1.45fr); + gap: 0.9rem; +} + +.left-column, +.right-column { + display: grid; + gap: 0.85rem; + align-content: start; +} + +.profile-header { + display: flex; + align-items: center; + gap: 0.8rem; +} + +.avatar { + width: 76px; + height: 76px; + border-radius: 14px; + border: 1px solid var(--border); + object-fit: cover; + background: var(--surface-soft); +} + +.profile-meta h2 { + margin: 0; + font-size: 1.03rem; +} + +.profile-meta p { + margin: 0.2rem 0; + font-size: 0.85rem; +} + +.profile-meta a { + font-size: 0.82rem; +} + +.profile-card #profileBio { + margin: 0.9rem 0 0.6rem; + font-size: 0.88rem; + line-height: 1.45; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.55rem; +} + +.stat-card { + background: var(--surface-soft); + border: 1px solid var(--border); + border-radius: 10px; + padding: 0.55rem 0.6rem; + display: grid; + gap: 0.3rem; +} + +.stat-card span { + color: var(--muted); + font-size: 0.72rem; +} + +.stat-card strong { + font-size: 1rem; +} + +.card-title-row { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.5rem; +} + +.section-title { + margin: 0; + font-size: 1rem; +} + +.item-list, +.insight-list { + margin: 0.65rem 0 0; + padding: 0; + list-style: none; + display: grid; + gap: 0.5rem; +} + +.item-list li, +.insight-list li { + border: 1px solid var(--border); + background: var(--surface-soft); + border-radius: 10px; + padding: 0.55rem 0.65rem; + font-size: 0.82rem; + line-height: 1.4; + transition: transform 160ms ease, border-color 160ms ease; +} + +.item-list li:hover, +.insight-list li:hover { + transform: translateX(2px); + border-color: color-mix(in srgb, var(--accent) 28%, var(--border)); +} + +.repo-item { + display: flex; + justify-content: space-between; + gap: 0.6rem; + align-items: center; +} + +.repo-item-meta { + color: var(--muted); + font-size: 0.74rem; +} + +.history-list { + display: flex; + flex-wrap: wrap; + gap: 0.45rem; + margin-top: 0.65rem; +} + +.history-chip { + border: 1px solid var(--border); + background: var(--surface-soft); + color: var(--text); + border-radius: 999px; + padding: 0.38rem 0.66rem; + font-size: 0.73rem; + cursor: pointer; +} + +.history-chip:hover { + border-color: var(--accent); +} + +.score-head { + display: grid; + grid-template-columns: auto 1fr; + gap: 0.9rem; + align-items: center; +} + +.score-head h2 { + margin: 0; + font-size: 1rem; +} + +.score-grade { + margin: 0.35rem 0; + font-size: 0.92rem; +} + +.score-ring { + --score-value: 0; + --ring-color: var(--accent); + width: 128px; + height: 128px; + border-radius: 50%; + position: relative; + display: grid; + place-items: center; + background: conic-gradient(var(--ring-color) calc(var(--score-value) * 1%), var(--border) 0); + transition: background 220ms ease; +} + +.score-ring::before { + content: ""; + position: absolute; + inset: 12px; + border-radius: 50%; + background: var(--surface); + border: 1px solid var(--border); +} + +.score-ring[data-level="good"] { + --ring-color: var(--good); +} + +.score-ring[data-level="warn"] { + --ring-color: var(--warn); +} + +.score-ring[data-level="risk"] { + --ring-color: var(--risk); +} + +.score-value { + position: relative; + z-index: 1; + font-size: 1.6rem; + font-weight: 800; +} + +.premium-score-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.55rem; + margin-top: 0.75rem; +} + +.premium-score-item { + border: 1px solid var(--border); + border-radius: 12px; + background: linear-gradient(145deg, var(--surface-soft), color-mix(in srgb, var(--surface-soft) 75%, var(--surface))); + padding: 0.55rem 0.62rem; + display: grid; + gap: 0.2rem; +} + +.premium-score-item span { + color: var(--muted); + font-size: 0.7rem; +} + +.premium-score-item strong { + font-size: 1rem; + letter-spacing: 0.02em; +} + +.premium-score-item small { + color: var(--muted); + font-size: 0.68rem; + line-height: 1.35; +} + +.readiness-track { + margin-top: 0.6rem; + height: 8px; + border-radius: 999px; + background: color-mix(in srgb, var(--accent) 14%, var(--surface-soft)); + overflow: hidden; +} + +.readiness-track span { + display: block; + width: 0; + height: 100%; + border-radius: 999px; + background: linear-gradient(120deg, var(--accent), var(--accent-strong)); + transition: width 280ms ease; +} + +.subscore-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.5rem; + margin-top: 0.95rem; +} + +.subscore-item { + border: 1px solid var(--border); + border-radius: 10px; + background: var(--surface-soft); + padding: 0.45rem 0.55rem; + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.45rem; + font-size: 0.74rem; +} + +.chip { + display: inline-flex; + align-items: center; + border-radius: 999px; + padding: 0.22rem 0.55rem; + font-size: 0.7rem; + border: 1px solid; + white-space: nowrap; +} + +.chip-neutral { + color: var(--muted); + border-color: var(--border); + background: transparent; +} + +.chip-good { + color: var(--good); + border-color: color-mix(in srgb, var(--good) 50%, var(--border)); + background: color-mix(in srgb, var(--good) 12%, transparent); +} + +.chip-warn { + color: var(--warn); + border-color: color-mix(in srgb, var(--warn) 55%, var(--border)); + background: color-mix(in srgb, var(--warn) 12%, transparent); +} + +.chip-risk { + color: var(--risk); + border-color: color-mix(in srgb, var(--risk) 55%, var(--border)); + background: color-mix(in srgb, var(--risk) 12%, transparent); +} + +.insights-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.8rem; +} + +.insights-grid h3 { + margin: 0; + font-size: 0.92rem; +} + +.recruiter-sim-card { + background: + radial-gradient(circle at 90% 0%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 38%), + var(--surface); +} + +#aiRecruiterSummary { + margin: 0.5rem 0 0.2rem; + line-height: 1.5; + font-size: 0.84rem; +} + +.career-title { + margin: 0.55rem 0 0.35rem; + font-size: 0.96rem; +} + +.roadmap-list { + margin: 0.72rem 0 0; + padding: 0; + list-style: none; + display: grid; + gap: 0.58rem; + counter-reset: roadmap; +} + +.roadmap-list li { + counter-increment: roadmap; + border: 1px solid var(--border); + border-radius: 12px; + background: var(--surface-soft); + padding: 0.6rem 0.65rem 0.6rem 2.2rem; + position: relative; + font-size: 0.82rem; + line-height: 1.45; +} + +.roadmap-list li::before { + content: counter(roadmap); + position: absolute; + left: 0.6rem; + top: 0.6rem; + width: 1.1rem; + height: 1.1rem; + border-radius: 50%; + display: grid; + place-items: center; + font-size: 0.66rem; + color: #fff; + background: linear-gradient(120deg, var(--accent), var(--accent-strong)); +} + +.transparency-note { + margin: 0.45rem 0 0.8rem; + font-size: 0.79rem; + line-height: 1.4; +} + +.formula-grid { + display: grid; + gap: 0.55rem; +} + +.formula-row { + display: flex; + justify-content: space-between; + gap: 0.8rem; + align-items: center; + border: 1px solid var(--border); + border-radius: 10px; + background: var(--surface-soft); + padding: 0.55rem 0.65rem; +} + +.formula-row strong { + display: block; + font-size: 0.76rem; + margin-bottom: 0.2rem; +} + +.formula-row p { + margin: 0; + color: var(--muted); + font-size: 0.7rem; + line-height: 1.35; +} + +.formula-row .chip { + white-space: normal; + text-align: right; + max-width: 48%; +} + +.chart-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.7rem; + margin-top: 0.75rem; +} + +.chart-panel { + border: 1px solid var(--border); + border-radius: 12px; + padding: 0.55rem; + background: var(--surface-soft); +} + +.chart-panel h3 { + margin: 0 0 0.35rem; + font-size: 0.82rem; + color: var(--muted); +} + +.chart-panel canvas { + width: 100% !important; + height: 260px !important; +} + +.table-wrap { + overflow-x: auto; + margin-top: 0.75rem; +} + +.table-wrap table { + width: 100%; + border-collapse: collapse; + min-width: 680px; +} + +.table-wrap th, +.table-wrap td { + border-bottom: 1px solid var(--border); + padding: 0.55rem; + text-align: left; + font-size: 0.78rem; + vertical-align: middle; +} + +.table-wrap th { + color: var(--muted); + font-weight: 700; +} + +.repo-link { + font-weight: 700; + text-decoration: none; +} + +.importance-wrap { + display: flex; + align-items: center; + gap: 0.45rem; +} + +.importance-meter { + width: 90px; + height: 8px; + border-radius: 999px; + background: color-mix(in srgb, var(--accent) 18%, var(--surface-soft)); + overflow: hidden; +} + +.importance-meter span { + display: block; + height: 100%; + background: linear-gradient(120deg, var(--accent), var(--accent-strong)); +} + +.empty-state { + color: var(--muted); + font-size: 0.78rem; +} + +@media (prefers-reduced-motion: reduce) { + * { + animation: none !important; + transition: none !important; + scroll-behavior: auto !important; + } +} + +@media (max-width: 1120px) { + .controls-grid { + grid-template-columns: 1fr; + } + + .button-group { + justify-content: flex-start; + } + + .layout { + grid-template-columns: 1fr; + } + + .insights-grid { + grid-template-columns: 1fr; + } + + .formula-row { + flex-direction: column; + align-items: flex-start; + } + + .formula-row .chip { + max-width: 100%; + text-align: left; + } +} + +@media (max-width: 760px) { + .app-shell { + width: calc(100% - 1rem); + margin-top: 0.7rem; + } + + .brand { + align-items: flex-start; + } + + .brand-logo { + width: 48px; + height: 48px; + } + + .stats-grid { + grid-template-columns: 1fr; + } + + .subscore-grid { + grid-template-columns: 1fr; + } + + .premium-score-grid { + grid-template-columns: 1fr; + } + + .score-ring { + width: 108px; + height: 108px; + } + + .score-ring::before { + inset: 10px; + } + + .score-value { + font-size: 1.35rem; + } + + .chart-grid { + grid-template-columns: 1fr; + } +} diff --git a/sw.js b/sw.js new file mode 100644 index 0000000000..4e429d7b8e --- /dev/null +++ b/sw.js @@ -0,0 +1,77 @@ +const CACHE_NAME = "devdetective-v5"; + +const STATIC_ASSETS = [ + "./", + "./index.html", + "./style.css", + "./src/main.js", + "./src/config/constants.js", + "./src/ui/elements.js", + "./src/ui/render.js", + "./src/ui/charts.js", + "./src/report/markdown.js", + "./src/utils/core.js", + "./manifest.json", + "./Images/logo.png", + "./Images/favicon-32x32.png", + "./Images/favicon-16x16.png", + "./Images/apple-touch-icon.png", + "./Images/android-chrome-192x192.png", + "./Images/android-chrome-512x512.png" +]; + +self.addEventListener("install", (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => cache.addAll(STATIC_ASSETS)) + ); + self.skipWaiting(); +}); + +self.addEventListener("activate", (event) => { + event.waitUntil( + caches.keys().then((keys) => + Promise.all( + keys + .filter((key) => key !== CACHE_NAME) + .map((key) => caches.delete(key)) + ) + ) + ); + self.clients.claim(); +}); + +self.addEventListener("fetch", (event) => { + const request = event.request; + + if (request.method !== "GET") { + return; + } + + const url = new URL(request.url); + + if (url.pathname.startsWith("/api/") || url.origin === "https://api.github.com") { + event.respondWith(fetch(request)); + return; + } + + event.respondWith( + caches.match(request).then((cached) => { + if (cached) { + return cached; + } + + return fetch(request).then((response) => { + const isStatic = + url.origin === self.location.origin && + ["document", "script", "style", "image", "font"].includes(request.destination); + + if (isStatic && response && response.status === 200) { + const responseClone = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(request, responseClone)); + } + + return response; + }); + }) + ); +}); diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000000..61cf13c21a --- /dev/null +++ b/vercel.json @@ -0,0 +1,71 @@ +{ + "functions": { + "api/analyze.js": { + "maxDuration": 15 + } + }, + "headers": [ + { + "source": "/Images/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + } + ] + }, + { + "source": "/style.css", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=3600" + } + ] + }, + { + "source": "/src/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=3600" + } + ] + }, + { + "source": "/manifest.json", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=86400" + } + ] + }, + { + "source": "/sw.js", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=0, must-revalidate" + } + ] + }, + { + "source": "/(.*)", + "headers": [ + { + "key": "X-Frame-Options", + "value": "DENY" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "Referrer-Policy", + "value": "strict-origin-when-cross-origin" + } + ] + } + ] +} diff --git a/vite.config.js b/vite.config.js deleted file mode 100644 index 248c2f847e..0000000000 --- a/vite.config.js +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], - test: { - globals: true, - environment: 'jsdom', - }, -})