diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..636f5c34649909eefe8422eaa0d49d7d9d0a303d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.png filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.ico filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/sync_to_hf.yml b/.github/workflows/sync_to_hf.yml new file mode 100644 index 0000000000000000000000000000000000000000..769e38e2300520bff9e81c1ecc2a68d7026cc38c --- /dev/null +++ b/.github/workflows/sync_to_hf.yml @@ -0,0 +1,33 @@ +name: Sync to Hugging Face +on: + push: + branches: [master] + +jobs: + sync-to-hub: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Push to hub + env: + HF_TOKEN: ${{ secrets.HF_TOKEN }} + run: | + # 1. Turn on Large File Storage (LFS) + git lfs install + + # 2. Tell Hugging Face to properly handle images + echo "*.png filter=lfs diff=lfs merge=lfs -text" >> .gitattributes + echo "*.jpg filter=lfs diff=lfs merge=lfs -text" >> .gitattributes + echo "*.ico filter=lfs diff=lfs merge=lfs -text" >> .gitattributes + + # 3. Wipe the hidden git history in the runner to clear past image errors + rm -rf .git + git config --global user.email "action@github.com" + git config --global user.name "GitHub Action" + + # 4. Create a fresh, clean package and force push it + git init + git checkout -b main + git add . + git commit -m "Automated sync to Hugging Face" + git push --force https://anky2002:$HF_TOKEN@huggingface.co/spaces/anky2002/open-prompt main \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..44669f9b97053ba15544e2f273ab1f6404d7dc91 --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +/src/generated/prisma +# openprompt extension build output +/openprompt-extension/dist +/openprompt-extension/build +/openprompt-extension/node_modules +goal.md +features.md diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000000000000000000000000000000000..209e3ef4b6247ce746048d5711befda46206d235 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000000000000000000000000000000000000..5dbd853e1c28b999e92e0d3673f88b636a3d7034 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,414 @@ +# ๐Ÿš€ OpenPrompt - Quick Deployment Guide + +**From Zero to Live in 10 Minutes** + +--- + +## Prerequisites + +- โœ… Node.js 18+ installed +- โœ… Git installed +- โœ… Vercel account (free) +- โœ… OpenAI API key + +--- + +## Step 1: Environment Variables (2 minutes) + +Create `.env.local` file in the root directory: + +```env +# Database (already configured) +DATABASE_URL="your-neon-postgres-url" + +# Authentication (Stack Auth - already configured) +NEXT_PUBLIC_STACK_PROJECT_ID="your-stack-project-id" +NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY="your-stack-key" +STACK_SECRET_SERVER_KEY="your-stack-secret" + +# AI Models (REQUIRED for tools to work) +OPENAI_API_KEY="sk-proj-..." + +# Optional but recommended +ANTHROPIC_API_KEY="sk-ant-..." +GOOGLE_AI_API_KEY="..." + +# Redis Cache (Optional - improves performance) +UPSTASH_REDIS_REST_URL="https://..." +UPSTASH_REDIS_REST_TOKEN="..." + +# Bot Protection (Optional) +NEXT_PUBLIC_TURNSTILE_SITE_KEY="..." +TURNSTILE_SECRET_KEY="..." +``` + +### Get API Keys: + +**OpenAI (Required):** +1. Go to https://platform.openai.com/api-keys +2. Create new secret key +3. Copy to `OPENAI_API_KEY` + +**Upstash Redis (Recommended):** +1. Go to https://upstash.com +2. Create new database +3. Copy REST URL and Token + +--- + +## Step 2: Install & Build (3 minutes) + +```bash +# Install dependencies +npm install + +# Generate Prisma client +npx prisma generate + +# Push database schema +npx prisma db push + +# Optional: Seed with sample data +npx prisma db seed + +# Build for production +npm run build + +# Test locally +npm start +``` + +Visit http://localhost:3000 to verify everything works. + +--- + +## Step 3: Deploy to Vercel (5 minutes) + +### Option A: Vercel CLI (Fastest) + +```bash +# Install Vercel CLI +npm i -g vercel + +# Login +vercel login + +# Deploy +vercel --prod +``` + +### Option B: Vercel Dashboard + +1. Go to https://vercel.com/new +2. Import your Git repository +3. Add environment variables in dashboard +4. Click "Deploy" + +**Environment Variables to Add in Vercel:** +- `DATABASE_URL` +- `NEXT_PUBLIC_STACK_PROJECT_ID` +- `NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY` +- `STACK_SECRET_SERVER_KEY` +- `OPENAI_API_KEY` +- `UPSTASH_REDIS_REST_URL` (if using) +- `UPSTASH_REDIS_REST_TOKEN` (if using) + +--- + +## Step 4: Post-Deployment Checks (2 minutes) + +Visit your live site and verify: + +**Basic Functionality:** +- [ ] Homepage loads +- [ ] Can browse `/explore` +- [ ] Can view `/tools` +- [ ] Can sign in/sign up +- [ ] Dark mode toggle works + +**Critical Features:** +- [ ] Can run a prompt at `/p/[slug]` +- [ ] AI response streams correctly +- [ ] Can execute a tool at `/tools/[slug]` +- [ ] Star/unstar works +- [ ] Search works + +**Performance:** +- [ ] Page load < 3 seconds +- [ ] No console errors +- [ ] Images load properly +- [ ] Mobile responsive + +--- + +## Step 5: Domain Setup (Optional) + +**Add Custom Domain in Vercel:** + +1. Go to your project settings +2. Click "Domains" +3. Add your domain (e.g., https://open-prompt.netlify.app) +4. Update DNS records as instructed +5. Wait for SSL certificate (automatic) + +--- + +## Troubleshooting + +### Build Errors + +**Error:** "Module not found" +```bash +# Clear cache and reinstall +rm -rf node_modules .next +npm install +npm run build +``` + +**Error:** "Prisma Client not generated" +```bash +npx prisma generate +npm run build +``` + +### Runtime Errors + +**Error:** "OpenAI API key not found" +- Check `OPENAI_API_KEY` is set in Vercel environment variables +- Redeploy after adding env vars + +**Error:** "Database connection failed" +- Verify `DATABASE_URL` is correct +- Check if Neon database is active +- Ensure IP allowlist includes Vercel IPs + +**Error:** "Rate limit exceeded" +- Redis not configured (optional but recommended) +- Add Upstash Redis credentials +- Or increase rate limits in `lib/rate-limit.ts` + +### Performance Issues + +**Slow page loads:** +- Enable Redis caching +- Optimize images (use Next.js Image component) +- Check database query performance + +**AI tools timeout:** +- Increase timeout in tool execution API +- Use streaming for long responses +- Consider using GPT-4o-mini for faster responses + +--- + +## Monitoring & Analytics + +### Add Vercel Analytics (Free) + +1. Go to Vercel project settings +2. Enable "Analytics" tab +3. Automatically tracks: + - Page views + - Performance metrics + - User engagement + +### Add Vercel Speed Insights + +```bash +npm install @vercel/speed-insights +``` + +In `app/layout.tsx`: +```typescript +import { SpeedInsights } from '@vercel/speed-insights/next' + +export default function RootLayout({ children }) { + return ( + + + {children} + + + + ) +} +``` + +### Optional: Add PostHog (Product Analytics) + +1. Sign up at https://posthog.com +2. Add tracking code to layout +3. Track: + - Tool usage + - Prompt runs + - User journeys + - Conversions + +--- + +## Scaling Considerations + +### When to Upgrade + +**Database:** +- Free tier: ~10GB storage, 1GB bandwidth +- Upgrade when: >5,000 users or >100,000 prompts + +**Redis:** +- Free tier: 10,000 commands/day +- Upgrade when: >1,000 daily active users + +**AI APIs:** +- Monitor usage in OpenAI dashboard +- Set usage limits to prevent surprise bills +- Consider caching common responses + +### Cost Estimates + +**MVP (0-1,000 users):** +- Vercel: Free +- Neon DB: Free +- Redis: Free +- OpenAI: ~$50-100/month +- **Total: ~$50-100/month** + +**Growth (1,000-10,000 users):** +- Vercel: $20/month +- Neon DB: $19/month +- Redis: $10/month +- OpenAI: ~$300-500/month +- **Total: ~$350-550/month** + +**Scale (10,000+ users):** +- Vercel: $20-50/month +- Neon DB: $50+/month +- Redis: $50+/month +- OpenAI: ~$1,000+/month +- **Total: ~$1,120+/month** + +--- + +## Production Checklist + +### Security +- [ ] Environment variables secured +- [ ] API keys rotated regularly +- [ ] Rate limiting enabled +- [ ] CORS configured +- [ ] Input validation on all forms +- [ ] XSS protection enabled + +### Performance +- [ ] Redis caching enabled +- [ ] Images optimized +- [ ] Code split by route +- [ ] Lazy loading implemented +- [ ] CDN configured (automatic with Vercel) + +### Monitoring +- [ ] Error tracking (Sentry recommended) +- [ ] Analytics enabled +- [ ] Uptime monitoring +- [ ] Database backups configured +- [ ] Logs accessible + +### SEO +- [ ] Meta tags complete +- [ ] Sitemap generated +- [ ] robots.txt configured +- [ ] Open Graph images +- [ ] Schema markup added + +### Legal +- [ ] Privacy policy published +- [ ] Terms of service published +- [ ] Cookie consent (if EU users) +- [ ] GDPR compliance (if EU users) +- [ ] CCPA compliance (if CA users) + +--- + +## Launch Day Actions + +**Hour 1: Deploy** +- [ ] Final build successful +- [ ] All environment variables set +- [ ] Domain connected +- [ ] SSL active + +**Hour 2: Verify** +- [ ] Test all critical paths +- [ ] Check mobile experience +- [ ] Verify AI tools work +- [ ] Test authentication flow + +**Hour 3: Announce** +- [ ] Post on social media +- [ ] Email early users +- [ ] Submit to Product Hunt +- [ ] Share in communities + +--- + +## Support Resources + +**Documentation:** +- Next.js: https://nextjs.org/docs +- Prisma: https://www.prisma.io/docs +- Vercel: https://vercel.com/docs +- Stack Auth: https://docs.stack-auth.com + +**Community:** +- Discord servers for each stack +- GitHub discussions +- Stack Overflow + +**Paid Support:** +- Vercel Enterprise support +- Database managed services +- Development agencies + +--- + +## Quick Commands Reference + +```bash +# Development +npm run dev # Start dev server +npm run build # Build for production +npm start # Run production build +npm run lint # Run ESLint + +# Database +npx prisma studio # Open database GUI +npx prisma db push # Push schema to database +npx prisma db seed # Seed database +npx prisma generate # Generate Prisma client +npx prisma migrate dev # Create migration + +# Deployment +vercel # Deploy to preview +vercel --prod # Deploy to production +vercel env pull # Pull env variables locally +vercel logs # View deployment logs +``` + +--- + +## Success! ๐ŸŽ‰ + +Your OpenPrompt platform is now LIVE and ready to: +- Serve users +- Generate revenue +- Scale infinitely +- Change the world + +**Next:** Monitor usage, gather feedback, iterate! + +--- + +**Need Help?** Check the documentation or open an issue on GitHub. + +**Ready to Scale?** Consider the growth roadmap in `final_summary.md`. + +**Want More Features?** See `implementation_plan.md` for adding more tools. diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5fa205665f9a20dd003f5734de991a380ca36cc7 --- /dev/null +++ b/README.md @@ -0,0 +1,414 @@ +# ๐Ÿš€ OpenPrompt - AI Prompts Marketplace + Tools Suite + +> **Production-ready platform combining a prompts marketplace with 177+ AI-powered tools, browser extension, and multi-model support** + +[![Next.js](https://img.shields.io/badge/Next.js-16.0.8-black)](https://nextjs.org/) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.8-blue)](https://www.typescriptlang.org/) +[![Prisma](https://img.shields.io/badge/Prisma-7.1-2D3748)](https://www.prisma.io/) +[![React](https://img.shields.io/badge/React-19.2-61DAFB)](https://react.dev/) + +**Live Demo:** [https://open-prompt.netlify.app](https://open-prompt.netlify.app) + +--- + +## ๐Ÿ“– Table of Contents + +- [Features](#-features) +- [Tech Stack](#-tech-stack) +- [Getting Started](#-getting-started) +- [Project Structure](#-project-structure) +- [Browser Extension](#-browser-extension) +- [Available Tools](#-available-tools) +- [Deployment](#-deployment) +- [Documentation](#-documentation) +- [Support](#-support) + +--- + +## โœจ Features + +### Prompts Marketplace + +- ๐Ÿ” **Advanced Search** - Full-text search with real-time filtering +- ๐Ÿ“Š **Trending Algorithm** - Hot score calculation for viral prompts +- ๐Ÿท๏ธ **7 Categories** - Content, Development, Marketing, Business, Education, Creative, Research +- โญ **User Engagement** - Star, share, remix, and collect prompts +- ๐Ÿ‘ฅ **Creator Economy** - Profile pages, rankings (Bronze/Silver/Gold/Verified), stats +- ๐ŸŽจ **10 Frameworks** - RACE, CARE, APE, CREATE, RISEN, RTF, TAG, BAB, STAR, PREP +- ๐Ÿ… **Quality Badges** - Auto-calculated (Hot, Viral, Featured, Top Rated, etc.) +- ๐Ÿ“ฆ **Collections** - Organize and share prompt collections +- ๐Ÿ”— **Embeds** - Share prompts with 3 theme options +- ๐Ÿ’ฌ **Comments** - Threaded discussions with likes and replies +- ๐ŸŒ“ **Dark Mode** - Beautiful light and dark themes + +### AI Tools Suite (177 Tools Across 15 Categories) + +- ๐ŸŽฏ **Prompting** (9) - Optimizer, Checker, Chain-of-Thought, Few-Shot, Meta-Prompt, etc. +- ๐Ÿ“ข **Marketing** (14) - Strategy, Sales Copy, Hooks, Ads, Campaigns +- ๐Ÿข **Branding** (11) - Business Names, Slogans, USP, Brand Voice +- โœ๏ธ **Copywriting** (12) - Titles, Headlines, Meta, Landing Pages +- ๐Ÿ’ผ **Business** (15) - Plans, Mission, SWOT, Pitches, Financial Models +- ๐Ÿ“ง **Email** (10) - Subject Lines, Cold Email, Sequences, Templates +- ๐Ÿ“ฆ **Product** (12) - Descriptions, PRDs, User Stories, Roadmaps +- ๐Ÿ’ผ **HR** (11) - Job Descriptions, Interviews, Reviews, Onboarding +- โญ **Personal Brand** (8) - LinkedIn, Twitter, Instagram, Bio +- ๐Ÿ“‹ **Operations** (9) - SOPs, KPIs, Process Improvement +- ๐Ÿ“ฑ **Social Media** (12) - Posts, Captions, Hashtags, Calendars +- ๐ŸŽ“ **Education** (10) - Lesson Plans, Quizzes, Curriculum +- ๐Ÿ’ป **Development** (15) - Code Review, Documentation, APIs +- ๐ŸŽจ **Creative** (14) - Stories, Scripts, Poetry, Art Prompts +- ๐Ÿ”ฌ **Research** (15) - Analysis, Summaries, Literature Review + +### Image Prompts Gallery +- ๐ŸŽจ **Midjourney** - v6.1, v6, v5.2, niji 6 +- ๐Ÿ–ผ๏ธ **DALL-E** - DALL-E 3, DALL-E 2 +- ๐ŸŽฏ **Stable Diffusion** - SDXL, SD 3.5, SD 1.5 +- โšก **FLUX** - FLUX.1-dev, schnell, pro +- ๐Ÿฆ **Leonardo AI** - Phoenix, Kino XL, Vision XL +- ๐Ÿ”ฅ **Adobe Firefly** - Firefly 3, Firefly 2 + +### AI Characters +- ๐Ÿค– **Experts** - Coding, Writing, Business mentors +- ๐ŸŽญ **Roleplay** - Storytelling, Adventure companions +- ๐ŸŽ“ **Education** - Tutors, Study buddies +- ๐Ÿ’ผ **Productivity** - Task assistants, Planners +- ๐ŸŽจ **Creative** - Art directors, Music composers + +### Thunderdome โš”๏ธ +- **Model vs Model** - Compare AI responses head-to-head +- **Community Voting** - Real-time leaderboard +- **20+ Models** - GPT-4o, Claude 3.5, Gemini 2.5, Ollama models + +### Workflow Chains ๐Ÿ”— +- **Multi-step Prompts** - Chain prompts together +- **Variable Passing** - Output โ†’ Input automation +- **Templates** - Pre-built workflow patterns + +### Infrastructure + +- โšก **Multi-Model AI** - OpenAI, Anthropic, Google AI, Ollama (20+ local models) +- ๐Ÿ”„ **Response Caching** - Redis with 7-day TTL +- ๐Ÿ›ก๏ธ **Rate Limiting** - 10/hr guests, 50/hr users +- ๐Ÿค– **Bot Protection** - Cloudflare Turnstile +- ๐Ÿ“Š **Analytics** - Usage tracking, engagement metrics +- ๐Ÿ” **Authentication** - Stack Auth integration +- ๐Ÿ“ฑ **Mobile Responsive** - Works on all devices +- ๐Ÿงฉ **Browser Extension** - Open prompts in any AI chat + +--- + +## ๐Ÿ› ๏ธ Tech Stack + +**Frontend:** +- [Next.js 16.0.8](https://nextjs.org/) - React framework with Turbopack +- [React 19.2.1](https://react.dev/) - UI library +- [TypeScript 5.8](https://www.typescriptlang.org/) - Type safety +- [Tailwind CSS 4.x](https://tailwindcss.com/) - Styling +- [Shadcn/ui](https://ui.shadcn.com/) - UI components +- [Framer Motion](https://www.framer.com/motion/) - Animations + +**Backend:** +- [Next.js API Routes](https://nextjs.org/docs/api-routes/introduction) - Serverless functions +- [Prisma 7.1](https://www.prisma.io/) - Database ORM +- [PostgreSQL](https://www.postgresql.org/) - Database (via Neon) +- [Redis](https://redis.io/) - Caching (via Upstash) + +**AI & Services:** +- [OpenAI API](https://platform.openai.com/) - GPT-4o, GPT-4o-mini +- [Anthropic API](https://www.anthropic.com/) - Claude 3.5 Sonnet, Claude 3 Haiku +- [Google AI](https://ai.google.dev/) - Gemini 2.5 Flash, Gemini 2.0 Flash +- [Ollama](https://ollama.ai/) - 20+ local models (Llama, Mistral, Phi, etc.) +- [Stack Auth](https://stack-auth.com/) - Authentication +- [Cloudflare Turnstile](https://www.cloudflare.com/products/turnstile/) - Bot protection + +**Deployment:** +- [Vercel](https://vercel.com/) - Hosting & deployments +- [GitHub](https://github.com/) - Version control + +--- + +## ๐Ÿš€ Getting Started + +### Prerequisites + +- Node.js 18+ +- npm or yarn +- PostgreSQL database (or Neon account) +- OpenAI API key + +### Installation + +1. **Clone the repository** + +```bash +git clone https://github.com/Anky9972/open-prompt.git +cd open-prompt +``` + +2. **Install dependencies** + +```bash +npm install +``` + +3. **Set up environment variables** + +Create `.env.local`: + +```env +# Database +DATABASE_URL="postgresql://..." + +# Authentication (Stack Auth) +NEXT_PUBLIC_STACK_PROJECT_ID="..." +NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY="..." +STACK_SECRET_SERVER_KEY="..." + +# AI Models (Required) +OPENAI_API_KEY="sk-..." + +# Optional +ANTHROPIC_API_KEY="sk-ant-..." +GOOGLE_AI_API_KEY="..." +UPSTASH_REDIS_REST_URL="..." +UPSTASH_REDIS_REST_TOKEN="..." +NEXT_PUBLIC_TURNSTILE_SITE_KEY="..." +TURNSTILE_SECRET_KEY="..." +``` + +4. **Set up database** + +```bash +npx prisma generate +npx prisma db push +npx prisma db seed # Optional: adds sample data +``` + +5. **Run development server** + +```bash +npm run dev +``` + +Visit [http://localhost:3000](http://localhost:3000) + +--- + +## ๐Ÿ“ Project Structure + +``` +openprompt/ +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ app/ # Next.js app directory +โ”‚ โ”‚ โ”œโ”€โ”€ api/ # API routes +โ”‚ โ”‚ โ”œโ”€โ”€ categories/ # Category pages +โ”‚ โ”‚ โ”œโ”€โ”€ category/ # Dynamic category +โ”‚ โ”‚ โ”œโ”€โ”€ collections/ # Collections +โ”‚ โ”‚ โ”œโ”€โ”€ create/ # Create prompt +โ”‚ โ”‚ โ”œโ”€โ”€ creators/ # Creators index +โ”‚ โ”‚ โ”œโ”€โ”€ creator/ # Creator profile +โ”‚ โ”‚ โ”œโ”€โ”€ embed/ # Embed pages +โ”‚ โ”‚ โ”œโ”€โ”€ explore/ # Explore page +โ”‚ โ”‚ โ”œโ”€โ”€ image-prompts/ # Image generation prompts +โ”‚ โ”‚ โ”œโ”€โ”€ characters/ # AI characters +โ”‚ โ”‚ โ”œโ”€โ”€ leaderboard/ # Creator rankings +โ”‚ โ”‚ โ”œโ”€โ”€ p/ # Prompt runner +โ”‚ โ”‚ โ”œโ”€โ”€ thunderdome/ # Model comparison +โ”‚ โ”‚ โ”œโ”€โ”€ workflows/ # Workflow chains +โ”‚ โ”‚ โ”œโ”€โ”€ tools/ # AI tools suite +โ”‚ โ”‚ โ”œโ”€โ”€ about/ # About page +โ”‚ โ”‚ โ”œโ”€โ”€ docs/ # Documentation +โ”‚ โ”‚ โ”œโ”€โ”€ guides/ # User guides +โ”‚ โ”‚ โ”œโ”€โ”€ blog/ # Blog +โ”‚ โ”‚ โ”œโ”€โ”€ layout.tsx # Root layout +โ”‚ โ”‚ โ””โ”€โ”€ page.tsx # Landing page +โ”‚ โ”œโ”€โ”€ components/ # React components +โ”‚ โ”‚ โ”œโ”€โ”€ auth/ # Auth components +โ”‚ โ”‚ โ”œโ”€โ”€ comments/ # Comments system +โ”‚ โ”‚ โ”œโ”€โ”€ create/ # Creation components +โ”‚ โ”‚ โ”œโ”€โ”€ engagement/ # Engagement metrics +โ”‚ โ”‚ โ”œโ”€โ”€ explore/ # Discovery components +โ”‚ โ”‚ โ”œโ”€โ”€ layout/ # Layout (header, footer) +โ”‚ โ”‚ โ”œโ”€โ”€ prompt-runner/ # Prompt execution +โ”‚ โ”‚ โ”œโ”€โ”€ prompts/ # Prompt components +โ”‚ โ”‚ โ”œโ”€โ”€ thunderdome/ # Model comparison UI +โ”‚ โ”‚ โ”œโ”€โ”€ tools/ # Tool components +โ”‚ โ”‚ โ”œโ”€โ”€ workflow/ # Workflow builder +โ”‚ โ”‚ โ””โ”€โ”€ ui/ # Shadcn UI components +โ”‚ โ”œโ”€โ”€ lib/ # Utilities +โ”‚ โ”‚ โ”œโ”€โ”€ prisma.ts # Prisma client +โ”‚ โ”‚ โ”œโ”€โ”€ tools.ts # 177 tool definitions +โ”‚ โ”‚ โ”œโ”€โ”€ frameworks.ts # Prompt frameworks +โ”‚ โ”‚ โ””โ”€โ”€ utils.ts # Helper functions +โ”‚ โ””โ”€โ”€ types/ # TypeScript types +โ”œโ”€โ”€ prisma/ +โ”‚ โ”œโ”€โ”€ schema.prisma # Database schema +โ”‚ โ””โ”€โ”€ seed.ts # Seed data +โ”œโ”€โ”€ openprompt-extension/ # Browser extension +โ”‚ โ”œโ”€โ”€ src/ # Extension source +โ”‚ โ”œโ”€โ”€ dist/ # Built extension +โ”‚ โ””โ”€โ”€ README.md # Extension docs +โ”œโ”€โ”€ public/ # Static assets +โ”œโ”€โ”€ DEPLOYMENT.md # Deployment guide +โ”œโ”€โ”€ FEATURE-GAP-ANALYSIS.md # Feature roadmap +โ””โ”€โ”€ README.md # This file +``` + +--- + +## ๐Ÿงฉ Browser Extension + +Open prompts directly in ChatGPT, Claude, Gemini, and other AI interfaces with one click! + +### Supported Platforms +- โœ… ChatGPT (chatgpt.com) +- โœ… Claude (claude.ai) +- โœ… Gemini (gemini.google.com) +- โœ… Perplexity (perplexity.ai) +- โœ… Mistral (chat.mistral.ai) +- โœ… Microsoft Copilot (copilot.microsoft.com) + +### Installation + +```bash +cd openprompt-extension +npm install +npm run build +``` + +Then load the `dist` folder as an unpacked extension in Chrome. + +See [openprompt-extension/README.md](openprompt-extension/README.md) for detailed instructions. + +--- + +## ๐Ÿ”ง Available Tools + +### 177 Tools Across 15 Categories + +| Category | Count | Examples | +|----------|-------|----------| +| **Prompting** | 9 | Optimizer, Chain-of-Thought, Meta-Prompt | +| **Marketing** | 14 | Strategy, Ads, Campaigns, Funnels | +| **Branding** | 11 | Names, Slogans, Voice, Guidelines | +| **Copywriting** | 12 | Headlines, Landing Pages, CTAs | +| **Business** | 15 | Plans, SWOT, Pitches, Financials | +| **Email** | 10 | Sequences, Templates, Subject Lines | +| **Product** | 12 | PRDs, Roadmaps, User Stories | +| **HR** | 11 | Job Posts, Interviews, Onboarding | +| **Personal Brand** | 8 | LinkedIn, Twitter, Bio Generators | +| **Operations** | 9 | SOPs, KPIs, Process Improvement | +| **Social Media** | 12 | Posts, Reels, Calendars, Hashtags | +| **Education** | 10 | Lesson Plans, Quizzes, Curriculum | +| **Development** | 15 | Code Review, Docs, API Design | +| **Creative** | 14 | Stories, Scripts, Poetry, Art | +| **Research** | 15 | Analysis, Summaries, Literature | + +See [src/lib/tools.ts](src/lib/tools.ts) for complete definitions. + +--- + +## ๐ŸŒ Deployment + +### Deploy to Vercel (Recommended) + +1. **Push to GitHub** + +```bash +git add . +git commit -m "Initial commit" +git push origin main +``` + +2. **Import to Vercel** + +- Go to [vercel.com/new](https://vercel.com/new) +- Import your repository +- Add environment variables +- Deploy! + +3. **Set up domain** (optional) + +- Add custom domain in Vercel dashboard +- Configure DNS settings +- SSL automatically provisioned + +For detailed instructions, see [DEPLOYMENT.md](DEPLOYMENT.md) + +--- + +## ๐Ÿ“š Documentation + +- **[DEPLOYMENT.md](DEPLOYMENT.md)** - Complete deployment guide +- **[FEATURE-GAP-ANALYSIS.md](FEATURE-GAP-ANALYSIS.md)** - Competitor analysis & roadmap +- **[openprompt-extension/README.md](openprompt-extension/README.md)** - Browser extension docs + +--- + +## ๐ŸŽฏ Roadmap + +### โœ… Current: v1.0 (Complete) +- โœ… Full prompts marketplace with 7 categories +- โœ… 177 AI tools across 15 categories +- โœ… Multi-model support (OpenAI, Anthropic, Google, Ollama) +- โœ… Thunderdome model comparison +- โœ… Workflow chains +- โœ… Image prompts gallery +- โœ… AI characters +- โœ… Comments & engagement +- โœ… Creator leaderboard +- โœ… Browser extension + +### ๐Ÿšง Next: v1.5 +- [ ] Prompt marketplace (buy/sell) +- [ ] Team workspaces +- [ ] API access +- [ ] Custom fine-tuning + +### ๐Ÿ”ฎ Future: v2.0 +- [ ] Mobile app +- [ ] Enterprise features +- [ ] White-label option +- [ ] Plugin ecosystem + +--- + +## ๐Ÿ’ฐ Monetization + +### Free Tier +- All basic features +- 20 tool executions/day +- Community prompts + +### Pro ($9/month) +- Unlimited tool executions +- Access to PRO tools +- Execution history +- Priority support + +### Enterprise (Custom) +- API access +- Custom tools +- White-label +- SLA guarantee + +--- + +## ๐Ÿ“ž Support + +- **Issues:** [GitHub Issues](https://github.com/Anky9972/open-prompt/issues) +- **Discussions:** [GitHub Discussions](https://github.com/Anky9972/open-prompt/discussions) +- **Email:** ankygaur9972@gmail.com +- **Twitter:** [@anky_vivek](https://x.com/anky_vivek) + +--- + +## ๐ŸŒŸ Star History + +If you find this project useful, please consider giving it a star โญ + +--- + +**Built with โค๏ธ by [Anky9972](https://github.com/Anky9972)** + +[Website](https://open-prompt.netlify.app) ยท [Twitter](https://x.com/anky_vivek) ยท [GitHub](https://github.com/Anky9972/open-prompt) diff --git a/components.json b/components.json new file mode 100644 index 0000000000000000000000000000000000000000..edcaef267e34d591c9ae0f0b4cd14a146e6c012f --- /dev/null +++ b/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000000000000000000000000000000000..05e726d1b4201bc8c7716d2b058279676582e8c0 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..663ffe45dd7fdd22d3c1ba9d76aca05ee4f759a9 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,95 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + // Image optimization โ€“ whitelist only known-safe domains (no wildcard **) + images: { + remotePatterns: [ + // GitHub avatars (OAuth) + { protocol: "https", hostname: "avatars.githubusercontent.com" }, + // Google avatars (OAuth) + { protocol: "https", hostname: "lh3.googleusercontent.com" }, + { protocol: "https", hostname: "lh4.googleusercontent.com" }, + { protocol: "https", hostname: "lh5.googleusercontent.com" }, + // Stack Auth CDN + { protocol: "https", hostname: "*.stackauth.com" }, + // Prompt preview / gallery images (Cloudflare R2 / storage) + { protocol: "https", hostname: "imagedelivery.net" }, + { protocol: "https", hostname: "images.unsplash.com" }, + // AI image CDNs + { protocol: "https", hostname: "oaidalleapiprodscus.blob.core.windows.net" }, + { protocol: "https", hostname: "cdn.midjourney.com" }, + { protocol: "https", hostname: "image.civitai.com" }, + ], + formats: ["image/avif", "image/webp"], + }, + + // Security headers + async headers() { + return [ + { + source: "/(.*)", + headers: [ + // โœ… SAMEORIGIN (not DENY) so /embed/ iframes work + { key: "X-Frame-Options", value: "SAMEORIGIN" }, + { key: "X-Content-Type-Options", value: "nosniff" }, + { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, + { key: "X-DNS-Prefetch-Control", value: "on" }, + { key: "X-Permitted-Cross-Domain-Policies", value: "none" }, + { key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains; preload" }, + { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" }, + { + key: "Content-Security-Policy", + value: [ + "default-src 'self'", + // Scripts: Next.js needs unsafe-inline for inline event handlers; Turnstile needs its domain + "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://challenges.cloudflare.com https://www.googletagmanager.com", + // Styles: Google Fonts + Tailwind inline + "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com", + // Fonts: Google Fonts CDN + "font-src 'self' https://fonts.gstatic.com", + // Images: broad HTTPS allowed (user avatar, AI-generated images) + "img-src 'self' data: blob: https:", + // Frames: Cloudflare Turnstile widget + same-origin embeds + "frame-src 'self' https://challenges.cloudflare.com", + // Connect: AI APIs + Cloudflare + analytics + "connect-src 'self' https://api.openai.com https://api.anthropic.com https://generativelanguage.googleapis.com https://challenges.cloudflare.com wss: ws:", + // Media / workers (Next.js internals) + "media-src 'self' blob:", + "worker-src 'self' blob:", + ].join("; "), + }, + ], + }, + { + // Cache logos & brand assets for 1 year + source: "/logos/(.*)", + headers: [ + { key: "Cache-Control", value: "public, max-age=31536000, immutable" }, + ], + }, + { + // Cache other static public assets for 1 day + source: "/(.*\\.(?:svg|png|jpg|jpeg|gif|ico|woff2|woff|ttf))", + headers: [ + { key: "Cache-Control", value: "public, max-age=86400, stale-while-revalidate=3600" }, + ], + }, + ]; + }, + + // Performance optimizations โ€“ tree-shake large packages + experimental: { + optimizePackageImports: [ + "lucide-react", + "react-icons", + "framer-motion", + "recharts", + "@radix-ui/react-dropdown-menu", + "@radix-ui/react-select", + "@radix-ui/react-tabs", + "@radix-ui/react-tooltip", + ], + }, +}; + +export default nextConfig; diff --git a/openprompt-extension/README.md b/openprompt-extension/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3f451716340d294ca9fee9ef259d82c7d5ebdf75 --- /dev/null +++ b/openprompt-extension/README.md @@ -0,0 +1,137 @@ +# OpenPrompt Browser Extension + +A browser extension that allows you to open prompts directly in ChatGPT, Claude, Gemini, Perplexity, Mistral, and Microsoft Copilot with one click. + +## Features + +- ๐Ÿš€ **One-Click Injection** - Send prompts directly to your favorite AI chat interface +- ๐Ÿค– **Multiple Platforms** - Supports ChatGPT, Claude, Gemini, Perplexity, Mistral, Copilot +- ๐Ÿ“ **Recent History** - Access your recently used prompts +- โšก **Default Platform** - Set your preferred AI platform for quick access +- ๐Ÿ”’ **Privacy First** - All data stays in your browser + +## Supported Platforms + +| Platform | URL | Status | +|----------|-----|--------| +| ChatGPT | chatgpt.com | โœ… Supported | +| Claude | claude.ai | โœ… Supported | +| Gemini | gemini.google.com | โœ… Supported | +| Perplexity | perplexity.ai | โœ… Supported | +| Mistral | chat.mistral.ai | โœ… Supported | +| Copilot | copilot.microsoft.com | โœ… Supported | + +## Installation + +### Development Build + +1. Install dependencies: + ```bash + cd openprompt-extension + npm install + ``` + +2. Build the extension: + ```bash + npm run build + ``` + +3. Load in Chrome: + - Open `chrome://extensions/` + - Enable "Developer mode" + - Click "Load unpacked" + - Select the `dist` folder + +### Development Mode + +For live reloading during development: + +```bash +npm run dev +``` + +This will watch for changes and rebuild automatically. + +## Project Structure + +``` +openprompt-extension/ +โ”œโ”€โ”€ public/ +โ”‚ โ”œโ”€โ”€ manifest.json # Chrome extension manifest +โ”‚ โ””โ”€โ”€ icons/ # Extension icons +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ popup/ # Extension popup UI (React) +โ”‚ โ”‚ โ”œโ”€โ”€ App.tsx +โ”‚ โ”‚ โ”œโ”€โ”€ main.tsx +โ”‚ โ”‚ โ””โ”€โ”€ index.css +โ”‚ โ”œโ”€โ”€ background/ # Service worker +โ”‚ โ”‚ โ””โ”€โ”€ index.ts +โ”‚ โ””โ”€โ”€ content-scripts/ # Platform-specific injection scripts +โ”‚ โ”œโ”€โ”€ chatgpt.ts +โ”‚ โ”œโ”€โ”€ claude.ts +โ”‚ โ”œโ”€โ”€ gemini.ts +โ”‚ โ”œโ”€โ”€ perplexity.ts +โ”‚ โ”œโ”€โ”€ mistral.ts +โ”‚ โ”œโ”€โ”€ copilot.ts +โ”‚ โ”œโ”€โ”€ openprompt-site.ts +โ”‚ โ””โ”€โ”€ utils.ts +โ”œโ”€โ”€ popup.html +โ”œโ”€โ”€ package.json +โ”œโ”€โ”€ vite.config.ts +โ”œโ”€โ”€ tailwind.config.js +โ””โ”€โ”€ tsconfig.json +``` + +## How It Works + +1. **From OpenPrompt Website:** + - Click "Open In..." on any prompt + - Select your preferred AI platform + - The prompt is automatically filled in the chat input + +2. **From Extension Popup:** + - Click the extension icon + - View pending prompts + - Choose where to open them + - Access recent prompt history + +## API Communication + +The extension communicates with the OpenPrompt website via: +- `window.postMessage` for content script communication +- `chrome.runtime.sendMessage` for external messaging +- Chrome storage API for state persistence + +## Building for Production + +```bash +npm run build +``` + +The built extension will be in the `dist` folder, ready for Chrome Web Store submission. + +## Publishing + +1. Create a developer account on Chrome Web Store +2. Package the `dist` folder as a ZIP +3. Upload to Chrome Web Store Developer Dashboard +4. Submit for review + +## Icons + +For production, you'll need to convert the SVG icon to PNG at these sizes: +- icon16.png (16x16) +- icon48.png (48x48) +- icon128.png (128x128) + +Use a tool like [CloudConvert](https://cloudconvert.com/svg-to-png) or run: +```bash +# With ImageMagick +convert -background none -resize 16x16 public/icons/icon.svg public/icons/icon16.png +convert -background none -resize 48x48 public/icons/icon.svg public/icons/icon48.png +convert -background none -resize 128x128 public/icons/icon.svg public/icons/icon128.png +``` + +## License + +MIT - Part of the OpenPrompt project diff --git a/openprompt-extension/package-lock.json b/openprompt-extension/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..16b00017bc478f4b323889f80872860df8a8de77 --- /dev/null +++ b/openprompt-extension/package-lock.json @@ -0,0 +1,3342 @@ +{ + "name": "openprompt-extension", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openprompt-extension", + "version": "1.0.0", + "dependencies": { + "lucide-react": "^0.469.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/chrome": "^0.0.283", + "@types/react": "^18.3.17", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "sharp": "^0.34.5", + "tailwindcss": "^3.4.17", + "typescript": "^5.7.2", + "vite": "^6.0.5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@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==", + "dev": true, + "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/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/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, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", + "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", + "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", + "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", + "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", + "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", + "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", + "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", + "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", + "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", + "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", + "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", + "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", + "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", + "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", + "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", + "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", + "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", + "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", + "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", + "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", + "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", + "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chrome": { + "version": "0.0.283", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.283.tgz", + "integrity": "sha512-bPnu1JqeQxMceRP0oxFYrauoe0BlWxxQxhYL58gWLg5Ywsd3i3Dd6By9OW7BdkNQMokodWzBLR5FHDIeQZvJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "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, + "license": "MIT" + }, + "node_modules/@types/filesystem": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", + "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", + "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", + "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.23", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", + "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001760", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001761", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz", + "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/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/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.469.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.469.0.tgz", + "integrity": "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", + "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.54.0", + "@rollup/rollup-android-arm64": "4.54.0", + "@rollup/rollup-darwin-arm64": "4.54.0", + "@rollup/rollup-darwin-x64": "4.54.0", + "@rollup/rollup-freebsd-arm64": "4.54.0", + "@rollup/rollup-freebsd-x64": "4.54.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", + "@rollup/rollup-linux-arm-musleabihf": "4.54.0", + "@rollup/rollup-linux-arm64-gnu": "4.54.0", + "@rollup/rollup-linux-arm64-musl": "4.54.0", + "@rollup/rollup-linux-loong64-gnu": "4.54.0", + "@rollup/rollup-linux-ppc64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-musl": "4.54.0", + "@rollup/rollup-linux-s390x-gnu": "4.54.0", + "@rollup/rollup-linux-x64-gnu": "4.54.0", + "@rollup/rollup-linux-x64-musl": "4.54.0", + "@rollup/rollup-openharmony-arm64": "4.54.0", + "@rollup/rollup-win32-arm64-msvc": "4.54.0", + "@rollup/rollup-win32-ia32-msvc": "4.54.0", + "@rollup/rollup-win32-x64-gnu": "4.54.0", + "@rollup/rollup-win32-x64-msvc": "4.54.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/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, + "license": "0BSD", + "optional": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/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, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/openprompt-extension/package.json b/openprompt-extension/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f11ef33f3c69b357159aef5aae3049eaca0d29c9 --- /dev/null +++ b/openprompt-extension/package.json @@ -0,0 +1,28 @@ +{ + "name": "openprompt-extension", + "version": "1.0.0", + "description": "Open prompts directly in ChatGPT, Claude, Gemini, and other AI chat interfaces", + "type": "module", + "scripts": { + "dev": "vite build --watch", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "lucide-react": "^0.469.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/chrome": "^0.0.283", + "@types/react": "^18.3.17", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "sharp": "^0.34.5", + "tailwindcss": "^3.4.17", + "typescript": "^5.7.2", + "vite": "^6.0.5" + } +} diff --git a/openprompt-extension/popup.html b/openprompt-extension/popup.html new file mode 100644 index 0000000000000000000000000000000000000000..8052cba9c7bfd26d78cd875c469a6418bcef9971 --- /dev/null +++ b/openprompt-extension/popup.html @@ -0,0 +1,12 @@ + + + + + + OpenPrompt + + +
+ + + diff --git a/openprompt-extension/postcss.config.js b/openprompt-extension/postcss.config.js new file mode 100644 index 0000000000000000000000000000000000000000..2e7af2b7f1a6f391da1631d93968a9d487ba977d --- /dev/null +++ b/openprompt-extension/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/openprompt-extension/public/icon.svg b/openprompt-extension/public/icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..991d8b67e1aeccc3c8ce1a0112cee73951287c63 --- /dev/null +++ b/openprompt-extension/public/icon.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/openprompt-extension/public/icons/icon128.png b/openprompt-extension/public/icons/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..b0f0f9af9132f9cdfec38530fef50d45f9516c25 --- /dev/null +++ b/openprompt-extension/public/icons/icon128.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35287b08bfd69409b3d6a53f3df5f7c9d8f9b54831cba0466c92fe52585e3046 +size 7709 diff --git a/openprompt-extension/public/icons/icon16.png b/openprompt-extension/public/icons/icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a8c61db73edaefc48d2132d4d131664d92ff5c --- /dev/null +++ b/openprompt-extension/public/icons/icon16.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:46be2ab7741008406fc7920ab6f98c8be47bbd0f0664abf3a06d75849f26ca60 +size 589 diff --git a/openprompt-extension/public/icons/icon48.png b/openprompt-extension/public/icons/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..9374e174941f09e7dea18cc88d5c7206af0d93ce --- /dev/null +++ b/openprompt-extension/public/icons/icon48.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55ee3d3b0d30f8790b1e39311a1b2b6362d8ec0e9f18337a01c77f3920e2521c +size 2332 diff --git a/openprompt-extension/public/icons/logo.svg b/openprompt-extension/public/icons/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..39f202a282a1a6c1c079715700e7b497f22853dc --- /dev/null +++ b/openprompt-extension/public/icons/logo.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openprompt-extension/public/manifest.json b/openprompt-extension/public/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..7ae008e7821d61b5c4b13f53f06a1f33fd3b1c69 --- /dev/null +++ b/openprompt-extension/public/manifest.json @@ -0,0 +1,150 @@ +{ + "manifest_version": 3, + "name": "OpenPrompt - Open in AI", + "version": "1.1.0", + "description": "Open prompts directly in ChatGPT, Claude, Gemini, Perplexity, and other AI chat interfaces with one click.", + "permissions": [ + "activeTab", + "storage", + "tabs", + "contextMenus", + "clipboardWrite", + "clipboardRead" + ], + "commands": { + "_execute_action": { + "suggested_key": { + "default": "Ctrl+Shift+O", + "mac": "Command+Shift+O" + }, + "description": "Open OpenPrompt popup" + }, + "quick-search": { + "suggested_key": { + "default": "Ctrl+Shift+P", + "mac": "Command+Shift+P" + }, + "description": "Quick search prompts" + }, + "capture-selection": { + "suggested_key": { + "default": "Ctrl+Shift+S", + "mac": "Command+Shift+S" + }, + "description": "Capture selected text as prompt" + } + }, + "host_permissions": [ + "https://chat.openai.com/*", + "https://chatgpt.com/*", + "https://claude.ai/*", + "https://gemini.google.com/*", + "https://www.perplexity.ai/*", + "https://chat.mistral.ai/*", + "https://poe.com/*", + "https://you.com/*", + "https://copilot.microsoft.com/*", + "https://open-prompt.netlify.app/*", + "http://localhost:3000/*" + ], + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } + }, + "icons": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + }, + "background": { + "service_worker": "background.js", + "type": "module" + }, + "content_scripts": [ + { + "matches": [ + "https://chat.openai.com/*", + "https://chatgpt.com/*" + ], + "js": [ + "content-scripts/chatgpt.js" + ], + "run_at": "document_idle" + }, + { + "matches": [ + "https://claude.ai/*" + ], + "js": [ + "content-scripts/claude.js" + ], + "run_at": "document_idle" + }, + { + "matches": [ + "https://gemini.google.com/*" + ], + "js": [ + "content-scripts/gemini.js" + ], + "run_at": "document_idle" + }, + { + "matches": [ + "https://www.perplexity.ai/*" + ], + "js": [ + "content-scripts/perplexity.js" + ], + "run_at": "document_idle" + }, + { + "matches": [ + "https://chat.mistral.ai/*" + ], + "js": [ + "content-scripts/mistral.js" + ], + "run_at": "document_idle" + }, + { + "matches": [ + "https://copilot.microsoft.com/*" + ], + "js": [ + "content-scripts/copilot.js" + ], + "run_at": "document_idle" + }, + { + "matches": [ + "https://open-prompt.netlify.app/*", + "http://localhost:3000/*" + ], + "js": [ + "content-scripts/openprompt-site.js" + ], + "run_at": "document_idle" + } + ], + "externally_connectable": { + "matches": [ + "https://open-prompt.netlify.app/*", + "http://localhost:3000/*" + ] + }, + "web_accessible_resources": [ + { + "resources": [ + "icons/*" + ], + "matches": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/openprompt-extension/public/small-promo-tile.png b/openprompt-extension/public/small-promo-tile.png new file mode 100644 index 0000000000000000000000000000000000000000..eb84b98141713fac51f65c7797322ef971b66a34 --- /dev/null +++ b/openprompt-extension/public/small-promo-tile.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f71a2c2e29c482527b1dd7306736923ba4cebc80c95d924e79b33a62dd7741ef +size 20901 diff --git a/openprompt-extension/scripts/create-icons.js b/openprompt-extension/scripts/create-icons.js new file mode 100644 index 0000000000000000000000000000000000000000..5ae41b5cd2c3284e0b8c5e7a538cafac277d1ed4 --- /dev/null +++ b/openprompt-extension/scripts/create-icons.js @@ -0,0 +1,27 @@ +// Simple script to create placeholder icon PNGs +// Run with: node scripts/create-icons.js + +const fs = require('fs'); +const path = require('path'); + +// Simple 1x1 purple pixel PNG base64 - we'll use SVG icons for now +// For production, use a proper image conversion tool + +const iconSizes = [16, 48, 128]; +const iconsDir = path.join(__dirname, '../public/icons'); + +// Create a simple colored square PNG (this is a minimal valid PNG) +function createMinimalPng(size) { + // For now, just create a note that real icons are needed + console.log(`Note: Create ${size}x${size} PNG icon at public/icons/icon${size}.png`); + console.log(`You can convert the SVG using: https://cloudconvert.com/svg-to-png`); +} + +iconSizes.forEach(size => { + createMinimalPng(size); +}); + +console.log('\nTo create proper icons, run:'); +console.log('npx sharp-cli --input public/icons/icon.svg --output public/icons/icon16.png --resize 16'); +console.log('npx sharp-cli --input public/icons/icon.svg --output public/icons/icon48.png --resize 48'); +console.log('npx sharp-cli --input public/icons/icon.svg --output public/icons/icon128.png --resize 128'); diff --git a/openprompt-extension/scripts/generate-icons.js b/openprompt-extension/scripts/generate-icons.js new file mode 100644 index 0000000000000000000000000000000000000000..fece6d3aad9166209a1caa5d39632d3cc249ca30 --- /dev/null +++ b/openprompt-extension/scripts/generate-icons.js @@ -0,0 +1,36 @@ +// Create extension icons from SVG +import sharp from 'sharp'; +import path from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const sizes = [16, 48, 128]; +const svgPath = path.join(__dirname, '../public/icons/icon.svg'); +const outputDir = path.join(__dirname, '../public/icons'); + +// Ensure output directory exists +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); +} + +async function createIcons() { + const svgBuffer = fs.readFileSync(svgPath); + + for (const size of sizes) { + const outputPath = path.join(outputDir, `icon${size}.png`); + + await sharp(svgBuffer) + .resize(size, size) + .png() + .toFile(outputPath); + + console.log(`Created: icon${size}.png`); + } + + console.log('\nAll icons created successfully!'); +} + +createIcons().catch(console.error); diff --git a/openprompt-extension/src/background/index.ts b/openprompt-extension/src/background/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..de6353bf4c1c773ae020e350e46ba3d658ebe24f --- /dev/null +++ b/openprompt-extension/src/background/index.ts @@ -0,0 +1,450 @@ +// Background Service Worker for OpenPrompt Extension + +// Configurable API base URL โ€” defaults to production, overridable via extension storage +let API_BASE = 'https://open-prompt.netlify.app'; + +// Load custom API URL from extension settings (set in options page) +(async () => { + try { + const result = await chrome.storage.sync.get(['apiBaseUrl']); + if (result.apiBaseUrl) API_BASE = result.apiBaseUrl; + } catch { /* use default */ } +})(); + +const PLATFORMS: Record = { + chatgpt: 'https://chatgpt.com', + claude: 'https://claude.ai', + gemini: 'https://gemini.google.com', + perplexity: 'https://www.perplexity.ai', + mistral: 'https://chat.mistral.ai', + copilot: 'https://copilot.microsoft.com', +}; + +const PLATFORM_URLS: Record = { + chatgpt: ['chat.openai.com', 'chatgpt.com'], + claude: ['claude.ai'], + gemini: ['gemini.google.com'], + perplexity: ['perplexity.ai'], + mistral: ['chat.mistral.ai'], + copilot: ['copilot.microsoft.com'], +}; + +// Get or create device ID for analytics +async function getDeviceId(): Promise { + const result = await chrome.storage.local.get(['deviceId']); + if (result.deviceId) return result.deviceId; + + const deviceId = 'ext_' + crypto.randomUUID(); + await chrome.storage.local.set({ deviceId }); + return deviceId; +} + +// Get user ID if logged in +async function getUserId(): Promise { + const result = await chrome.storage.local.get(['userId']); + return result.userId || null; +} + +// Track analytics +async function trackAnalytics(data: { + action: string; + platform?: string; + platforms?: string[]; + promptId?: string; + promptTitle?: string; + promptText?: string; + metadata?: Record; +}): Promise { + try { + const deviceId = await getDeviceId(); + const userId = await getUserId(); + + await fetch(`${API_BASE}/api/extension/analytics`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + deviceId, + userId, + ...data, + }), + }); + } catch (error) { + console.error('[OpenPrompt] Analytics error:', error); + } +} + +// Create context menus on install +function createContextMenus(): void { + chrome.contextMenus.removeAll(() => { + // Send selected text to AI + chrome.contextMenus.create({ + id: 'send-to-ai', + title: 'Send to AI', + contexts: ['selection'], + }); + + // Sub-menus for each platform + Object.entries(PLATFORMS).forEach(([id, _url]) => { + chrome.contextMenus.create({ + id: `send-to-${id}`, + parentId: 'send-to-ai', + title: id.charAt(0).toUpperCase() + id.slice(1), + contexts: ['selection'], + }); + }); + + // Capture prompt + chrome.contextMenus.create({ + id: 'capture-prompt', + title: 'Save to OpenPrompt', + contexts: ['selection'], + }); + + // Open OpenPrompt + chrome.contextMenus.create({ + id: 'open-openprompt', + title: 'Browse OpenPrompt', + contexts: ['page'], + }); + }); +} + +// Handle context menu clicks +chrome.contextMenus.onClicked.addListener(async (info, tab) => { + const selectedText = info.selectionText; + + if (info.menuItemId === 'open-openprompt') { + chrome.tabs.create({ url: API_BASE }); + return; + } + + if (info.menuItemId === 'capture-prompt' && selectedText) { + // Save to captured prompts + const deviceId = await getDeviceId(); + const userId = await getUserId(); + const platform = detectPlatformFromUrl(tab?.url || ''); + + try { + await fetch(`${API_BASE}/api/extension/capture`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + deviceId, + userId, + text: selectedText, + platform: platform || 'unknown', + url: tab?.url, + }), + }); + + // Show notification + if (tab?.id) { + chrome.tabs.sendMessage(tab.id, { + type: 'SHOW_NOTIFICATION', + message: 'โœ“ Prompt saved to OpenPrompt!', + }).catch(() => {}); + } + + trackAnalytics({ + action: 'capture', + platform: platform || 'unknown', + promptText: selectedText.slice(0, 500), + metadata: { source: 'context_menu' }, + }); + } catch (error) { + console.error('[OpenPrompt] Capture error:', error); + } + return; + } + + // Handle send-to-* menus + if (info.menuItemId?.toString().startsWith('send-to-') && selectedText) { + const platformId = info.menuItemId.toString().replace('send-to-', ''); + const url = PLATFORMS[platformId]; + + if (url) { + await chrome.storage.local.set({ + promptToInject: { + prompt: selectedText, + platform: platformId, + timestamp: Date.now(), + }, + }); + + chrome.tabs.create({ url }); + + trackAnalytics({ + action: 'context_menu', + platform: platformId, + promptText: selectedText.slice(0, 500), + }); + } + } +}); + +// Detect which AI platform from URL +function detectPlatformFromUrl(url: string): string | null { + for (const [platform, urls] of Object.entries(PLATFORM_URLS)) { + if (urls.some(u => url.includes(u))) { + return platform; + } + } + return null; +} + +// Handle keyboard shortcuts +chrome.commands.onCommand.addListener(async (command) => { + console.log('[OpenPrompt] Command:', command); + + if (command === 'quick-search') { + // Open popup with search focused + chrome.action.openPopup().catch(() => { + // Fallback: set badge to indicate action + chrome.action.setBadgeText({ text: 'S' }); + chrome.action.setBadgeBackgroundColor({ color: '#9333ea' }); + setTimeout(() => chrome.action.setBadgeText({ text: '' }), 3000); + }); + + trackAnalytics({ + action: 'shortcut_use', + metadata: { shortcut: 'quick-search' }, + }); + } + + if (command === 'capture-selection') { + // Get current tab and capture selected text + const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); + if (tab?.id) { + chrome.tabs.sendMessage(tab.id, { type: 'CAPTURE_SELECTION' }).catch(() => {}); + } + + trackAnalytics({ + action: 'shortcut_use', + metadata: { shortcut: 'capture-selection' }, + }); + } +}); + +// Handle messages from content scripts +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message.type === 'OPEN_TAB') { + chrome.tabs.create({ url: message.url }, (tab) => { + sendResponse({ success: true, tabId: tab?.id }); + }); + return true; + } + + if (message.type === 'OPEN_POPUP') { + chrome.action.setBadgeText({ text: '1' }); + chrome.action.setBadgeBackgroundColor({ color: '#9333ea' }); + setTimeout(() => chrome.action.setBadgeText({ text: '' }), 5000); + sendResponse({ success: true }); + return true; + } + + if (message.type === 'CAPTURE_PROMPT') { + // Capture from content script + (async () => { + const deviceId = await getDeviceId(); + const userId = await getUserId(); + const platform = detectPlatformFromUrl(sender.tab?.url || ''); + + try { + const response = await fetch(`${API_BASE}/api/extension/capture`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + deviceId, + userId, + text: message.text, + title: message.title, + platform: platform || 'unknown', + url: sender.tab?.url, + }), + }); + + const data = await response.json(); + sendResponse({ success: true, id: data.id }); + + trackAnalytics({ + action: 'capture', + platform: platform || 'unknown', + promptText: message.text?.slice(0, 500), + }); + } catch (error) { + sendResponse({ success: false, error: String(error) }); + } + })(); + return true; + } + + if (message.type === 'BROADCAST_PROMPT') { + // Send to multiple platforms + const { prompt, platforms: targetPlatforms } = message; + + (async () => { + for (const platformId of targetPlatforms) { + const url = PLATFORMS[platformId]; + if (url) { + await chrome.storage.local.set({ + [`promptToInject_${platformId}`]: { + prompt, + platform: platformId, + timestamp: Date.now(), + }, + }); + chrome.tabs.create({ url }); + } + } + + trackAnalytics({ + action: 'broadcast', + platforms: targetPlatforms, + promptText: prompt?.slice(0, 500), + }); + + sendResponse({ success: true }); + })(); + return true; + } + + if (message.type === 'TRACK_ANALYTICS') { + trackAnalytics(message.data).then(() => sendResponse({ success: true })); + return true; + } + + if (message.type === 'SET_USER_ID') { + chrome.storage.local.set({ userId: message.userId }).then(() => { + sendResponse({ success: true }); + }); + return true; + } + + if (message.type === 'GET_DEVICE_ID') { + getDeviceId().then(deviceId => sendResponse({ deviceId })); + return true; + } +}); + +// Handle external messages from the website +chrome.runtime.onMessageExternal.addListener( + (message, sender, sendResponse) => { + console.log('[OpenPrompt] External message received:', message, 'from:', sender); + + if (message.type === 'CHECK_EXTENSION') { + sendResponse({ installed: true, version: chrome.runtime.getManifest().version }); + return true; + } + + if (message.type === 'SYNC_USER') { + chrome.storage.local.set({ userId: message.userId }).then(() => { + sendResponse({ success: true }); + }); + return true; + } + + if (message.type === 'OPEN_IN_AI') { + chrome.storage.local.set({ + pendingPrompt: { + prompt: message.prompt, + title: message.title, + promptId: message.promptId, + timestamp: Date.now(), + } + }).then(async () => { + if (message.platform) { + const url = PLATFORMS[message.platform]; + if (url) { + await chrome.storage.local.set({ + promptToInject: { + prompt: message.prompt, + platform: message.platform, + timestamp: Date.now(), + } + }); + chrome.tabs.create({ url }); + + trackAnalytics({ + action: 'inject', + platform: message.platform, + promptId: message.promptId, + promptTitle: message.title, + }); + } + } + sendResponse({ success: true }); + }); + return true; + } + } +); + +// Handle installation +chrome.runtime.onInstalled.addListener((details) => { + if (details.reason === 'install') { + console.log('[OpenPrompt] Extension installed'); + createContextMenus(); + chrome.tabs.create({ + url: `${API_BASE}/extension?installed=true` + }); + + trackAnalytics({ + action: 'install', + metadata: { version: chrome.runtime.getManifest().version }, + }); + } else if (details.reason === 'update') { + console.log('[OpenPrompt] Extension updated to version', chrome.runtime.getManifest().version); + createContextMenus(); + + trackAnalytics({ + action: 'update', + metadata: { version: chrome.runtime.getManifest().version }, + }); + } +}); + +// Handle tab updates to inject prompts +chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { + if (changeInfo.status === 'complete' && tab.url) { + // Check for regular prompt injection + const result = await chrome.storage.local.get(['promptToInject']); + + if (result.promptToInject) { + const { platform } = result.promptToInject; + const urls = PLATFORM_URLS[platform] || []; + const isMatchingUrl = urls.some(url => tab.url?.includes(url)); + + if (isMatchingUrl) { + setTimeout(() => { + chrome.tabs.sendMessage(tabId, { type: 'INJECT_PROMPT' }).catch(() => {}); + }, 1000); + } + } + + // Check for broadcast prompts + for (const platformId of Object.keys(PLATFORMS)) { + const broadcastResult = await chrome.storage.local.get([`promptToInject_${platformId}`]); + const promptData = broadcastResult[`promptToInject_${platformId}`]; + + if (promptData) { + const urls = PLATFORM_URLS[platformId] || []; + const isMatchingUrl = urls.some(url => tab.url?.includes(url)); + + if (isMatchingUrl) { + // Move broadcast prompt to regular prompt slot for injection + await chrome.storage.local.set({ promptToInject: promptData }); + await chrome.storage.local.remove(`promptToInject_${platformId}`); + + setTimeout(() => { + chrome.tabs.sendMessage(tabId, { type: 'INJECT_PROMPT' }).catch(() => {}); + }, 1000); + } + } + } + } +}); + +// Initialize context menus on startup +createContextMenus(); + +console.log('[OpenPrompt] Background service worker started'); diff --git a/openprompt-extension/src/content-scripts/chatgpt.ts b/openprompt-extension/src/content-scripts/chatgpt.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c46da32901802e277000f59b81dcaf094f11da5 --- /dev/null +++ b/openprompt-extension/src/content-scripts/chatgpt.ts @@ -0,0 +1,87 @@ +// ChatGPT Content Script +import { + getPromptToInject, + clearPromptToInject, + waitForElement, + showNotification, + setupCaptureListener, + createCaptureButton +} from './utils'; + +async function injectPrompt(): Promise { + const promptData = await getPromptToInject(); + + if (!promptData || promptData.platform !== 'chatgpt') { + return; + } + + console.log('[OpenPrompt] Injecting prompt into ChatGPT...'); + + // Wait for the textarea to be available + // ChatGPT uses a contenteditable div with id="prompt-textarea" + const textareaSelector = '#prompt-textarea'; + const textarea = await waitForElement(textareaSelector, 15000); + + if (!textarea) { + console.error('[OpenPrompt] Could not find ChatGPT textarea'); + showNotification('Could not find input field. Please try again.', 'error'); + return; + } + + try { + // Focus the textarea + (textarea as HTMLElement).focus(); + + // Clear existing content + textarea.innerHTML = ''; + + // Create a paragraph element with the prompt text + const p = document.createElement('p'); + p.textContent = promptData.prompt; + textarea.appendChild(p); + + // Dispatch input event to trigger React state update + textarea.dispatchEvent(new InputEvent('input', { + bubbles: true, + cancelable: true, + inputType: 'insertText', + data: promptData.prompt, + })); + + // Clear the pending prompt + await clearPromptToInject(); + + showNotification('โœ“ Prompt loaded! Press Enter to send.'); + console.log('[OpenPrompt] Prompt injected successfully'); + } catch (error) { + console.error('[OpenPrompt] Error injecting prompt:', error); + showNotification('Failed to inject prompt. Please try again.', 'error'); + } +} + +// Initialize +function init(): void { + // Setup capture listener for keyboard shortcut + setupCaptureListener(); + + // Add floating capture button + createCaptureButton('ChatGPT'); + + // Try to inject prompt + setTimeout(injectPrompt, 1500); +} + +// Run on page load +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} + +// Listen for messages from the extension +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message.type === 'INJECT_PROMPT') { + injectPrompt().then(() => sendResponse({ success: true })); + return true; + } +}); diff --git a/openprompt-extension/src/content-scripts/claude.ts b/openprompt-extension/src/content-scripts/claude.ts new file mode 100644 index 0000000000000000000000000000000000000000..9df4995aad11e51f104a85886073533c828e603f --- /dev/null +++ b/openprompt-extension/src/content-scripts/claude.ts @@ -0,0 +1,83 @@ +// Claude Content Script +import { + getPromptToInject, + clearPromptToInject, + waitForElement, + showNotification, + setupCaptureListener, + createCaptureButton +} from './utils'; + +async function injectPrompt(): Promise { + const promptData = await getPromptToInject(); + + if (!promptData || promptData.platform !== 'claude') { + return; + } + + console.log('[OpenPrompt] Injecting prompt into Claude...'); + + // Claude uses a contenteditable div with class containing "ProseMirror" + const textareaSelector = '[contenteditable="true"].ProseMirror, div[contenteditable="true"]'; + const textarea = await waitForElement(textareaSelector, 15000); + + if (!textarea) { + console.error('[OpenPrompt] Could not find Claude textarea'); + showNotification('Could not find input field. Please try again.', 'error'); + return; + } + + try { + const element = textarea as HTMLElement; + + // Focus the element + element.focus(); + + // Clear existing content + element.innerHTML = ''; + + // For ProseMirror editors, we need to create a paragraph + const p = document.createElement('p'); + p.textContent = promptData.prompt; + element.appendChild(p); + + // Dispatch input event + element.dispatchEvent(new InputEvent('input', { + bubbles: true, + cancelable: true, + inputType: 'insertText', + data: promptData.prompt, + })); + + // Clear the pending prompt + await clearPromptToInject(); + + showNotification('โœ“ Prompt loaded! Press Enter to send.'); + console.log('[OpenPrompt] Prompt injected successfully'); + } catch (error) { + console.error('[OpenPrompt] Error injecting prompt:', error); + showNotification('Failed to inject prompt. Please try again.', 'error'); + } +} + +// Initialize +function init(): void { + setupCaptureListener(); + createCaptureButton('Claude'); + setTimeout(injectPrompt, 2000); +} + +// Run on page load +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} + +// Listen for messages from the extension +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message.type === 'INJECT_PROMPT') { + injectPrompt().then(() => sendResponse({ success: true })); + return true; + } +}); diff --git a/openprompt-extension/src/content-scripts/copilot.ts b/openprompt-extension/src/content-scripts/copilot.ts new file mode 100644 index 0000000000000000000000000000000000000000..a30bb9e4e8b6f60ed8a1b4a5548fe053a2e31659 --- /dev/null +++ b/openprompt-extension/src/content-scripts/copilot.ts @@ -0,0 +1,72 @@ +// Microsoft Copilot Content Script +import { + getPromptToInject, + clearPromptToInject, + waitForElement, + showNotification, + setupCaptureListener, + createCaptureButton +} from './utils'; + +async function injectPrompt(): Promise { + const promptData = await getPromptToInject(); + + if (!promptData || promptData.platform !== 'copilot') { + return; + } + + console.log('[OpenPrompt] Injecting prompt into Copilot...'); + + // Copilot uses a textarea + const textareaSelector = 'textarea#userInput, textarea[name="searchbox"], textarea'; + const textarea = await waitForElement(textareaSelector, 15000); + + if (!textarea) { + console.error('[OpenPrompt] Could not find Copilot textarea'); + showNotification('Could not find input field. Please try again.', 'error'); + return; + } + + try { + const element = textarea as HTMLTextAreaElement; + + // Focus and set value + element.focus(); + element.value = promptData.prompt; + + // Dispatch events + element.dispatchEvent(new Event('input', { bubbles: true })); + element.dispatchEvent(new Event('change', { bubbles: true })); + + // Clear the pending prompt + await clearPromptToInject(); + + showNotification('โœ“ Prompt loaded! Press Enter to send.'); + console.log('[OpenPrompt] Prompt injected successfully'); + } catch (error) { + console.error('[OpenPrompt] Error injecting prompt:', error); + showNotification('Failed to inject prompt. Please try again.', 'error'); + } +} + +// Initialize +function init(): void { + setupCaptureListener(); + createCaptureButton('Copilot'); + setTimeout(injectPrompt, 2000); +} + +// Run on page load +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} + +// Listen for messages from the extension +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message.type === 'INJECT_PROMPT') { + injectPrompt().then(() => sendResponse({ success: true })); + return true; + } +}); diff --git a/openprompt-extension/src/content-scripts/gemini.ts b/openprompt-extension/src/content-scripts/gemini.ts new file mode 100644 index 0000000000000000000000000000000000000000..ded3773b94f097488cb1c004a79d0ce3feb0f6b1 --- /dev/null +++ b/openprompt-extension/src/content-scripts/gemini.ts @@ -0,0 +1,87 @@ +// Gemini Content Script +import { + getPromptToInject, + clearPromptToInject, + waitForElement, + showNotification, + setupCaptureListener, + createCaptureButton +} from './utils'; + +async function injectPrompt(): Promise { + const promptData = await getPromptToInject(); + + if (!promptData || promptData.platform !== 'gemini') { + return; + } + + console.log('[OpenPrompt] Injecting prompt into Gemini...'); + + // Gemini uses a rich text input with contenteditable + const textareaSelector = '.ql-editor, [contenteditable="true"], textarea'; + const textarea = await waitForElement(textareaSelector, 15000); + + if (!textarea) { + console.error('[OpenPrompt] Could not find Gemini textarea'); + showNotification('Could not find input field. Please try again.', 'error'); + return; + } + + try { + const element = textarea as HTMLElement; + + // Focus the element + element.focus(); + + if (element.getAttribute('contenteditable') === 'true') { + // For contenteditable elements + element.innerHTML = ''; + + const p = document.createElement('p'); + p.textContent = promptData.prompt; + element.appendChild(p); + + element.dispatchEvent(new InputEvent('input', { + bubbles: true, + cancelable: true, + inputType: 'insertText', + data: promptData.prompt, + })); + } else if (element instanceof HTMLTextAreaElement) { + // For textarea elements + element.value = promptData.prompt; + element.dispatchEvent(new Event('input', { bubbles: true })); + } + + // Clear the pending prompt + await clearPromptToInject(); + + showNotification('โœ“ Prompt loaded! Press Enter to send.'); + console.log('[OpenPrompt] Prompt injected successfully'); + } catch (error) { + console.error('[OpenPrompt] Error injecting prompt:', error); + showNotification('Failed to inject prompt. Please try again.', 'error'); + } +} + +// Initialize +function init(): void { + setupCaptureListener(); + createCaptureButton('Gemini'); + setTimeout(injectPrompt, 2000); +} + +// Run on page load +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} + +// Listen for messages from the extension +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message.type === 'INJECT_PROMPT') { + injectPrompt().then(() => sendResponse({ success: true })); + return true; + } +}); diff --git a/openprompt-extension/src/content-scripts/mistral.ts b/openprompt-extension/src/content-scripts/mistral.ts new file mode 100644 index 0000000000000000000000000000000000000000..721082f2be466cd09929b67f4114b3f394bb93b2 --- /dev/null +++ b/openprompt-extension/src/content-scripts/mistral.ts @@ -0,0 +1,83 @@ +// Mistral Content Script +import { + getPromptToInject, + clearPromptToInject, + waitForElement, + showNotification, + setupCaptureListener, + createCaptureButton +} from './utils'; + +async function injectPrompt(): Promise { + const promptData = await getPromptToInject(); + + if (!promptData || promptData.platform !== 'mistral') { + return; + } + + console.log('[OpenPrompt] Injecting prompt into Mistral...'); + + // Mistral uses a textarea or contenteditable + const textareaSelector = 'textarea, [contenteditable="true"]'; + const textarea = await waitForElement(textareaSelector, 15000); + + if (!textarea) { + console.error('[OpenPrompt] Could not find Mistral textarea'); + showNotification('Could not find input field. Please try again.', 'error'); + return; + } + + try { + const element = textarea as HTMLElement; + element.focus(); + + if (element instanceof HTMLTextAreaElement) { + element.value = promptData.prompt; + element.dispatchEvent(new Event('input', { bubbles: true })); + element.dispatchEvent(new Event('change', { bubbles: true })); + } else if (element.getAttribute('contenteditable') === 'true') { + element.innerHTML = ''; + const p = document.createElement('p'); + p.textContent = promptData.prompt; + element.appendChild(p); + + element.dispatchEvent(new InputEvent('input', { + bubbles: true, + cancelable: true, + inputType: 'insertText', + data: promptData.prompt, + })); + } + + // Clear the pending prompt + await clearPromptToInject(); + + showNotification('โœ“ Prompt loaded! Press Enter to send.'); + console.log('[OpenPrompt] Prompt injected successfully'); + } catch (error) { + console.error('[OpenPrompt] Error injecting prompt:', error); + showNotification('Failed to inject prompt. Please try again.', 'error'); + } +} + +// Initialize +function init(): void { + setupCaptureListener(); + createCaptureButton('Mistral'); + setTimeout(injectPrompt, 1500); +} + +// Run on page load +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} + +// Listen for messages from the extension +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message.type === 'INJECT_PROMPT') { + injectPrompt().then(() => sendResponse({ success: true })); + return true; + } +}); diff --git a/openprompt-extension/src/content-scripts/openprompt-site.ts b/openprompt-extension/src/content-scripts/openprompt-site.ts new file mode 100644 index 0000000000000000000000000000000000000000..caa03d18a004f9d94abca4fb7b520ff74d7a84fd --- /dev/null +++ b/openprompt-extension/src/content-scripts/openprompt-site.ts @@ -0,0 +1,120 @@ +// OpenPrompt Website Content Script +// This script runs on the OpenPrompt website to enable communication with the extension + +interface OpenInMessage { + type: 'OPEN_IN_AI'; + prompt: string; + title?: string; + platform?: string; +} + +// Helper to check if extension context is still valid +function isExtensionContextValid(): boolean { + try { + // This will throw if context is invalidated + return !!chrome.runtime?.id; + } catch { + return false; + } +} + +// Safely call chrome APIs with error handling +async function safeStorageSet(data: Record): Promise { + try { + if (!isExtensionContextValid()) return false; + await chrome.storage.local.set(data); + return true; + } catch (error) { + console.warn('[OpenPrompt Extension] Storage error (extension may need reload):', error); + return false; + } +} + +function safeSendMessage(message: unknown): void { + try { + if (!isExtensionContextValid()) return; + chrome.runtime.sendMessage(message); + } catch (error) { + console.warn('[OpenPrompt Extension] Message error (extension may need reload):', error); + } +} + +// Listen for messages from the website +window.addEventListener('message', async (event) => { + // Only accept messages from the same origin + if (event.origin !== window.location.origin) { + return; + } + + const message = event.data as OpenInMessage; + + if (message.type === 'OPEN_IN_AI') { + console.log('[OpenPrompt Extension] Received prompt from website:', message); + + // Check if extension context is still valid + if (!isExtensionContextValid()) { + console.warn('[OpenPrompt Extension] Extension context invalidated. Please refresh the page.'); + window.postMessage({ + type: 'OPEN_IN_AI_RECEIVED', + success: false, + error: 'Extension needs to be reloaded. Please refresh the page.', + }, '*'); + return; + } + + // Store the prompt for the popup or direct injection + await safeStorageSet({ + pendingPrompt: { + prompt: message.prompt, + title: message.title, + timestamp: Date.now(), + } + }); + + // If a specific platform is requested, open it directly + if (message.platform) { + const platforms: Record = { + chatgpt: 'https://chatgpt.com', + claude: 'https://claude.ai', + gemini: 'https://gemini.google.com', + perplexity: 'https://www.perplexity.ai', + mistral: 'https://chat.mistral.ai', + copilot: 'https://copilot.microsoft.com', + }; + + const url = platforms[message.platform]; + if (url) { + await safeStorageSet({ + promptToInject: { + prompt: message.prompt, + platform: message.platform, + timestamp: Date.now(), + } + }); + + safeSendMessage({ + type: 'OPEN_TAB', + url: url, + }); + } + } else { + // Open the extension popup to let user choose + safeSendMessage({ type: 'OPEN_POPUP' }); + } + + // Send confirmation back to the website + window.postMessage({ + type: 'OPEN_IN_AI_RECEIVED', + success: true, + }, '*'); + } +}); + +// Inject a script to add the extension detection +// We use postMessage instead of inline script to avoid CSP issues +window.postMessage({ type: 'OPENPROMPT_EXTENSION_READY' }, '*'); + +// Also set a data attribute on the body +document.body.setAttribute('data-openprompt-extension', 'true'); + +console.log('[OpenPrompt Extension] Content script loaded on OpenPrompt website'); diff --git a/openprompt-extension/src/content-scripts/perplexity.ts b/openprompt-extension/src/content-scripts/perplexity.ts new file mode 100644 index 0000000000000000000000000000000000000000..14cd9d2595ad3da2f4fef93c6e5607c7fc53cf86 --- /dev/null +++ b/openprompt-extension/src/content-scripts/perplexity.ts @@ -0,0 +1,83 @@ +// Perplexity Content Script +import { + getPromptToInject, + clearPromptToInject, + waitForElement, + showNotification, + setupCaptureListener, + createCaptureButton +} from './utils'; + +async function injectPrompt(): Promise { + const promptData = await getPromptToInject(); + + if (!promptData || promptData.platform !== 'perplexity') { + return; + } + + console.log('[OpenPrompt] Injecting prompt into Perplexity...'); + + // Perplexity uses a textarea + const textareaSelector = 'textarea[placeholder*="Ask"], textarea'; + const textarea = await waitForElement(textareaSelector, 15000); + + if (!textarea) { + console.error('[OpenPrompt] Could not find Perplexity textarea'); + showNotification('Could not find input field. Please try again.', 'error'); + return; + } + + try { + const element = textarea as HTMLTextAreaElement; + + // Focus and set value + element.focus(); + element.value = promptData.prompt; + + // Dispatch events for React + element.dispatchEvent(new Event('input', { bubbles: true })); + element.dispatchEvent(new Event('change', { bubbles: true })); + + // For React synthetic events + const nativeInputValueSetter = Object.getOwnPropertyDescriptor( + HTMLTextAreaElement.prototype, + 'value' + )?.set; + + if (nativeInputValueSetter) { + nativeInputValueSetter.call(element, promptData.prompt); + element.dispatchEvent(new Event('input', { bubbles: true })); + } + + // Clear the pending prompt + await clearPromptToInject(); + + showNotification('โœ“ Prompt loaded! Press Enter to send.'); + console.log('[OpenPrompt] Prompt injected successfully'); + } catch (error) { + console.error('[OpenPrompt] Error injecting prompt:', error); + showNotification('Failed to inject prompt. Please try again.', 'error'); + } +} + +// Initialize +function init(): void { + setupCaptureListener(); + createCaptureButton('Perplexity'); + setTimeout(injectPrompt, 1500); +} + +// Run on page load +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} + +// Listen for messages from the extension +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message.type === 'INJECT_PROMPT') { + injectPrompt().then(() => sendResponse({ success: true })); + return true; + } +}); diff --git a/openprompt-extension/src/content-scripts/utils.ts b/openprompt-extension/src/content-scripts/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..696ddd77dcbe1cfe3d9be008b4f5dd6bd25de4da --- /dev/null +++ b/openprompt-extension/src/content-scripts/utils.ts @@ -0,0 +1,258 @@ +// Shared utilities for content scripts + +export interface PromptToInject { + prompt: string; + platform: string; + timestamp: number; +} + +export async function getPromptToInject(): Promise { + return new Promise((resolve) => { + chrome.storage.local.get(['promptToInject'], (result) => { + if (result.promptToInject) { + // Check if prompt is recent (within last 30 seconds) + const isRecent = Date.now() - result.promptToInject.timestamp < 30000; + if (isRecent) { + resolve(result.promptToInject); + } else { + // Clear stale prompt + chrome.storage.local.remove('promptToInject'); + resolve(null); + } + } else { + resolve(null); + } + }); + }); +} + +export async function clearPromptToInject(): Promise { + return new Promise((resolve) => { + chrome.storage.local.remove('promptToInject', () => resolve()); + }); +} + +export function waitForElement( + selector: string, + timeout = 10000 +): Promise { + return new Promise((resolve) => { + const element = document.querySelector(selector); + if (element) { + resolve(element); + return; + } + + const observer = new MutationObserver(() => { + const element = document.querySelector(selector); + if (element) { + observer.disconnect(); + resolve(element); + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true, + }); + + setTimeout(() => { + observer.disconnect(); + resolve(null); + }, timeout); + }); +} + +export function simulateInput(element: HTMLElement, text: string): void { + // For contenteditable elements + if (element.getAttribute('contenteditable') === 'true') { + element.focus(); + element.innerHTML = ''; + + // Use execCommand for better compatibility + document.execCommand('insertText', false, text); + + // Dispatch input event + element.dispatchEvent(new InputEvent('input', { + bubbles: true, + cancelable: true, + inputType: 'insertText', + data: text, + })); + } + // For textarea/input elements + else if (element instanceof HTMLTextAreaElement || element instanceof HTMLInputElement) { + element.focus(); + element.value = text; + + // Dispatch events to trigger React state updates + element.dispatchEvent(new Event('input', { bubbles: true })); + element.dispatchEvent(new Event('change', { bubbles: true })); + + // For React 17+ synthetic events + const nativeInputValueSetter = Object.getOwnPropertyDescriptor( + element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype, + 'value' + )?.set; + + if (nativeInputValueSetter) { + nativeInputValueSetter.call(element, text); + element.dispatchEvent(new Event('input', { bubbles: true })); + } + } +} + +export function showNotification(message: string, type: 'success' | 'error' = 'success'): void { + const notification = document.createElement('div'); + notification.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + padding: 12px 20px; + border-radius: 8px; + background: ${type === 'success' ? 'linear-gradient(135deg, #10b981, #059669)' : 'linear-gradient(135deg, #ef4444, #dc2626)'}; + color: white; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-size: 14px; + font-weight: 500; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + z-index: 999999; + animation: slideIn 0.3s ease; + `; + + notification.textContent = message; + + // Add animation keyframes + const style = document.createElement('style'); + style.textContent = ` + @keyframes slideIn { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } + } + `; + document.head.appendChild(style); + document.body.appendChild(notification); + + setTimeout(() => { + notification.style.animation = 'slideIn 0.3s ease reverse'; + setTimeout(() => { + notification.remove(); + style.remove(); + }, 300); + }, 3000); +} + +// Capture selected text +export function getSelectedText(): string { + const selection = window.getSelection(); + return selection ? selection.toString().trim() : ''; +} + +// Handle capture selection command from background +export function setupCaptureListener(): void { + chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message.type === 'CAPTURE_SELECTION') { + const text = getSelectedText(); + if (text) { + chrome.runtime.sendMessage({ + type: 'CAPTURE_PROMPT', + text, + title: document.title, + }).then(() => { + showNotification('โœ“ Prompt captured!'); + }).catch(() => { + showNotification('Failed to capture prompt', 'error'); + }); + } else { + showNotification('No text selected', 'error'); + } + sendResponse({ success: true }); + return true; + } + + if (message.type === 'SHOW_NOTIFICATION') { + showNotification(message.message, message.type || 'success'); + sendResponse({ success: true }); + return true; + } + }); +} + +// Create floating capture button for AI chat pages +export function createCaptureButton(platform: string): void { + // Remove existing button + const existing = document.getElementById('openprompt-capture-btn'); + if (existing) existing.remove(); + + const button = document.createElement('button'); + button.id = 'openprompt-capture-btn'; + button.innerHTML = ` + + + + + + Save to OpenPrompt + `; + button.style.cssText = ` + position: fixed; + bottom: 20px; + right: 20px; + display: none; + align-items: center; + gap: 8px; + padding: 10px 16px; + border: none; + border-radius: 8px; + background: linear-gradient(135deg, #9333ea, #db2777); + color: white; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-size: 14px; + font-weight: 500; + cursor: pointer; + box-shadow: 0 4px 12px rgba(147, 51, 234, 0.4); + z-index: 999998; + transition: transform 0.2s, box-shadow 0.2s; + `; + + button.addEventListener('mouseenter', () => { + button.style.transform = 'scale(1.05)'; + button.style.boxShadow = '0 6px 16px rgba(147, 51, 234, 0.5)'; + }); + + button.addEventListener('mouseleave', () => { + button.style.transform = 'scale(1)'; + button.style.boxShadow = '0 4px 12px rgba(147, 51, 234, 0.4)'; + }); + + button.addEventListener('click', () => { + const text = getSelectedText(); + if (text) { + chrome.runtime.sendMessage({ + type: 'CAPTURE_PROMPT', + text, + title: `Captured from ${platform}`, + }).then(() => { + showNotification('โœ“ Prompt saved to OpenPrompt!'); + }).catch(() => { + showNotification('Failed to save prompt', 'error'); + }); + } else { + showNotification('Select text to capture', 'error'); + } + }); + + document.body.appendChild(button); + + // Show/hide based on selection + document.addEventListener('selectionchange', () => { + const text = getSelectedText(); + button.style.display = text.length > 10 ? 'flex' : 'none'; + }); +} diff --git a/openprompt-extension/src/popup/App.tsx b/openprompt-extension/src/popup/App.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a2f2f11309ad494e9ee598f09d9a7f7a75acf6c7 --- /dev/null +++ b/openprompt-extension/src/popup/App.tsx @@ -0,0 +1,743 @@ +import { useState, useEffect, useMemo } from 'react'; +import { + Sparkles, + ExternalLink, + Settings, + History, + Copy, + Check, + ChevronRight, + Zap, + Search, + BarChart3, + Send, + Layers, + X, + Keyboard, + Save, + Bot, + Brain, + Wind, + Rocket, + FileText +} from 'lucide-react'; + +const API_BASE = 'https://open-prompt.netlify.app'; +// const API_BASE = 'http://localhost:3000'; // For development + +// Icon components for platforms +const PlatformIcons: Record = { + chatgpt: Bot, + claude: Brain, + gemini: Sparkles, + perplexity: Search, + mistral: Wind, + copilot: Rocket, +}; + +// Supported AI platforms +const AI_PLATFORMS = [ + { + id: 'chatgpt', + name: 'ChatGPT', + url: 'https://chatgpt.com', + color: 'from-green-500 to-emerald-600', + bgColor: 'bg-green-500/10', + borderColor: 'border-green-500/30', + }, + { + id: 'claude', + name: 'Claude', + url: 'https://claude.ai', + color: 'from-orange-500 to-amber-600', + bgColor: 'bg-orange-500/10', + borderColor: 'border-orange-500/30', + }, + { + id: 'gemini', + name: 'Gemini', + url: 'https://gemini.google.com', + color: 'from-blue-500 to-indigo-600', + bgColor: 'bg-blue-500/10', + borderColor: 'border-blue-500/30', + }, + { + id: 'perplexity', + name: 'Perplexity', + url: 'https://www.perplexity.ai', + color: 'from-cyan-500 to-teal-600', + bgColor: 'bg-cyan-500/10', + borderColor: 'border-cyan-500/30', + }, + { + id: 'mistral', + name: 'Mistral', + url: 'https://chat.mistral.ai', + color: 'from-purple-500 to-violet-600', + bgColor: 'bg-purple-500/10', + borderColor: 'border-purple-500/30', + }, + { + id: 'copilot', + name: 'Copilot', + url: 'https://copilot.microsoft.com', + color: 'from-sky-500 to-blue-600', + bgColor: 'bg-sky-500/10', + borderColor: 'border-sky-500/30', + }, +]; + +interface PendingPrompt { + prompt: string; + title?: string; + promptId?: string; + timestamp: number; +} + +interface RecentPrompt { + prompt: string; + title?: string; + platform: string; + timestamp: number; +} + +interface CapturedPrompt { + id: string; + text: string; + title?: string; + platform: string; + createdAt: string; +} + +interface Analytics { + stats: { action: string; count: number }[]; + platformStats: { platform: string; count: number }[]; +} + +type TabType = 'main' | 'settings' | 'analytics' | 'search' | 'captured'; + +// Helper to get platform icon component +const getPlatformIcon = (platformId: string, className: string = "h-5 w-5") => { + const IconComponent = PlatformIcons[platformId] || FileText; + return ; +}; + +function App() { + const [pendingPrompt, setPendingPrompt] = useState(null); + const [recentPrompts, setRecentPrompts] = useState([]); + const [capturedPrompts, setCapturedPrompts] = useState([]); + const [defaultPlatform, setDefaultPlatform] = useState('chatgpt'); + const [activeTab, setActiveTab] = useState('main'); + const [copied, setCopied] = useState(false); + const [sending, setSending] = useState(null); + const [searchQuery, setSearchQuery] = useState(''); + const [analytics, setAnalytics] = useState(null); + const [broadcastMode, setBroadcastMode] = useState(false); + const [selectedPlatforms, setSelectedPlatforms] = useState([]); + + useEffect(() => { + // Load data from storage + chrome.storage.local.get(['pendingPrompt', 'recentPrompts', 'defaultPlatform', 'deviceId'], (result) => { + if (result.pendingPrompt) { + setPendingPrompt(result.pendingPrompt); + } + if (result.recentPrompts) { + setRecentPrompts(result.recentPrompts.slice(0, 10)); + } + if (result.defaultPlatform) { + setDefaultPlatform(result.defaultPlatform); + } + + // Fetch analytics and captured prompts + if (result.deviceId) { + fetchAnalytics(result.deviceId); + fetchCapturedPrompts(result.deviceId); + } + }); + }, []); + + const fetchAnalytics = async (deviceId: string) => { + try { + const response = await fetch(`${API_BASE}/api/extension/analytics?deviceId=${deviceId}`); + if (response.ok) { + const data = await response.json(); + setAnalytics(data); + } + } catch (error) { + console.error('Failed to fetch analytics:', error); + } + }; + + const fetchCapturedPrompts = async (deviceId: string) => { + try { + const response = await fetch(`${API_BASE}/api/extension/capture?deviceId=${deviceId}&limit=10`); + if (response.ok) { + const data = await response.json(); + setCapturedPrompts(data.captured || []); + } + } catch (error) { + console.error('Failed to fetch captured prompts:', error); + } + }; + + // Fuzzy search through recent prompts + const filteredPrompts = useMemo(() => { + if (!searchQuery.trim()) return recentPrompts; + + const query = searchQuery.toLowerCase(); + return recentPrompts.filter(p => + p.title?.toLowerCase().includes(query) || + p.prompt.toLowerCase().includes(query) + ); + }, [searchQuery, recentPrompts]); + + const handleOpenIn = async (platformId: string) => { + if (!pendingPrompt) return; + + setSending(platformId); + const platform = AI_PLATFORMS.find(p => p.id === platformId); + if (!platform) return; + + // Save to recent prompts + const newRecent: RecentPrompt = { + prompt: pendingPrompt.prompt, + title: pendingPrompt.title, + platform: platformId, + timestamp: Date.now(), + }; + + const updatedRecents = [newRecent, ...recentPrompts.filter(r => + r.prompt !== pendingPrompt.prompt || r.platform !== platformId + )].slice(0, 10); + + await chrome.storage.local.set({ recentPrompts: updatedRecents }); + setRecentPrompts(updatedRecents); + + // Store prompt for the content script to pick up + await chrome.storage.local.set({ + promptToInject: { + prompt: pendingPrompt.prompt, + platform: platformId, + timestamp: Date.now(), + } + }); + + // Track analytics + chrome.runtime.sendMessage({ + type: 'TRACK_ANALYTICS', + data: { + action: 'inject', + platform: platformId, + promptId: pendingPrompt.promptId, + promptTitle: pendingPrompt.title, + } + }); + + // Open the platform in a new tab + chrome.tabs.create({ url: platform.url }, () => { + setSending(null); + chrome.storage.local.remove('pendingPrompt'); + setPendingPrompt(null); + }); + }; + + const handleBroadcast = async () => { + if (!pendingPrompt || selectedPlatforms.length === 0) return; + + setSending('broadcast'); + + // Track analytics + chrome.runtime.sendMessage({ + type: 'TRACK_ANALYTICS', + data: { + action: 'broadcast', + platforms: selectedPlatforms, + promptTitle: pendingPrompt.title, + } + }); + + // Send broadcast message + chrome.runtime.sendMessage({ + type: 'BROADCAST_PROMPT', + prompt: pendingPrompt.prompt, + platforms: selectedPlatforms, + }, () => { + setSending(null); + setBroadcastMode(false); + setSelectedPlatforms([]); + chrome.storage.local.remove('pendingPrompt'); + setPendingPrompt(null); + }); + }; + + const togglePlatformSelection = (platformId: string) => { + setSelectedPlatforms(prev => + prev.includes(platformId) + ? prev.filter(p => p !== platformId) + : [...prev, platformId] + ); + }; + + const handleCopyPrompt = () => { + if (!pendingPrompt) return; + navigator.clipboard.writeText(pendingPrompt.prompt); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + const handleSetDefault = (platformId: string) => { + setDefaultPlatform(platformId); + chrome.storage.local.set({ defaultPlatform: platformId }); + }; + + const handleReopenPrompt = async (recent: RecentPrompt) => { + const platform = AI_PLATFORMS.find(p => p.id === recent.platform); + if (!platform) return; + + await chrome.storage.local.set({ + promptToInject: { + prompt: recent.prompt, + platform: recent.platform, + timestamp: Date.now(), + } + }); + + chrome.tabs.create({ url: platform.url }); + }; + + const handleUseCaptured = async (captured: CapturedPrompt) => { + setPendingPrompt({ + prompt: captured.text, + title: captured.title || `From ${captured.platform}`, + timestamp: Date.now(), + }); + setActiveTab('main'); + }; + + const renderTabContent = () => { + switch (activeTab) { + case 'settings': + return ( +
+

Default Platform

+
+ {AI_PLATFORMS.map((platform) => ( + + ))} +
+ +
+

+ + Keyboard Shortcuts +

+
+
+ Open Popup + Ctrl+Shift+O +
+
+ Quick Search + Ctrl+Shift+P +
+
+ Capture Selection + Ctrl+Shift+S +
+
+
+
+ ); + + case 'analytics': + return ( +
+

+ + Your Usage Stats +

+ + {analytics ? ( + <> +
+ {analytics.stats.map(stat => ( +
+
{stat.count}
+
{stat.action}s
+
+ ))} +
+ +

By Platform

+
+ {analytics.platformStats.map(stat => { + const platform = AI_PLATFORMS.find(p => p.id === stat.platform); + return ( +
+ {getPlatformIcon(stat.platform)} + {platform?.name || stat.platform} + {stat.count} +
+ ); + })} +
+ + ) : ( +
+ +

No usage data yet

+

Start using prompts to see stats

+
+ )} +
+ ); + + case 'search': + return ( +
+
+ + setSearchQuery(e.target.value)} + placeholder="Search your prompts..." + className="w-full pl-10 pr-4 py-2 rounded-lg bg-white/10 border border-white/20 text-sm focus:outline-none focus:ring-2 focus:ring-purple-500" + autoFocus + /> +
+ +
+ {filteredPrompts.length > 0 ? ( + filteredPrompts.map((prompt, index) => ( + + )) + ) : ( +
+ +

No matching prompts

+
+ )} +
+
+ ); + + case 'captured': + return ( +
+

+ + Captured Prompts +

+ + {capturedPrompts.length > 0 ? ( +
+ {capturedPrompts.map((captured) => ( + + ))} +
+ ) : ( +
+ +

No captured prompts yet

+

Select text in any AI chat and use Ctrl+Shift+S

+
+ )} +
+ ); + + default: + // Main view + if (pendingPrompt) { + return ( +
+
+
+

+ {pendingPrompt.title || 'Prompt Ready'} +

+ +
+

+ {pendingPrompt.prompt} +

+
+ + {broadcastMode ? ( + <> +
+

+ + Broadcast to Multiple +

+ +
+ +
+ {AI_PLATFORMS.map((platform) => ( + + ))} +
+ + + + ) : ( + <> +
+

+ + Open in... +

+ +
+ +
+ {AI_PLATFORMS.map((platform) => ( + + ))} +
+ + )} +
+ ); + } + + // No pending prompt + return ( +
+
+
+ +
+

No Prompt Selected

+

+ Visit OpenPrompt and click "Open In..." on any prompt to send it to your favorite AI chat. +

+
+ + {recentPrompts.length > 0 && ( +
+

+ + Recent Prompts +

+
+ {recentPrompts.slice(0, 3).map((recent, index) => ( + + ))} +
+
+ )} + + + Browse Prompts on OpenPrompt + + +
+ ); + } + }; + + return ( +
+ {/* Header */} +
+
+
+
+ +
+
+

OpenPrompt

+

Open in AI

+
+
+ + {/* Tab buttons */} +
+ + + + +
+
+
+ + {/* Main Content */} +
+ {activeTab !== 'main' && ( + + )} + {renderTabContent()} +
+ + {/* Footer */} +
+

+ OpenPrompt Extension v1.1.0 +

+
+
+ ); +} + +export default App; diff --git a/openprompt-extension/src/popup/index.css b/openprompt-extension/src/popup/index.css new file mode 100644 index 0000000000000000000000000000000000000000..c5dc3ca25fee34fa574cdd9712d647e614b2a029 --- /dev/null +++ b/openprompt-extension/src/popup/index.css @@ -0,0 +1,34 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + width: 360px; + min-height: 480px; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f0f23 100%); + color: #fff; +} + +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.05); +} + +::-webkit-scrollbar-thumb { + background: rgba(168, 85, 247, 0.4); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(168, 85, 247, 0.6); +} diff --git a/openprompt-extension/src/popup/main.tsx b/openprompt-extension/src/popup/main.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2339d59cf67910c2bd93c28509f754e71476374e --- /dev/null +++ b/openprompt-extension/src/popup/main.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import './index.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + +); diff --git a/openprompt-extension/tailwind.config.js b/openprompt-extension/tailwind.config.js new file mode 100644 index 0000000000000000000000000000000000000000..19f82f22cd21c3675ced6dd12d37dca38190d0bb --- /dev/null +++ b/openprompt-extension/tailwind.config.js @@ -0,0 +1,26 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./popup.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: { + colors: { + primary: { + 50: '#faf5ff', + 100: '#f3e8ff', + 200: '#e9d5ff', + 300: '#d8b4fe', + 400: '#c084fc', + 500: '#a855f7', + 600: '#9333ea', + 700: '#7c3aed', + 800: '#6b21a8', + 900: '#581c87', + }, + }, + }, + }, + plugins: [], +} diff --git a/openprompt-extension/tsconfig.json b/openprompt-extension/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..1bad0bad982218563deacb1e4f53f7465b431b8c --- /dev/null +++ b/openprompt-extension/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "types": ["chrome"], + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/openprompt-extension/vite.config.ts b/openprompt-extension/vite.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb440a9961c75094d5175537aed6ef3e904f2abc --- /dev/null +++ b/openprompt-extension/vite.config.ts @@ -0,0 +1,63 @@ +import { defineConfig, build } from 'vite'; +import react from '@vitejs/plugin-react'; +import { resolve } from 'path'; + +// Custom plugin to build content scripts as IIFE after main build +function buildContentScriptsPlugin() { + return { + name: 'build-content-scripts', + async closeBundle() { + const contentScripts = [ + 'chatgpt', + 'claude', + 'gemini', + 'perplexity', + 'mistral', + 'copilot', + 'openprompt-site', + ]; + + for (const script of contentScripts) { + await build({ + configFile: false, + build: { + outDir: 'dist/content-scripts', + emptyOutDir: false, + lib: { + entry: resolve(__dirname, `src/content-scripts/${script}.ts`), + name: script, + fileName: () => `${script}.js`, + formats: ['iife'], + }, + rollupOptions: { + output: { + extend: true, + }, + }, + }, + }); + } + }, + }; +} + +export default defineConfig({ + plugins: [react(), buildContentScriptsPlugin()], + build: { + outDir: 'dist', + rollupOptions: { + input: { + popup: resolve(__dirname, 'popup.html'), + background: resolve(__dirname, 'src/background/index.ts'), + }, + output: { + entryFileNames: '[name].js', + assetFileNames: 'assets/[name].[ext]', + format: 'es', + }, + }, + emptyOutDir: true, + sourcemap: process.env.NODE_ENV === 'development', + }, + publicDir: 'public', +}); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..a377fdbb5588316dfc1450db0e07abf6726cb1e0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,15639 @@ +{ + "name": "openprompt", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openprompt", + "version": "0.1.0", + "hasInstallScript": true, + "dependencies": { + "@ai-sdk/anthropic": "^2.0.54", + "@ai-sdk/google": "^2.0.45", + "@ai-sdk/openai": "^2.0.80", + "@ai-sdk/react": "^2.0.109", + "@hookform/resolvers": "^5.2.2", + "@neondatabase/serverless": "^1.0.2", + "@prisma/adapter-neon": "^7.1.0", + "@prisma/adapter-pg": "^7.1.0", + "@prisma/client": "^7.1.0", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.8", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.4.2", + "@stackframe/stack": "^2.8.56", + "@stackframe/stack-shared": "^2.8.56", + "@stripe/stripe-js": "^9.4.0", + "@studio-freight/lenis": "^1.0.42", + "@types/three": "^0.182.0", + "@upstash/redis": "^1.35.8", + "ai": "^5.0.108", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "framer-motion": "^12.23.26", + "lucide-react": "^0.559.0", + "nanoid": "^5.1.6", + "next": "16.0.8", + "next-themes": "^0.4.6", + "pg": "^8.16.3", + "prisma": "^7.1.0", + "qrcode.react": "^4.2.0", + "radix-ui": "^1.4.3", + "react": "19.2.1", + "react-dom": "19.2.1", + "react-hook-form": "^7.68.0", + "react-icons": "^5.5.0", + "react-markdown": "^10.1.0", + "recharts": "^3.5.1", + "stripe": "^22.1.0", + "tailwind-merge": "^3.4.0", + "three": "^0.182.0", + "zod": "^4.1.13", + "zustand": "^5.0.9" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.0.8", + "sharp": "^0.34.5", + "tailwindcss": "^4", + "tw-animate-css": "^1.4.0", + "typescript": "^5" + } + }, + "node_modules/@ai-sdk/anthropic": { + "version": "2.0.56", + "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-2.0.56.tgz", + "integrity": "sha512-XHJKu0Yvfu9SPzRfsAFESa+9T7f2YJY6TxykKMfRsAwpeWAiX/Gbx5J5uM15AzYC3Rw8tVP3oH+j7jEivENirQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.19" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/gateway": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.23.tgz", + "integrity": "sha512-qmX7afPRszUqG5hryHF3UN8ITPIRSGmDW6VYCmByzjoUkgm3MekzSx2hMV1wr0P+llDeuXb378SjqUfpvWJulg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.19", + "@vercel/oidc": "3.0.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/gateway/node_modules/@vercel/oidc": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.5.tgz", + "integrity": "sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@ai-sdk/google": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-2.0.51.tgz", + "integrity": "sha512-5VMHdZTP4th00hthmh98jP+BZmxiTRMB9R2qh/AuF6OkQeiJikqxZg3hrWDfYrCmQ12wDjy6CbIypnhlwZiYrg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.19" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai": { + "version": "2.0.88", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-2.0.88.tgz", + "integrity": "sha512-LlOf83haeZIiRUH1Zw1oEmqUfw5y54227CvndFoBpIkMJwQDGAB3VARUeOJ6iwAWDJjXSz06GdnEnhRU67Yatw==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.19" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "3.0.19", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.19.tgz", + "integrity": "sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/react": { + "version": "2.0.118", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-2.0.118.tgz", + "integrity": "sha512-K/5VVEGTIu9SWrdQ0s/11OldFU8IjprDzeE6TaC2fOcQWhG7dGVGl9H8Z32QBHzdfJyMhFUxEyFKSOgA2j9+VQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider-utils": "3.0.19", + "ai": "5.0.116", + "swr": "^2.2.5", + "throttleit": "2.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1", + "zod": "^3.25.76 || ^4.1.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-kms": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.958.0.tgz", + "integrity": "sha512-RuthVYRE7gEmQVpO6s2t559qROuSIst4slC/+7/GZOBbcOvoC2byTaiLdEhFidZkeb74PGuS62BIW6w2AYWcCg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.957.0", + "@aws-sdk/credential-provider-node": "3.958.0", + "@aws-sdk/middleware-host-header": "3.957.0", + "@aws-sdk/middleware-logger": "3.957.0", + "@aws-sdk/middleware-recursion-detection": "3.957.0", + "@aws-sdk/middleware-user-agent": "3.957.0", + "@aws-sdk/region-config-resolver": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@aws-sdk/util-endpoints": "3.957.0", + "@aws-sdk/util-user-agent-browser": "3.957.0", + "@aws-sdk/util-user-agent-node": "3.957.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.16", + "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.958.0.tgz", + "integrity": "sha512-6qNCIeaMzKzfqasy2nNRuYnMuaMebCcCPP4J2CVGkA8QYMbIVKPlkn9bpB20Vxe6H/r3jtCCLQaOJjVTx/6dXg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.957.0", + "@aws-sdk/middleware-host-header": "3.957.0", + "@aws-sdk/middleware-logger": "3.957.0", + "@aws-sdk/middleware-recursion-detection": "3.957.0", + "@aws-sdk/middleware-user-agent": "3.957.0", + "@aws-sdk/region-config-resolver": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@aws-sdk/util-endpoints": "3.957.0", + "@aws-sdk/util-user-agent-browser": "3.957.0", + "@aws-sdk/util-user-agent-node": "3.957.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.16", + "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.957.0.tgz", + "integrity": "sha512-DrZgDnF1lQZv75a52nFWs6MExihJF2GZB6ETZRqr6jMwhrk2kbJPUtvgbifwcL7AYmVqHQDJBrR/MqkwwFCpiw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.957.0", + "@aws-sdk/xml-builder": "3.957.0", + "@smithy/core": "^3.20.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/signature-v4": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.957.0.tgz", + "integrity": "sha512-475mkhGaWCr+Z52fOOVb/q2VHuNvqEDixlYIkeaO6xJ6t9qR0wpLt4hOQaR6zR1wfZV0SlE7d8RErdYq/PByog==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.957.0.tgz", + "integrity": "sha512-8dS55QHRxXgJlHkEYaCGZIhieCs9NU1HU1BcqQ4RfUdSsfRdxxktqUKgCnBnOOn0oD3PPA8cQOCAVgIyRb3Rfw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/util-stream": "^4.5.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.958.0.tgz", + "integrity": "sha512-u7twvZa1/6GWmPBZs6DbjlegCoNzNjBsMS/6fvh5quByYrcJr/uLd8YEr7S3UIq4kR/gSnHqcae7y2nL2bqZdg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/credential-provider-env": "3.957.0", + "@aws-sdk/credential-provider-http": "3.957.0", + "@aws-sdk/credential-provider-login": "3.958.0", + "@aws-sdk/credential-provider-process": "3.957.0", + "@aws-sdk/credential-provider-sso": "3.958.0", + "@aws-sdk/credential-provider-web-identity": "3.958.0", + "@aws-sdk/nested-clients": "3.958.0", + "@aws-sdk/types": "3.957.0", + "@smithy/credential-provider-imds": "^4.2.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.958.0.tgz", + "integrity": "sha512-sDwtDnBSszUIbzbOORGh5gmXGl9aK25+BHb4gb1aVlqB+nNL2+IUEJA62+CE55lXSH8qXF90paivjK8tOHTwPA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/nested-clients": "3.958.0", + "@aws-sdk/types": "3.957.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.958.0.tgz", + "integrity": "sha512-vdoZbNG2dt66I7EpN3fKCzi6fp9xjIiwEA/vVVgqO4wXCGw8rKPIdDUus4e13VvTr330uQs2W0UNg/7AgtquEQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.957.0", + "@aws-sdk/credential-provider-http": "3.957.0", + "@aws-sdk/credential-provider-ini": "3.958.0", + "@aws-sdk/credential-provider-process": "3.957.0", + "@aws-sdk/credential-provider-sso": "3.958.0", + "@aws-sdk/credential-provider-web-identity": "3.958.0", + "@aws-sdk/types": "3.957.0", + "@smithy/credential-provider-imds": "^4.2.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.957.0.tgz", + "integrity": "sha512-/KIz9kadwbeLy6SKvT79W81Y+hb/8LMDyeloA2zhouE28hmne+hLn0wNCQXAAupFFlYOAtZR2NTBs7HBAReJlg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.958.0.tgz", + "integrity": "sha512-CBYHJ5ufp8HC4q+o7IJejCUctJXWaksgpmoFpXerbjAso7/Fg7LLUu9inXVOxlHKLlvYekDXjIUBXDJS2WYdgg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.958.0", + "@aws-sdk/core": "3.957.0", + "@aws-sdk/token-providers": "3.958.0", + "@aws-sdk/types": "3.957.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.958.0.tgz", + "integrity": "sha512-dgnvwjMq5Y66WozzUzxNkCFap+umHUtqMMKlr8z/vl9NYMLem/WUbWNpFFOVFWquXikc+ewtpBMR4KEDXfZ+KA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/nested-clients": "3.958.0", + "@aws-sdk/types": "3.957.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.957.0.tgz", + "integrity": "sha512-BBgKawVyfQZglEkNTuBBdC3azlyqNXsvvN4jPkWAiNYcY0x1BasaJFl+7u/HisfULstryweJq/dAvIZIxzlZaA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.957.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.957.0.tgz", + "integrity": "sha512-w1qfKrSKHf9b5a8O76yQ1t69u6NWuBjr5kBX+jRWFx/5mu6RLpqERXRpVJxfosbep7k3B+DSB5tZMZ82GKcJtQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.957.0", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.957.0.tgz", + "integrity": "sha512-D2H/WoxhAZNYX+IjkKTdOhOkWQaK0jjJrDBj56hKjU5c9ltQiaX/1PqJ4dfjHntEshJfu0w+E6XJ+/6A6ILBBA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.957.0", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.957.0.tgz", + "integrity": "sha512-50vcHu96XakQnIvlKJ1UoltrFODjsq2KvtTgHiPFteUS884lQnK5VC/8xd1Msz/1ONpLMzdCVproCQqhDTtMPQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@aws-sdk/util-endpoints": "3.957.0", + "@smithy/core": "^3.20.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.958.0.tgz", + "integrity": "sha512-/KuCcS8b5TpQXkYOrPLYytrgxBhv81+5pChkOlhegbeHttjM69pyUpQVJqyfDM/A7wPLnDrzCAnk4zaAOkY0Nw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.957.0", + "@aws-sdk/middleware-host-header": "3.957.0", + "@aws-sdk/middleware-logger": "3.957.0", + "@aws-sdk/middleware-recursion-detection": "3.957.0", + "@aws-sdk/middleware-user-agent": "3.957.0", + "@aws-sdk/region-config-resolver": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@aws-sdk/util-endpoints": "3.957.0", + "@aws-sdk/util-user-agent-browser": "3.957.0", + "@aws-sdk/util-user-agent-node": "3.957.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.16", + "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.957.0.tgz", + "integrity": "sha512-V8iY3blh8l2iaOqXWW88HbkY5jDoWjH56jonprG/cpyqqCnprvpMUZWPWYJoI8rHRf2bqzZeql1slxG6EnKI7A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.957.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.958.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.958.0.tgz", + "integrity": "sha512-UCj7lQXODduD1myNJQkV+LYcGYJ9iiMggR8ow8Hva1g3A/Na5imNXzz6O67k7DAee0TYpy+gkNw+SizC6min8Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.957.0", + "@aws-sdk/nested-clients": "3.958.0", + "@aws-sdk/types": "3.957.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.957.0.tgz", + "integrity": "sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.957.0.tgz", + "integrity": "sha512-xwF9K24mZSxcxKS3UKQFeX/dPYkEps9wF1b+MGON7EvnbcucrJGyQyK1v1xFPn1aqXkBTFi+SZaMRx5E5YCVFw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.957.0", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-endpoints": "^3.2.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.957.0.tgz", + "integrity": "sha512-nhmgKHnNV9K+i9daumaIz8JTLsIIML9PE/HUks5liyrjUzenjW/aHoc7WJ9/Td/gPZtayxFnXQSJRb/fDlBuJw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.957.0.tgz", + "integrity": "sha512-exueuwxef0lUJRnGaVkNSC674eAiWU07ORhxBnevFFZEKisln+09Qrtw823iyv5I1N8T+wKfh95xvtWQrNKNQw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.957.0", + "@smithy/types": "^4.11.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.957.0.tgz", + "integrity": "sha512-ycbYCwqXk4gJGp0Oxkzf2KBeeGBdTxz559D41NJP8FlzSej1Gh7Rk40Zo6AyTfsNWkrl/kVi1t937OIzC5t+9Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.957.0", + "@aws-sdk/types": "3.957.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.957.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.957.0.tgz", + "integrity": "sha512-Ai5iiQqS8kJ5PjzMhWcLKN0G2yasAkvpnPlq2EnqlIMdB48HsizElt62qcktdxp4neRMyGkFq4NzgmDbXnhRiA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.2.tgz", + "integrity": "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "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==", + "dev": true, + "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/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.5.0.tgz", + "integrity": "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "10.5.0", + "@chevrotain/types": "10.5.0", + "lodash": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.5.0.tgz", + "integrity": "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "10.5.0", + "lodash": "4.17.21" + } + }, + "node_modules/@chevrotain/types": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.5.0.tgz", + "integrity": "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.5.0.tgz", + "integrity": "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==", + "license": "Apache-2.0" + }, + "node_modules/@date-fns/tz": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", + "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==", + "license": "MIT" + }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "license": "Apache-2.0" + }, + "node_modules/@electric-sql/pglite": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.2.tgz", + "integrity": "sha512-zfWWa+V2ViDCY/cmUfRqeWY1yLto+EpxjXnZzenB1TyxsTiXaTWeZFIZw6mac52BsuQm0RjCnisjBtdBaXOI6w==", + "license": "Apache-2.0" + }, + "node_modules/@electric-sql/pglite-socket": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.0.6.tgz", + "integrity": "sha512-6RjmgzphIHIBA4NrMGJsjNWK4pu+bCWJlEWlwcxFTVY3WT86dFpKwbZaGWZV6C5Rd7sCk1Z0CI76QEfukLAUXw==", + "license": "Apache-2.0", + "bin": { + "pglite-server": "dist/scripts/server.js" + }, + "peerDependencies": { + "@electric-sql/pglite": "0.3.2" + } + }, + "node_modules/@electric-sql/pglite-tools": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.2.7.tgz", + "integrity": "sha512-9dAccClqxx4cZB+Ar9B+FZ5WgxDc/Xvl9DPrTWv+dYTf0YNubLzi4wHHRGRGhrJv15XwnyKcGOZAP1VXSneSUg==", + "license": "Apache-2.0", + "peerDependencies": { + "@electric-sql/pglite": "0.3.2" + } + }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@hono/node-server": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.6.tgz", + "integrity": "sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@hookform/resolvers": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz", + "integrity": "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/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, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mediapipe/tasks-vision": { + "version": "0.10.17", + "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", + "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", + "license": "Apache-2.0" + }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", + "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", + "license": "MIT", + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" + } + }, + "node_modules/@mrleebo/prisma-ast": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@mrleebo/prisma-ast/-/prisma-ast-0.12.1.tgz", + "integrity": "sha512-JwqeCQ1U3fvccttHZq7Tk0m/TMC6WcFAQZdukypW3AzlJYKYTGNVd1ANU2GuhKnv4UQuOFj3oAl0LLG/gxFN1w==", + "license": "MIT", + "dependencies": { + "chevrotain": "^10.5.0", + "lilconfig": "^2.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@neondatabase/serverless": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@neondatabase/serverless/-/serverless-1.0.2.tgz", + "integrity": "sha512-I5sbpSIAHiB+b6UttofhrN/UJXII+4tZPAq1qugzwCwLIL8EZLV7F/JyHUrEIiGgQpEXzpnjlJ+zwcEhheGvCw==", + "license": "MIT", + "dependencies": { + "@types/node": "^22.15.30", + "@types/pg": "^8.8.0" + }, + "engines": { + "node": ">=19.0.0" + } + }, + "node_modules/@neondatabase/serverless/node_modules/@types/node": { + "version": "22.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz", + "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@next/env": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.8.tgz", + "integrity": "sha512-xP4WrQZuj9MdmLJy3eWFHepo+R3vznsMSS8Dy3wdA7FKpjCiesQ6DxZvdGziQisj0tEtCgBKJzjcAc4yZOgLEQ==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.8.tgz", + "integrity": "sha512-1miV0qXDcLUaOdHridVPCh4i39ElRIAraseVIbb3BEqyZ5ol9sPyjTP/GNTPV5rBxqxjF6/vv5zQTVbhiNaLqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.8.tgz", + "integrity": "sha512-yjVMvTQN21ZHOclQnhSFbjBTEizle+1uo4NV6L4rtS9WO3nfjaeJYw+H91G+nEf3Ef43TaEZvY5mPWfB/De7tA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.8.tgz", + "integrity": "sha512-+zu2N3QQ0ZOb6RyqQKfcu/pn0UPGmg+mUDqpAAEviAcEVEYgDckemOpiMRsBP3IsEKpcoKuNzekDcPczEeEIzA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.8.tgz", + "integrity": "sha512-LConttk+BeD0e6RG0jGEP9GfvdaBVMYsLJ5aDDweKiJVVCu6sGvo+Ohz9nQhvj7EQDVVRJMCGhl19DmJwGr6bQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.8.tgz", + "integrity": "sha512-JaXFAlqn8fJV+GhhA9lpg6da/NCN/v9ub98n3HoayoUSPOVdoxEEt86iT58jXqQCs/R3dv5ZnxGkW8aF4obMrQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.8.tgz", + "integrity": "sha512-O7M9it6HyNhsJp3HNAsJoHk5BUsfj7hRshfptpGcVsPZ1u0KQ/oVy8oxF7tlwxA5tR43VUP0yRmAGm1us514ng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.8.tgz", + "integrity": "sha512-8+KClEC/GLI2dLYcrWwHu5JyC5cZYCFnccVIvmxpo6K+XQt4qzqM5L4coofNDZYkct/VCCyJWGbZZDsg6w6LFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.8.tgz", + "integrity": "sha512-rpQ/PgTEgH68SiXmhu/cJ2hk9aZ6YgFvspzQWe2I9HufY6g7V02DXRr/xrVqOaKm2lenBFPNQ+KAaeveywqV+A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.8.tgz", + "integrity": "sha512-jWpWjWcMQu2iZz4pEK2IktcfR+OA9+cCG8zenyLpcW8rN4rzjfOzH4yj/b1FiEAZHKS+5Vq8+bZyHi+2yqHbFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@oslojs/asn1": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/asn1/-/asn1-1.0.0.tgz", + "integrity": "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==", + "license": "MIT", + "dependencies": { + "@oslojs/binary": "1.0.0" + } + }, + "node_modules/@oslojs/binary": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/binary/-/binary-1.0.0.tgz", + "integrity": "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==", + "license": "MIT" + }, + "node_modules/@oslojs/crypto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/crypto/-/crypto-1.0.0.tgz", + "integrity": "sha512-dVz8TkkgYdr3tlwxHd7SCYGxoN7ynwHLA0nei/Aq9C+ERU0BK+U8+/3soEzBUxUNKYBf42351DyJUZ2REla50w==", + "license": "MIT", + "dependencies": { + "@oslojs/asn1": "1.0.0", + "@oslojs/binary": "1.0.0" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.0.0.tgz", + "integrity": "sha512-dyIB0SdZgMm5BhGwdSp8rMxEFIopLKxDG1vxIBaiogyom6ZqH2aXPb6DEC2WzOOWKdPSq1cxdNeRx2wAn1Z+ZQ==", + "license": "MIT" + }, + "node_modules/@oslojs/otp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/otp/-/otp-1.1.0.tgz", + "integrity": "sha512-tpdxlnCLcY6IZLLqH8kGD8PSvIVyev/+Gbglgvrk9e4YzgKO7+7FL8NWBofL7LZI6MgQ1HnNUuotRG6t1JJ0dg==", + "license": "MIT", + "dependencies": { + "@oslojs/binary": "1.0.0", + "@oslojs/crypto": "1.0.0", + "@oslojs/encoding": "1.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@prisma/adapter-neon": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/adapter-neon/-/adapter-neon-7.2.0.tgz", + "integrity": "sha512-XLTCQ0mDdaOqzBO99jyMOWBofJ5iqsvgWYB7lW+2ZEXvY6888tkeKfpo2VwdKhu1Cj/q4IqHd15eFQzPwbpjJQ==", + "license": "Apache-2.0", + "dependencies": { + "@neondatabase/serverless": ">0.6.0 <2", + "@prisma/driver-adapter-utils": "7.2.0", + "postgres-array": "3.0.4" + } + }, + "node_modules/@prisma/adapter-pg": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.2.0.tgz", + "integrity": "sha512-euIdQ13cRB2wZ3jPsnDnFhINquo1PYFPCg6yVL8b2rp3EdinQHsX9EDdCtRr489D5uhphcRk463OdQAFlsCr0w==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/driver-adapter-utils": "7.2.0", + "pg": "^8.16.3", + "postgres-array": "3.0.4" + } + }, + "node_modules/@prisma/client": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.2.0.tgz", + "integrity": "sha512-JdLF8lWZ+LjKGKpBqyAlenxd/kXjd1Abf/xK+6vUA7R7L2Suo6AFTHFRpPSdAKCan9wzdFApsUpSa/F6+t1AtA==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/client-runtime-utils": "7.2.0" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/client-runtime-utils": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.2.0.tgz", + "integrity": "sha512-dn7oB53v0tqkB0wBdMuTNFNPdEbfICEUe82Tn9FoKAhJCUkDH+fmyEp0ClciGh+9Hp2Tuu2K52kth2MTLstvmA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/config": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.2.0.tgz", + "integrity": "sha512-qmvSnfQ6l/srBW1S7RZGfjTQhc44Yl3ldvU6y3pgmuLM+83SBDs6UQVgMtQuMRe9J3gGqB0RF8wER6RlXEr6jQ==", + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.18.4", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.2.0.tgz", + "integrity": "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/dev": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.17.0.tgz", + "integrity": "sha512-6sGebe5jxX+FEsQTpjHLzvOGPn6ypFQprcs3jcuIWv1Xp/5v6P/rjfdvAwTkP2iF6pDx2tCd8vGLNWcsWzImTA==", + "license": "ISC", + "dependencies": { + "@electric-sql/pglite": "0.3.2", + "@electric-sql/pglite-socket": "0.0.6", + "@electric-sql/pglite-tools": "0.2.7", + "@hono/node-server": "1.19.6", + "@mrleebo/prisma-ast": "0.12.1", + "@prisma/get-platform": "6.8.2", + "@prisma/query-plan-executor": "6.18.0", + "foreground-child": "3.3.1", + "get-port-please": "3.1.2", + "hono": "4.10.6", + "http-status-codes": "2.3.0", + "pathe": "2.0.3", + "proper-lockfile": "4.1.2", + "remeda": "2.21.3", + "std-env": "3.9.0", + "valibot": "1.2.0", + "zeptomatch": "2.0.2" + } + }, + "node_modules/@prisma/driver-adapter-utils": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.2.0.tgz", + "integrity": "sha512-gzrUcbI9VmHS24Uf+0+7DNzdIw7keglJsD5m/MHxQOU68OhGVzlphQRobLiDMn8CHNA2XN8uugwKjudVtnfMVQ==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.2.0" + } + }, + "node_modules/@prisma/engines": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.2.0.tgz", + "integrity": "sha512-HUeOI/SvCDsHrR9QZn24cxxZcujOjcS3w1oW/XVhnSATAli5SRMOfp/WkG3TtT5rCxDA4xOnlJkW7xkho4nURA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.2.0", + "@prisma/engines-version": "7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3", + "@prisma/fetch-engine": "7.2.0", + "@prisma/get-platform": "7.2.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3.tgz", + "integrity": "sha512-KezsjCZDsbjNR7SzIiVlUsn9PnLePI7r5uxABlwL+xoerurZTfgQVbIjvjF2sVr3Uc0ZcsnREw3F84HvbggGdA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz", + "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.2.0" + } + }, + "node_modules/@prisma/fetch-engine": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.2.0.tgz", + "integrity": "sha512-Z5XZztJ8Ap+wovpjPD2lQKnB8nWFGNouCrglaNFjxIWAGWz0oeHXwUJRiclIoSSXN/ptcs9/behptSk8d0Yy6w==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.2.0", + "@prisma/engines-version": "7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3", + "@prisma/get-platform": "7.2.0" + } + }, + "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz", + "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.2.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.8.2.tgz", + "integrity": "sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.8.2" + } + }, + "node_modules/@prisma/get-platform/node_modules/@prisma/debug": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.8.2.tgz", + "integrity": "sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/query-plan-executor": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@prisma/query-plan-executor/-/query-plan-executor-6.18.0.tgz", + "integrity": "sha512-jZ8cfzFgL0jReE1R10gT8JLHtQxjWYLiQ//wHmVYZ2rVkFHoh0DT8IXsxcKcFlfKN7ak7k6j0XMNn2xVNyr5cA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/studio-core": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.9.0.tgz", + "integrity": "sha512-xA2zoR/ADu/NCSQuriBKTh6Ps4XjU0bErkEcgMfnSGh346K1VI7iWKnoq1l2DoxUqiddPHIEWwtxJ6xCHG6W7g==", + "license": "Apache-2.0", + "peerDependencies": { + "@types/react": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", + "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.8.tgz", + "integrity": "sha512-5nZrJTF7gH+e0nZS7/QxFz6tJV4VimhQb1avEgtsJxvvIp5JilL+c58HICsKzPxghdwaDt48hEfPM1au4zGy+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", + "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-icons": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", + "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "license": "MIT", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-one-time-password-field": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", + "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", + "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz", + "integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", + "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-toggle-group": "1.1.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@react-three/drei": { + "version": "10.7.7", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-10.7.7.tgz", + "integrity": "sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mediapipe/tasks-vision": "0.10.17", + "@monogrid/gainmap-js": "^3.0.6", + "@use-gesture/react": "^10.3.1", + "camera-controls": "^3.1.0", + "cross-env": "^7.0.3", + "detect-gpu": "^5.0.56", + "glsl-noise": "^0.0.0", + "hls.js": "^1.5.17", + "maath": "^0.10.8", + "meshline": "^3.3.1", + "stats-gl": "^2.2.8", + "stats.js": "^0.17.0", + "suspend-react": "^0.1.3", + "three-mesh-bvh": "^0.8.3", + "three-stdlib": "^2.35.6", + "troika-three-text": "^0.52.4", + "tunnel-rat": "^0.1.2", + "use-sync-external-store": "^1.4.0", + "utility-types": "^3.11.0", + "zustand": "^5.0.1" + }, + "peerDependencies": { + "@react-three/fiber": "^9.0.0", + "react": "^19", + "react-dom": "^19", + "three": ">=0.159" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.4.2.tgz", + "integrity": "sha512-H4B4+FDNHpvIb4FmphH4ubxOfX5bxmfOw0+3pkQwR9u9wFiyMS7wUDkNn0m4RqQuiLWeia9jfN1eBvtyAVGEog==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8", + "@types/react-reconciler": "^0.32.0", + "@types/webxr": "*", + "base64-js": "^1.5.1", + "buffer": "^6.0.3", + "its-fine": "^2.0.0", + "react-reconciler": "^0.31.0", + "react-use-measure": "^2.1.7", + "scheduler": "^0.25.0", + "suspend-react": "^0.1.3", + "use-sync-external-store": "^1.4.0", + "zustand": "^5.0.3" + }, + "peerDependencies": { + "expo": ">=43.0", + "expo-asset": ">=8.4", + "expo-file-system": ">=11.0", + "expo-gl": ">=11.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-native": ">=0.78", + "three": ">=0.156" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "expo-asset": { + "optional": true + }, + "expo-file-system": { + "optional": true + }, + "expo-gl": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.0.tgz", + "integrity": "sha512-dlzb07f5LDY+tzs+iLCSXV2yuhaYfezqyZQc+n6baLECWkOMEWxkECAOnXL0ba7lsA25fM9b2jtzpu/uxo1a7g==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@simplewebauthn/browser": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-11.0.0.tgz", + "integrity": "sha512-KEGCStrl08QC2I561BzxqGiwoknblP6O1YW7jApdXLPtIqZ+vgJYAv8ssLCdm1wD8HGAHd49CJLkUF8X70x/pg==", + "license": "MIT", + "dependencies": { + "@simplewebauthn/types": "^11.0.0" + } + }, + "node_modules/@simplewebauthn/types": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@simplewebauthn/types/-/types-11.0.0.tgz", + "integrity": "sha512-b2o0wC5u2rWts31dTgBkAtSNKGX0cvL6h8QedNsKmj8O4QoLFQFR3DBVBUlpyVEhYKA+mXGUaXbcOc4JdQ3HzA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, + "node_modules/@smithy/abort-controller": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.7.tgz", + "integrity": "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.5.tgz", + "integrity": "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.0.tgz", + "integrity": "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.2.8", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-stream": "^4.5.8", + "@smithy/util-utf8": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.7.tgz", + "integrity": "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.8.tgz", + "integrity": "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.7", + "@smithy/querystring-builder": "^4.2.7", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.7.tgz", + "integrity": "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.7.tgz", + "integrity": "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", + "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.7.tgz", + "integrity": "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.1.tgz", + "integrity": "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.20.0", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-middleware": "^4.2.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.4.17", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.17.tgz", + "integrity": "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/service-error-classification": "^4.2.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.8.tgz", + "integrity": "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.7.tgz", + "integrity": "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.7.tgz", + "integrity": "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.7.tgz", + "integrity": "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/querystring-builder": "^4.2.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.7.tgz", + "integrity": "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.7.tgz", + "integrity": "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.7.tgz", + "integrity": "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "@smithy/util-uri-escape": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.7.tgz", + "integrity": "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.7.tgz", + "integrity": "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.2.tgz", + "integrity": "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.7.tgz", + "integrity": "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-uri-escape": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.2.tgz", + "integrity": "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.20.0", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "@smithy/util-stream": "^4.5.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.11.0.tgz", + "integrity": "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.7.tgz", + "integrity": "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.2.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz", + "integrity": "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", + "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz", + "integrity": "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", + "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", + "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.16.tgz", + "integrity": "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.19.tgz", + "integrity": "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.4.5", + "@smithy/credential-provider-imds": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.7.tgz", + "integrity": "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", + "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.7.tgz", + "integrity": "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.7.tgz", + "integrity": "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^4.2.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.5.8", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.8.tgz", + "integrity": "sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", + "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", + "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", + "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@stackframe/stack": { + "version": "2.8.56", + "resolved": "https://registry.npmjs.org/@stackframe/stack/-/stack-2.8.56.tgz", + "integrity": "sha512-jHSpslKPPNtduLVOAdf7uT/1X4xoJdI7ATmSI5yo/VHTieuzBIzzj+2AYXK/uEVozRaYyceLgqJoX+9Is6ZjTQ==", + "dependencies": { + "@hookform/resolvers": "^3.3.4", + "@oslojs/otp": "^1.1.0", + "@simplewebauthn/browser": "^11.0.0", + "@stackframe/stack-sc": "2.8.56", + "@stackframe/stack-shared": "2.8.56", + "@stackframe/stack-ui": "2.8.56", + "@tanstack/react-table": "^8.20.5", + "browser-image-compression": "^2.0.2", + "color": "^4.2.3", + "cookie": "^0.6.0", + "jose": "^5.2.2", + "js-cookie": "^3.0.5", + "lucide-react": "^0.378.0", + "oauth4webapi": "^2.10.3", + "qrcode": "^1.5.4", + "react-easy-crop": "^5.4.1", + "react-hook-form": "^7.51.4", + "rimraf": "^5.0.5", + "tailwindcss-animate": "^1.0.7", + "tsx": "^4.7.2", + "yup": "^1.4.0" + }, + "peerDependencies": { + "@types/react": ">=18.3.0", + "@types/react-dom": ">=18.3.0", + "next": ">=14.1 || >=15.0.0-canary.0 || >=15.0.0-rc.0", + "react": ">=18.3.0", + "react-dom": ">=18.3.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@stackframe/stack-sc": { + "version": "2.8.56", + "resolved": "https://registry.npmjs.org/@stackframe/stack-sc/-/stack-sc-2.8.56.tgz", + "integrity": "sha512-2GizntFNIERG+rN2r6qv8U8xY/N5U5LRVHuFizR2oo83um8IVSzgGozPVWjQUBdeKuMjpx0IzKolmCZMkE1pYQ==", + "peerDependencies": { + "@types/react": ">=19.0.0", + "@types/react-dom": ">=19.0.0", + "next": ">=14.1 || >=15.0.0-rc.0", + "react": ">=19.0.0", + "react-dom": ">=19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@stackframe/stack-shared": { + "version": "2.8.56", + "resolved": "https://registry.npmjs.org/@stackframe/stack-shared/-/stack-shared-2.8.56.tgz", + "integrity": "sha512-fPb01gM0bUS6DuQ5J4zoTyrEEo/4/p3mA4Z9YaQFJ47AOmzD58Q7uL5OTTARJNsQLeWvbbWx/EkmcPzVk9qLnw==", + "dependencies": { + "@aws-sdk/client-kms": "^3.876.0", + "@opentelemetry/api": "^1.9.0", + "@simplewebauthn/browser": "^11.0.0", + "@vercel/functions": "^2.0.0", + "async-mutex": "^0.5.0", + "bcryptjs": "^3.0.2", + "crc": "^4.3.2", + "elliptic": "^6.5.7", + "esbuild-wasm": "^0.20.2", + "ip-regex": "^5.0.0", + "jose": "^5.2.2", + "oauth4webapi": "^2.10.3", + "semver": "^7.6.3", + "uuid": "^9.0.1" + }, + "peerDependencies": { + "@types/react": ">=19.0.0", + "@types/react-dom": ">=19.0.0", + "react": ">=19.0.0", + "react-dom": ">=19.0.0", + "yup": "^1.4.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react": { + "optional": true + }, + "yup": { + "optional": true + } + } + }, + "node_modules/@stackframe/stack-ui": { + "version": "2.8.56", + "resolved": "https://registry.npmjs.org/@stackframe/stack-ui/-/stack-ui-2.8.56.tgz", + "integrity": "sha512-seH/FAQMENyPJykpkhv1AjtjL70ju5BcMlGkhePGGvujDFhN7pzVPlGGmShkd23umKq6ZxlJFa8ynCSS3RAh3w==", + "dependencies": { + "@radix-ui/react-accordion": "^1.2.1", + "@radix-ui/react-alert-dialog": "^1.1.2", + "@radix-ui/react-aspect-ratio": "^1.1.0", + "@radix-ui/react-avatar": "^1.1.1", + "@radix-ui/react-checkbox": "^1.1.2", + "@radix-ui/react-collapsible": "^1.1.1", + "@radix-ui/react-context": "^1.1.1", + "@radix-ui/react-context-menu": "^2.2.2", + "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-dropdown-menu": "^2.1.2", + "@radix-ui/react-hover-card": "^1.1.2", + "@radix-ui/react-icons": "^1.3.1", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-menubar": "^1.1.2", + "@radix-ui/react-navigation-menu": "^1.2.1", + "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-progress": "^1.1.0", + "@radix-ui/react-radio-group": "^1.2.1", + "@radix-ui/react-scroll-area": "^1.2.0", + "@radix-ui/react-select": "^2.1.2", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slider": "^1.2.1", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.1", + "@radix-ui/react-tabs": "^1.1.1", + "@radix-ui/react-toast": "^1.2.2", + "@radix-ui/react-toggle": "^1.1.0", + "@radix-ui/react-toggle-group": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.3", + "@stackframe/stack-shared": "2.8.56", + "@tanstack/react-table": "^8.20.5", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.4", + "date-fns": "^3.6.0", + "export-to-csv": "^1.4.0", + "input-otp": "^1.4.1", + "lucide-react": "^0.508.0", + "react-day-picker": "^9.6.7", + "react-hook-form": "^7.53.1", + "react-resizable-panels": "^2.1.6", + "tailwind-merge": "^2.5.4" + }, + "peerDependencies": { + "@types/react": ">=19.0.0", + "@types/react-dom": ">=19.0.0", + "react": ">=19.0.0", + "react-dom": ">=19.0.0", + "yup": "^1.4.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "yup": { + "optional": true + } + } + }, + "node_modules/@stackframe/stack-ui/node_modules/lucide-react": { + "version": "0.508.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.508.0.tgz", + "integrity": "sha512-gcP16PnexqtOFrTtv98kVsGzTfnbPekzZiQfByi2S89xfk7E/4uKE1USZqccIp58v42LqkO7MuwpCqshwSrJCg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@stackframe/stack-ui/node_modules/tailwind-merge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/@stackframe/stack/node_modules/@hookform/resolvers": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz", + "integrity": "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, + "node_modules/@stackframe/stack/node_modules/lucide-react": { + "version": "0.378.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.378.0.tgz", + "integrity": "sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@stripe/stripe-js": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-9.4.0.tgz", + "integrity": "sha512-zXG86DnoLU5nH2U18tX5ApTE3IAm+txoiPm4YFyEtRS0K5y7ZDH9M8e1Le/cZyI6wvW3BkJn2daZe2FqZOrSSg==", + "license": "MIT", + "engines": { + "node": ">=12.16" + } + }, + "node_modules/@studio-freight/lenis": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/@studio-freight/lenis/-/lenis-1.0.42.tgz", + "integrity": "sha512-HJAGf2DeM+BTvKzHv752z6Z7zy6bA643nZM7W88Ft9tnw2GsJSp6iJ+3cekjyMIWH+cloL2U9X82dKXgdU8kPg==", + "deprecated": "The '@studio-freight/lenis' package has been renamed to 'lenis'. Please update your dependencies: npm install lenis and visit the documentation: https://www.npmjs.com/package/lenis", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz", + "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "postcss": "^8.4.41", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/draco3d": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", + "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, + "node_modules/@types/pg": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", + "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-reconciler": { + "version": "0.32.3", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.32.3.tgz", + "integrity": "sha512-cMi5ZrLG7UtbL7LTK6hq9w/EZIRk4Mf1Z5qHoI+qBh7/WkYkFXQ7gOto2yfUvPzF5ERMAhaXS5eTQ2SAnHjLzA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.182.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.182.0.tgz", + "integrity": "sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.22.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.50.1.tgz", + "integrity": "sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.50.1", + "@typescript-eslint/type-utils": "8.50.1", + "@typescript-eslint/utils": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.50.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.50.1.tgz", + "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.50.1", + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.50.1.tgz", + "integrity": "sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.50.1", + "@typescript-eslint/types": "^8.50.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.50.1.tgz", + "integrity": "sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.50.1.tgz", + "integrity": "sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.50.1.tgz", + "integrity": "sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1", + "@typescript-eslint/utils": "8.50.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.50.1.tgz", + "integrity": "sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.50.1.tgz", + "integrity": "sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.50.1", + "@typescript-eslint/tsconfig-utils": "8.50.1", + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.50.1.tgz", + "integrity": "sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.50.1", + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.50.1.tgz", + "integrity": "sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@upstash/redis": { + "version": "1.35.8", + "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.35.8.tgz", + "integrity": "sha512-QqLpVCD9PCPE6hlRzOkz864nfijSdazxtyJLIy9ZeTh6kU2nBIKKfjT5HMHjIRD4BCm6TK1dbUT9pxhFjcvpng==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, + "node_modules/@vercel/functions": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/@vercel/functions/-/functions-2.2.13.tgz", + "integrity": "sha512-14ArBSIIcOBx9nrEgaJb4Bw+en1gl6eSoJWh8qjifLl5G3E4dRXCFOT8HP+w66vb9Wqyd1lAQBrmRhRwOj9X9A==", + "license": "Apache-2.0", + "dependencies": { + "@vercel/oidc": "2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-web-identity": "*" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-provider-web-identity": { + "optional": true + } + } + }, + "node_modules/@vercel/oidc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-2.0.2.tgz", + "integrity": "sha512-59PBFx3T+k5hLTEWa3ggiMpGRz1OVvl9eN8SUai+A43IsqiOuAe7qPBf+cray/Fj6mkgnxm/D7IAtjc8zSHi7g==", + "license": "Apache-2.0", + "dependencies": { + "@types/ms": "2.1.0", + "ms": "2.1.3" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@webgpu/types": { + "version": "0.1.68", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.68.tgz", + "integrity": "sha512-3ab1B59Ojb6RwjOspYLsTpCzbNB3ZaamIAxBMmvnNkiDoLTZUOBXZ9p5nAYVEkQlDdf6qAZWi1pqj9+ypiqznA==", + "license": "BSD-3-Clause" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ai": { + "version": "5.0.116", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.116.tgz", + "integrity": "sha512-+2hYJ80/NcDWuv9K2/MLP3cTCFgwWHmHlS1tOpFUKKcmLbErAAlE/S2knsKboc3PNAu8pQkDr2N3K/Vle7ENgQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/gateway": "2.0.23", + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.19", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axe-core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", + "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/bowser": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", + "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/browser-image-compression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/browser-image-compression/-/browser-image-compression-2.0.2.tgz", + "integrity": "sha512-pBLlQyUf6yB8SmmngrcOw3EoS4RpQ1BcylI3T9Yqn7+4nrQTXJD4sJDe5ODnJdrvNMaio5OicFo75rDyJD2Ucw==", + "license": "MIT", + "dependencies": { + "uzip": "0.20201231.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camera-controls": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.2.tgz", + "integrity": "sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==", + "license": "MIT", + "engines": { + "node": ">=22.0.0", + "npm": ">=10.5.1" + }, + "peerDependencies": { + "three": ">=0.126.1" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001761", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz", + "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.5.0.tgz", + "integrity": "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "10.5.0", + "@chevrotain/gast": "10.5.0", + "@chevrotain/types": "10.5.0", + "@chevrotain/utils": "10.5.0", + "lodash": "4.17.21", + "regexp-to-ast": "0.5.0" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "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/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/crc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/crc/-/crc-4.3.2.tgz", + "integrity": "sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "buffer": ">=6.0.3" + }, + "peerDependenciesMeta": { + "buffer": { + "optional": true + } + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/date-fns-jalali": { + "version": "4.1.0-0", + "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz", + "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-gpu": { + "version": "5.0.70", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz", + "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==", + "license": "MIT", + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, + "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==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/draco3d": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", + "license": "Apache-2.0" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", + "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", + "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.1", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-toolkit": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.43.0.tgz", + "integrity": "sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.2.tgz", + "integrity": "sha512-7o6nmsEqlcXJXMNqnx5K+M4w4OPx7yTFXQHcJyeP3SkXb8p2T8N9E1ayK4vd/qDBepH6fuPoZwiFvZm8x5qv+w==", + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.8.tgz", + "integrity": "sha512-8J5cOAboXIV3f8OD6BOyj7Fik6n/as7J4MboiUSExWruf/lCu1OPR3ZVSdnta6WhzebrmAATEmNSBZsLWA6kbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "16.0.8", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "16.4.0", + "typescript-eslint": "^8.46.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/export-to-csv": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/export-to-csv/-/export-to-csv-1.4.0.tgz", + "integrity": "sha512-6CX17Cu+rC2Fi2CyZ4CkgVG3hLl6BFsdAxfXiZkmDFIDY4mRx2y2spdeH6dqPHI9rP+AsHEfGeKz84Uuw7+Pmg==", + "license": "MIT", + "engines": { + "node": "^v12.20.0 || >=v14.13.0" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-xml-parser": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", + "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/framer-motion": { + "version": "12.23.26", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.26.tgz", + "integrity": "sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.23.23", + "motion-utils": "^12.23.6", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-port-please": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.1.2.tgz", + "integrity": "sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==", + "license": "MIT" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==", + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/grammex": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.12.tgz", + "integrity": "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==", + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hls.js": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz", + "integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==", + "license": "Apache-2.0" + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hono": { + "version": "4.10.6", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.10.6.tgz", + "integrity": "sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/http-status-codes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", + "license": "MIT" + }, + "node_modules/iconv-lite": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/input-otp": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz", + "integrity": "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/ip-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-5.0.0.tgz", + "integrity": "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT" + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/its-fine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz", + "integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==", + "license": "MIT", + "dependencies": { + "@types/react-reconciler": "^0.28.9" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/its-fine/node_modules/@types/react-reconciler": { + "version": "0.28.9", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", + "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "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.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "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.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "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.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "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.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "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.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "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.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "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.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lru.min": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.3.tgz", + "integrity": "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/lucide-react": { + "version": "0.559.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.559.0.tgz", + "integrity": "sha512-3ymrkBPXWk3U2bwUDg6TdA6hP5iGDMgPEAMLhchEgTQmA+g0Zk24tOtKtXMx35w1PizTmsBC3RhP88QYm+7mHQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/maath": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz", + "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", + "license": "MIT", + "peerDependencies": { + "@types/three": ">=0.134.0", + "three": ">=0.134.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/meshline": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz", + "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.137" + } + }, + "node_modules/meshoptimizer": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.22.0.tgz", + "integrity": "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==", + "license": "MIT" + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/motion-dom": { + "version": "12.23.23", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", + "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mysql2": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", + "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.0", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", + "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", + "license": "MIT", + "dependencies": { + "lru.min": "^1.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/next/-/next-16.0.8.tgz", + "integrity": "sha512-LmcZzG04JuzNXi48s5P+TnJBsTGPJunViNKV/iE4uM6kstjTQsQhvsAv+xF6MJxU2Pr26tl15eVbp0jQnsv6/g==", + "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details.", + "license": "MIT", + "dependencies": { + "@next/env": "16.0.8", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.0.8", + "@next/swc-darwin-x64": "16.0.8", + "@next/swc-linux-arm64-gnu": "16.0.8", + "@next/swc-linux-arm64-musl": "16.0.8", + "@next/swc-linux-x64-gnu": "16.0.8", + "@next/swc-linux-x64-musl": "16.0.8", + "@next/swc-win32-arm64-msvc": "16.0.8", + "@next/swc-win32-x64-msvc": "16.0.8", + "sharp": "^0.34.4" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/next/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==", + "license": "BSD-3-Clause" + }, + "node_modules/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/oauth4webapi": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.17.0.tgz", + "integrity": "sha512-lbC0Z7uzAFNFyzEYRIC+pkSVvDHJTbEW+dYlSBAlCYDe6RxUkJ26bClhk8ocBZip1wfI9uKTe0fm4Ib4RHn6uQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/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==", + "license": "ISC" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.16.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.7" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-types/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/postgres": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", + "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", + "license": "Unlicense", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + }, + "node_modules/postgres-array": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", + "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", + "license": "ISC" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prisma": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.2.0.tgz", + "integrity": "sha512-jSdHWgWOgFF24+nRyyNRVBIgGDQEsMEF8KPHvhBBg3jWyR9fUAK0Nq9ThUmiGlNgq2FA7vSk/ZoCvefod+a8qg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "7.2.0", + "@prisma/dev": "0.17.0", + "@prisma/engines": "7.2.0", + "@prisma/studio-core": "0.9.0", + "mysql2": "3.15.3", + "postgres": "3.4.7" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0" + }, + "peerDependencies": { + "better-sqlite3": ">=9.0.0", + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/promise-worker-transferable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", + "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", + "license": "Apache-2.0", + "dependencies": { + "is-promise": "^2.1.0", + "lie": "^3.0.2" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "license": "MIT" + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode.react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz", + "integrity": "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/radix-ui": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", + "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-accessible-icon": "1.1.7", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-aspect-ratio": "1.1.7", + "@radix-ui/react-avatar": "1.1.10", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-form": "0.1.8", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-one-time-password-field": "0.1.8", + "@radix-ui/react-password-toggle-field": "0.1.3", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-progress": "1.1.7", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-toolbar": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-escape-keydown": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", + "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/react": { + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", + "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-day-picker": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.13.0.tgz", + "integrity": "sha512-euzj5Hlq+lOHqI53NiuNhCP8HWgsPf/bBAVijR50hNaY1XwjKjShAnIe8jm8RD2W9IJUvihDIZ+KrmqfFzNhFQ==", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "date-fns": "^4.1.0", + "date-fns-jalali": "^4.1.0-0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-day-picker/node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/react-dom": { + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz", + "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.1" + } + }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/react-easy-crop": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-5.5.6.tgz", + "integrity": "sha512-Jw3/ozs8uXj3NpL511Suc4AHY+mLRO23rUgipXvNYKqezcFSYHxe4QXibBymkOoY6oOtLVMPO2HNPRHYvMPyTw==", + "license": "MIT", + "dependencies": { + "normalize-wheel": "^1.0.1", + "tslib": "^2.0.1" + }, + "peerDependencies": { + "react": ">=16.4.0", + "react-dom": ">=16.4.0" + } + }, + "node_modules/react-hook-form": { + "version": "7.69.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.69.0.tgz", + "integrity": "sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", + "integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==", + "license": "MIT", + "peer": true + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-reconciler": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.31.0.tgz", + "integrity": "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.25.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-resizable-panels": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.1.9.tgz", + "integrity": "sha512-z77+X08YDIrgAes4jl8xhnUu1LNIRp4+E7cv4xHmLOxxUPO/ML7PSrE813b90vj7xvQ1lcf7g2uA9GeMZonjhQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-use-measure": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz", + "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/recharts": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.6.0.tgz", + "integrity": "sha512-L5bjxvQRAe26RlToBAziKUB7whaGKEwD3znoM6fz3DrTowCIC/FnJYnuq1GEzB8Zv2kdTfaxQfi5GoH0tBinyg==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "1.x.x || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remeda": { + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.21.3.tgz", + "integrity": "sha512-XXrZdLA10oEOQhLLzEJEiFFSKi21REGAkHdImIb4rt/XXy8ORGXh5HCcpUOsElfPNDb+X6TA/+wkh+p2KffYmg==", + "license": "MIT", + "dependencies": { + "type-fest": "^4.39.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stats-gl": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz", + "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==", + "license": "MIT", + "dependencies": { + "@types/three": "*", + "three": "^0.170.0" + }, + "peerDependencies": { + "@types/three": "*", + "three": "*" + } + }, + "node_modules/stats-gl/node_modules/three": { + "version": "0.170.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz", + "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", + "license": "MIT" + }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stripe": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-22.1.0.tgz", + "integrity": "sha512-w/xHyJGxXWnLPbNHG13sz/fae0MrFGC80Oz7YbICQymbfpqfEcsoG+6yG+9BWb81PWc4rrkeSO4wmTcmefmbLw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/strnum": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", + "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/suspend-react": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", + "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=17.0" + } + }, + "node_modules/swr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.8.tgz", + "integrity": "sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/tailwind-merge": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", + "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "license": "MIT" + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/three": { + "version": "0.182.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz", + "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==", + "license": "MIT" + }, + "node_modules/three-mesh-bvh": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz", + "integrity": "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==", + "license": "MIT", + "peerDependencies": { + "three": ">= 0.159.0" + } + }, + "node_modules/three-stdlib": { + "version": "2.36.1", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.36.1.tgz", + "integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==", + "license": "MIT", + "dependencies": { + "@types/draco3d": "^1.4.0", + "@types/offscreencanvas": "^2019.6.4", + "@types/webxr": "^0.5.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "potpack": "^1.0.1" + }, + "peerDependencies": { + "three": ">=0.128.0" + } + }, + "node_modules/three-stdlib/node_modules/fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", + "license": "MIT" + }, + "node_modules/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/troika-three-text": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz", + "integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", + "license": "MIT", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.52.4", + "troika-worker-utils": "^0.52.0", + "webgl-sdf-generator": "1.1.1" + }, + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-three-utils": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz", + "integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-worker-utils": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", + "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", + "license": "MIT" + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tunnel-rat": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", + "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", + "license": "MIT", + "dependencies": { + "zustand": "^4.3.2" + } + }, + "node_modules/tunnel-rat/node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.50.1.tgz", + "integrity": "sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.50.1", + "@typescript-eslint/parser": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1", + "@typescript-eslint/utils": "8.50.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uzip": { + "version": "0.20201231.0", + "resolved": "https://registry.npmjs.org/uzip/-/uzip-0.20201231.0.tgz", + "integrity": "sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng==", + "license": "MIT" + }, + "node_modules/valibot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz", + "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, + "node_modules/webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yup": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.7.1.tgz", + "integrity": "sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==", + "license": "MIT", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zeptomatch": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.0.2.tgz", + "integrity": "sha512-H33jtSKf8Ijtb5BW6wua3G5DhnFjbFML36eFu+VdOoVY4HD9e7ggjqdM6639B+L87rjnR6Y+XeRzBXZdy52B/g==", + "license": "MIT", + "dependencies": { + "grammex": "^3.1.10" + } + }, + "node_modules/zod": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz", + "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/zustand": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.9.tgz", + "integrity": "sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3b14872b3e44d8f56ca809662ef15d362f9b5bb5 --- /dev/null +++ b/package.json @@ -0,0 +1,81 @@ +{ + "name": "openprompt", + "version": "0.1.0", + "private": true, + "author": { + "name": "Anky9972", + "url": "https://github.com/Anky9972" + }, + "repository": { + "type": "git", + "url": "https://github.com/Anky9972/open-prompt.git" + }, + "scripts": { + "dev": "next dev", + "build": "prisma generate && next build", + "postinstall": "prisma generate", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "@ai-sdk/anthropic": "^2.0.54", + "@ai-sdk/google": "^2.0.45", + "@ai-sdk/openai": "^2.0.80", + "@ai-sdk/react": "^2.0.109", + "@hookform/resolvers": "^5.2.2", + "@neondatabase/serverless": "^1.0.2", + "@prisma/adapter-neon": "^7.1.0", + "@prisma/adapter-pg": "^7.1.0", + "@prisma/client": "^7.1.0", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.8", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.4.2", + "@stackframe/stack": "^2.8.56", + "@stackframe/stack-shared": "^2.8.56", + "@stripe/stripe-js": "^9.4.0", + "@studio-freight/lenis": "^1.0.42", + "@types/three": "^0.182.0", + "@upstash/redis": "^1.35.8", + "ai": "^5.0.108", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "framer-motion": "^12.23.26", + "lucide-react": "^0.559.0", + "nanoid": "^5.1.6", + "next": "16.0.8", + "next-themes": "^0.4.6", + "pg": "^8.16.3", + "prisma": "^7.1.0", + "qrcode.react": "^4.2.0", + "radix-ui": "^1.4.3", + "react": "19.2.1", + "react-dom": "19.2.1", + "react-hook-form": "^7.68.0", + "react-icons": "^5.5.0", + "react-markdown": "^10.1.0", + "recharts": "^3.5.1", + "stripe": "^22.1.0", + "tailwind-merge": "^3.4.0", + "three": "^0.182.0", + "zod": "^4.1.13", + "zustand": "^5.0.9" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.0.8", + "sharp": "^0.34.5", + "tailwindcss": "^4", + "tw-animate-css": "^1.4.0", + "typescript": "^5" + } +} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000000000000000000000000000000000000..61e36849cf7cfa9f1f71b4a3964a4953e3e243d3 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/prisma.config.ts b/prisma.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c5e959309f6f1f72e60eab041ab6bad324fdfdd --- /dev/null +++ b/prisma.config.ts @@ -0,0 +1,14 @@ +// This file was generated by Prisma and assumes you have installed the following: +// npm install --save-dev prisma dotenv +import "dotenv/config"; +import { defineConfig, env } from "prisma/config"; + +export default defineConfig({ + schema: "prisma/schema.prisma", + migrations: { + path: "prisma/migrations", + }, + datasource: { + url: env("DATABASE_URL"), + }, +}); diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000000000000000000000000000000000000..91370224f587aa202937f150bb4446d52e786175 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,760 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" +} + +model User { + id String @id @default(cuid()) + email String @unique + name String? + username String? @unique + image String? + bio String? + rank String? @default("bronze") // bronze, silver, gold, verified + totalRuns Int @default(0) + totalStars Int @default(0) + totalRemixes Int @default(0) + socialLinks Json? + + // Notification preferences + notifyEmail Boolean @default(true) + notifyStars Boolean @default(true) + notifyRemixes Boolean @default(true) + + // Stripe / Billing + stripeCustomerId String? @unique + stripePlan String @default("free") // free, pro + stripeSubscriptionId String? @unique + stripeSubscriptionStatus String? // active, canceled, past_due, etc. + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + prompts Prompt[] + stars Star[] + runs Run[] + collections Collection[] + comments Comment[] + commentLikes CommentLike[] + imagePrompts ImagePrompt[] + imageVotes ImagePromptVote[] + characters Character[] + characterVotes CharacterVote[] + workflows Workflow[] @relation("WorkflowCreator") + forumPosts ForumPost[] + forumReplies ForumReply[] + notifications Notification[] @relation("NotificationReceiver") + followers Follow[] @relation("Following") + following Follow[] @relation("Follower") + subscription Subscription? + purchases PromptPurchase[] +} + +model Prompt { + id String @id @default(cuid()) + slug String @unique + title String + description String? + template String @db.Text + schema Json @default("{\"variables\":[]}") + + category String? + tags String[] + visibility String @default("public") // public, unlisted, private + + modelDefault String @default("gpt-4o-mini") + modelAllowed String[] @default(["gpt-4o-mini", "gpt-4o", "claude-3-5-sonnet"]) + maxTokens Int @default(2048) + + totalRuns Int @default(0) + starsCount Int @default(0) + remixesCount Int @default(0) + + // Tier 3 fields + framework String? // RACE, CARE, APE, etc. + badges String[] @default([]) // Auto-calculated quality badges + + // Version tracking + currentVersion Int @default(1) + + // Premium marketplace + isPremium Boolean @default(false) // Is this a paid prompt? + price Int? // Price in cents (e.g., 299 = $2.99) + + creatorId String? + creator User? @relation(fields: [creatorId], references: [id]) + + parentId String? + parent Prompt? @relation("Remixes", fields: [parentId], references: [id]) + remixes Prompt[] @relation("Remixes") + + stars Star[] + runs Run[] + savedRuns SavedPromptRun[] + collections CollectionPrompt[] + comments Comment[] + versions PromptVersion[] + purchases PromptPurchase[] @relation("PremiumPurchases") + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([slug]) + @@index([creatorId]) + @@index([category]) + @@index([visibility]) +} + +model Star { + userId String + promptId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) + createdAt DateTime @default(now()) + + @@id([userId, promptId]) +} + +model Run { + id String @id @default(cuid()) + promptId String + userId String? + model String + tokens Int? + cached Boolean @default(false) + ipHash String? + prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) + user User? @relation(fields: [userId], references: [id]) + createdAt DateTime @default(now()) + + @@index([promptId]) + @@index([userId]) +} + +model Collection { + id String @id @default(cuid()) + name String + description String? + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + prompts CollectionPrompt[] + isPublic Boolean @default(false) + viewCount Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([userId]) + @@index([isPublic]) +} + +model CollectionPrompt { + collectionId String + promptId String + collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade) + prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) + addedAt DateTime @default(now()) + + @@id([collectionId, promptId]) + @@index([collectionId]) + @@index([promptId]) +} + +model Workflow { + id String @id @default(cuid()) + slug String @unique + name String + description String? + steps Json // Array of workflow steps + variables Json? // Input variables for the workflow + + visibility String @default("private") // public, unlisted, private + + totalRuns Int @default(0) + starsCount Int @default(0) + + creatorId String? + creator User? @relation("WorkflowCreator", fields: [creatorId], references: [id]) + + runs WorkflowRun[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([slug]) + @@index([creatorId]) + @@index([visibility]) +} + +model WorkflowRun { + id String @id @default(cuid()) + + workflowId String + workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade) + + userId String? // Who ran it + + name String? // Optional name for the run (user can name it) + + variables Json? // The variable values used for this run + outputs Json // Array of step outputs + model String // Model used for the run + + createdAt DateTime @default(now()) + + @@index([workflowId]) + @@index([userId]) +} + +// Saved prompt execution results +model SavedPromptRun { + id String @id @default(cuid()) + + promptId String + prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) + + userId String? + + name String? + variables Json? // Variable values used + output String @db.Text // The AI output + model String + + createdAt DateTime @default(now()) + + @@index([promptId]) + @@index([userId]) +} + +// Saved AI tool execution results +model SavedToolRun { + id String @id @default(cuid()) + + toolSlug String // Tool identifier (no relation, tools are static) + + userId String? + + name String? + inputs Json? // Input values used + output String @db.Text // The AI output + model String + + createdAt DateTime @default(now()) + + @@index([toolSlug]) + @@index([userId]) +} + +// Saved model comparison results (Thunderdome / Performance) +model SavedComparison { + id String @id @default(cuid()) + + type String // "thunderdome" or "performance" + + userId String? + + name String? + prompt String @db.Text // The prompt used + results Json // Array of model results with outputs + winner String? // Winning model (for thunderdome) + + createdAt DateTime @default(now()) + + @@index([userId]) + @@index([type]) +} + +// ============================================ +// NEW FEATURES - December 2025 +// ============================================ + +// Comments on prompts (threaded discussions) +model Comment { + id String @id @default(cuid()) + content String @db.Text + + promptId String + prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) + + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + parentId String? // For threaded replies + parent Comment? @relation("CommentReplies", fields: [parentId], references: [id], onDelete: Cascade) + replies Comment[] @relation("CommentReplies") + + // Per-user like tracking (replaces plain Int to prevent spam) + commentLikes CommentLike[] + likesCount Int @default(0) // Denormalized count for quick display + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([promptId]) + @@index([userId]) + @@index([parentId]) +} + +// Per-user comment likes โ€” prevents duplicate/spam likes +model CommentLike { + commentId String + comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade) + + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + createdAt DateTime @default(now()) + + @@id([commentId, userId]) + @@index([commentId]) + @@index([userId]) +} + +// Image Generation Prompts (Midjourney, DALL-E, Stable Diffusion, FLUX) +model ImagePrompt { + id String @id @default(cuid()) + slug String @unique + title String + description String? + + // The actual prompt text + prompt String @db.Text + negativePrompt String? @db.Text // For SD/FLUX + + // Target model + model String // midjourney, dalle, stable-diffusion, flux, leonardo + modelVersion String? // v6.1, SDXL, FLUX.1-dev, etc. + + // Image settings + aspectRatio String? // 16:9, 1:1, 9:16, etc. + style String? // photorealistic, anime, cartoon, etc. + + // Generated image preview (URL) + previewImage String? + gallery String[] @default([]) // Multiple generated images + + // Metadata + category String? // portrait, landscape, abstract, etc. + tags String[] + visibility String @default("public") + + // Stats + totalUses Int @default(0) + votesCount Int @default(0) + savesCount Int @default(0) + + creatorId String? + creator User? @relation(fields: [creatorId], references: [id]) + + votes ImagePromptVote[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([slug]) + @@index([model]) + @@index([creatorId]) + @@index([category]) +} + +// Votes for image prompts +model ImagePromptVote { + id String @id @default(cuid()) + + imagePromptId String + imagePrompt ImagePrompt @relation(fields: [imagePromptId], references: [id], onDelete: Cascade) + + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + value Int @default(1) // 1 for upvote, -1 for downvote + + createdAt DateTime @default(now()) + + @@unique([imagePromptId, userId]) + @@index([imagePromptId]) + @@index([userId]) +} + +// Character/Persona System +model Character { + id String @id @default(cuid()) + slug String @unique + name String + description String? @db.Text + + // Persona definition + personality String @db.Text // Character's personality traits + background String? @db.Text // Character's backstory + systemPrompt String @db.Text // The actual system prompt + + // Visual representation + avatar String? // URL to avatar image + style String? // anime, realistic, cartoon, etc. + + // Metadata + category String? // assistant, roleplay, educational, etc. + tags String[] + visibility String @default("public") + + // Conversation settings + responseStyle String? // formal, casual, playful, etc. + temperature Float @default(0.7) + + // Stats + totalChats Int @default(0) + votesCount Int @default(0) + savesCount Int @default(0) + + creatorId String? + creator User? @relation(fields: [creatorId], references: [id]) + + votes CharacterVote[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([slug]) + @@index([creatorId]) + @@index([category]) +} + +// Votes for characters +model CharacterVote { + id String @id @default(cuid()) + + characterId String + character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) + + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + value Int @default(1) + + createdAt DateTime @default(now()) + + @@unique([characterId, userId]) + @@index([characterId]) + @@index([userId]) +} + +// Engagement metrics tracking +model EngagementMetric { + id String @id @default(cuid()) + + // What was engaged with + targetType String // prompt, imagePrompt, character, workflow + targetId String + + // Type of engagement + action String // view, use, save, share, copy + + userId String? // Null for anonymous + ipHash String? // For anonymous tracking + + createdAt DateTime @default(now()) + + @@index([targetType, targetId]) + @@index([action]) + @@index([createdAt]) +} + +// Extension Analytics - tracks prompt usage from extension +model ExtensionAnalytics { + id String @id @default(cuid()) + + // User tracking + userId String? // Null for anonymous users + deviceId String // Unique device identifier from extension + + // What action was taken + action String // inject, capture, broadcast, shortcut_use, context_menu + + // Platform info + platform String // chatgpt, claude, gemini, etc. + platforms String[] @default([]) // For broadcast (multiple platforms) + + // Prompt info (optional - for inject/capture) + promptId String? // If from OpenPrompt library + promptTitle String? + promptText String? @db.Text // For captured prompts + + // Source info + source String @default("extension") // extension, website + + // Metadata + metadata Json? // Additional data like shortcut used, etc. + + createdAt DateTime @default(now()) + + @@index([userId]) + @@index([deviceId]) + @@index([action]) + @@index([platform]) + @@index([createdAt]) +} + +// Captured prompts from AI chats (saved by users via extension) +model CapturedPrompt { + id String @id @default(cuid()) + + userId String? + deviceId String + + title String? + text String @db.Text + + platform String // Where it was captured from + url String? // Original URL + + // If saved to library + savedToLibrary Boolean @default(false) + promptId String? // If converted to a Prompt + + tags String[] @default([]) + + createdAt DateTime @default(now()) + + @@index([userId]) + @@index([deviceId]) + @@index([platform]) + @@index([createdAt]) +} + +// ============================================ +// COMMUNITY FEATURES - December 2025 +// ============================================ + +// Forum Posts (Community Q&A) +model ForumPost { + id String @id @default(cuid()) + title String + content String @db.Text + category String // general, help, showcase, feature-request, tips + + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + replies ForumReply[] + + views Int @default(0) + likes Int @default(0) + isPinned Boolean @default(false) + isClosed Boolean @default(false) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([userId]) + @@index([category]) + @@index([createdAt]) +} + +// Forum Replies +model ForumReply { + id String @id @default(cuid()) + content String @db.Text + + postId String + post ForumPost @relation(fields: [postId], references: [id], onDelete: Cascade) + + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + parentId String? // For nested replies + + likes Int @default(0) + isAccepted Boolean @default(false) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([postId]) + @@index([userId]) + @@index([parentId]) +} + +// User Conversations (Messaging) +model Conversation { + id String @id @default(cuid()) + + participant1 String + participant2 String + + messages Message[] + + lastMessage String? @db.Text + lastActivity DateTime @default(now()) + + createdAt DateTime @default(now()) + + @@unique([participant1, participant2]) + @@index([participant1]) + @@index([participant2]) + @@index([lastActivity]) +} + +// Direct Messages +model Message { + id String @id @default(cuid()) + content String @db.Text + + senderId String + + conversationId String + conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade) + + isRead Boolean @default(false) + + createdAt DateTime @default(now()) + + @@index([conversationId]) + @@index([senderId]) + @@index([createdAt]) +} + +// Character Memory (Persistent context) +model CharacterMemory { + id String @id @default(cuid()) + + characterId String + userId String + + contextSummary String? @db.Text + recentMessages Json @default("[]") + userFacts Json @default("[]") + messageCount Int @default(0) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([characterId, userId]) + @@index([characterId]) + @@index([userId]) +} + +// ============================================ +// NEW FEATURES - Follow & Notifications +// ============================================ + +// Follow system for creators +model Follow { + id String @id @default(cuid()) + + followerId String + follower User @relation("Follower", fields: [followerId], references: [id], onDelete: Cascade) + + followingId String + following User @relation("Following", fields: [followingId], references: [id], onDelete: Cascade) + + createdAt DateTime @default(now()) + + @@unique([followerId, followingId]) + @@index([followerId]) + @@index([followingId]) +} + +// Notification system +model Notification { + id String @id @default(cuid()) + + userId String // Who receives the notification + user User @relation("NotificationReceiver", fields: [userId], references: [id], onDelete: Cascade) + + type String // star, remix, comment, follow, mention + title String + message String? + + // What triggered the notification + actorId String? // Who performed the action + targetType String? // prompt, workflow, comment, etc. + targetId String? + targetSlug String? // For linking + + isRead Boolean @default(false) + + createdAt DateTime @default(now()) + + @@index([userId, isRead]) + @@index([userId, createdAt]) +} + +// Prompt version history +model PromptVersion { + id String @id @default(cuid()) + + promptId String + prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) + + version Int @default(1) + title String + template String @db.Text + schema Json @default("{\"variables\":[]}") + changeNote String? // What changed + + createdAt DateTime @default(now()) + + @@index([promptId]) + @@index([promptId, version]) +} + +// ============================================ +// BILLING โ€” Stripe Integration +// ============================================ + +// Active subscription record (one per user) +model Subscription { + id String @id @default(cuid()) + + userId String @unique + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + // Stripe identifiers + stripeCustomerId String @unique + stripeSubscriptionId String @unique + stripePriceId String + + // Plan info + plan String @default("pro") // pro, enterprise + status String // active, canceled, past_due, trialing, unpaid + + // Billing cycle + currentPeriodStart DateTime + currentPeriodEnd DateTime + cancelAtPeriodEnd Boolean @default(false) + canceledAt DateTime? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([userId]) + @@index([stripeSubscriptionId]) +} + +// Records when a user purchases a premium prompt +model PromptPurchase { + id String @id @default(cuid()) + + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + promptId String + prompt Prompt @relation("PremiumPurchases", fields: [promptId], references: [id], onDelete: Cascade) + + // Payment info + amount Int // in cents + currency String @default("usd") + stripePaymentIntentId String @unique + + // Creator payout (80% to creator) + creatorPayout Int // 80% of amount in cents + creatorPaid Boolean @default(false) + + createdAt DateTime @default(now()) + + @@unique([userId, promptId]) // One purchase per user per prompt + @@index([userId]) + @@index([promptId]) +} diff --git a/prisma/seed-more.ts b/prisma/seed-more.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7074731426ffb2f10d51045174b8d999c7775a1 --- /dev/null +++ b/prisma/seed-more.ts @@ -0,0 +1,128 @@ +import { Pool } from 'pg' +import { PrismaPg } from '@prisma/adapter-pg' +import { PrismaClient } from '@prisma/client' +import 'dotenv/config' + +const connectionString = process.env.DATABASE_URL +if (!connectionString) throw new Error('DATABASE_URL not set') + +const pool = new Pool({ connectionString }) +const adapter = new PrismaPg(pool) +const prisma = new PrismaClient({ adapter }) + +const morePrompts = [ + // ============ CONTENT (10 more) ============ + { slug: 'newsletter-writer', title: 'Newsletter Writer Pro', description: 'Create engaging email newsletters that get opened and read.', category: 'Content', template: 'Write a {{frequency}} newsletter about {{topic}} for {{audience}}.\n\nInclude:\n- Catchy subject line\n- Personal intro\n- 3 main sections\n- CTA\n- P.S. line', schema: { variables: [{ name: 'topic', type: 'text', label: 'Newsletter Topic', required: true }, { name: 'frequency', type: 'dropdown', label: 'Frequency', options: ['Weekly', 'Monthly', 'Daily'] }, { name: 'audience', type: 'text', label: 'Target Audience' }] }, tags: ['newsletter', 'email'], totalRuns: 4532, starsCount: 312 }, + { slug: 'linkedin-post', title: 'LinkedIn Post Generator', description: 'Create viral LinkedIn posts that build your personal brand.', category: 'Content', template: 'Write a LinkedIn post about {{topic}}.\n\nStyle: {{style}}\nInclude hook, story, lesson, CTA.\nUse line breaks for readability.\nAdd relevant emojis.', schema: { variables: [{ name: 'topic', type: 'text', label: 'Post Topic', required: true }, { name: 'style', type: 'dropdown', label: 'Style', options: ['Story', 'Tips', 'Hot Take', 'Celebration', 'Question'] }] }, tags: ['linkedin', 'social-media'], totalRuns: 7654, starsCount: 543 }, + { slug: 'product-description', title: 'E-Commerce Product Description', description: 'Write product descriptions that convert browsers to buyers.', category: 'Content', template: 'Write a product description for:\n\nProduct: {{product}}\nPrice: {{price}}\nTarget Customer: {{customer}}\n\nInclude features, benefits, social proof elements, and urgency.', schema: { variables: [{ name: 'product', type: 'text', label: 'Product Name', required: true }, { name: 'price', type: 'text', label: 'Price' }, { name: 'customer', type: 'text', label: 'Target Customer' }] }, tags: ['ecommerce', 'product'], totalRuns: 8765, starsCount: 654 }, + { slug: 'podcast-outline', title: 'Podcast Episode Outline', description: 'Plan engaging podcast episodes with structured outlines.', category: 'Content', template: 'Create a podcast outline for:\n\nTopic: {{topic}}\nDuration: {{duration}} minutes\nFormat: {{format}}\n\nInclude intro hook, main segments, key talking points, and outro.', schema: { variables: [{ name: 'topic', type: 'text', label: 'Episode Topic', required: true }, { name: 'duration', type: 'dropdown', label: 'Duration', options: ['15', '30', '45', '60'] }, { name: 'format', type: 'dropdown', label: 'Format', options: ['Solo', 'Interview', 'Co-hosted', 'Panel'] }] }, tags: ['podcast', 'audio'], totalRuns: 3456, starsCount: 234 }, + { slug: 'press-release', title: 'Press Release Generator', description: 'Write professional press releases for announcements.', category: 'Content', template: 'Write a press release for:\n\nCompany: {{company}}\nAnnouncement: {{announcement}}\nQuote from: {{spokesperson}}\n\nFollow AP style, include headline, dateline, boilerplate.', schema: { variables: [{ name: 'company', type: 'text', label: 'Company Name', required: true }, { name: 'announcement', type: 'textarea', label: 'Announcement', required: true }, { name: 'spokesperson', type: 'text', label: 'Spokesperson Name' }] }, tags: ['pr', 'press'], totalRuns: 2345, starsCount: 187 }, + { slug: 'case-study', title: 'Case Study Writer', description: 'Create compelling case studies that showcase results.', category: 'Content', template: 'Write a case study about:\n\nClient: {{client}}\nChallenge: {{challenge}}\nSolution: {{solution}}\nResults: {{results}}\n\nFormat with Problem, Solution, Results sections.', schema: { variables: [{ name: 'client', type: 'text', label: 'Client/Company', required: true }, { name: 'challenge', type: 'textarea', label: 'Challenge', required: true }, { name: 'solution', type: 'textarea', label: 'Solution' }, { name: 'results', type: 'textarea', label: 'Results' }] }, tags: ['case-study', 'marketing'], totalRuns: 4567, starsCount: 345 }, + { slug: 'faq-generator', title: 'FAQ Generator', description: 'Generate comprehensive FAQs for products or services.', category: 'Content', template: 'Generate {{count}} FAQs for:\n\nProduct/Service: {{product}}\nTarget Audience: {{audience}}\n\nInclude common questions and detailed, helpful answers.', schema: { variables: [{ name: 'product', type: 'text', label: 'Product/Service', required: true }, { name: 'count', type: 'dropdown', label: 'Number of FAQs', options: ['5', '10', '15', '20'] }, { name: 'audience', type: 'text', label: 'Target Audience' }] }, tags: ['faq', 'support'], totalRuns: 5678, starsCount: 432 }, + { slug: 'meta-description', title: 'SEO Meta Description Writer', description: 'Write click-worthy meta descriptions for better CTR.', category: 'Content', template: 'Write 3 meta description variations for:\n\nPage: {{page}}\nKeyword: {{keyword}}\nTarget Length: 155 characters\n\nMake them compelling with CTAs.', schema: { variables: [{ name: 'page', type: 'text', label: 'Page Description', required: true }, { name: 'keyword', type: 'text', label: 'Target Keyword', required: true }] }, tags: ['seo', 'meta'], totalRuns: 8765, starsCount: 567 }, + { slug: 'book-summary', title: 'Book Summary Generator', description: 'Create comprehensive book summaries with key takeaways.', category: 'Content', template: 'Summarize the book "{{book}}" by {{author}}.\n\nInclude:\n- Overview\n- Key concepts\n- Main takeaways\n- Who should read it\n- Best quotes', schema: { variables: [{ name: 'book', type: 'text', label: 'Book Title', required: true }, { name: 'author', type: 'text', label: 'Author' }] }, tags: ['books', 'summary'], totalRuns: 6543, starsCount: 456 }, + { slug: 'caption-writer', title: 'Instagram Caption Writer', description: 'Write engaging Instagram captions with hashtags.', category: 'Content', template: 'Write an Instagram caption for:\n\nPhoto/Video: {{content}}\nBrand Voice: {{voice}}\nGoal: {{goal}}\n\nInclude emojis, call-to-action, and 10-15 relevant hashtags.', schema: { variables: [{ name: 'content', type: 'text', label: 'Content Description', required: true }, { name: 'voice', type: 'dropdown', label: 'Brand Voice', options: ['Professional', 'Fun', 'Inspirational', 'Educational'] }, { name: 'goal', type: 'dropdown', label: 'Goal', options: ['Engagement', 'Sales', 'Brand Awareness', 'Traffic'] }] }, tags: ['instagram', 'social-media', 'captions'], totalRuns: 9876, starsCount: 765 }, + + // ============ DEVELOPMENT (10 more) ============ + { slug: 'unit-test-writer', title: 'Unit Test Generator', description: 'Generate comprehensive unit tests for your code.', category: 'Development', template: 'Write unit tests for this {{language}} code:\n\n```{{language}}\n{{code}}\n```\n\nFramework: {{framework}}\n\nInclude edge cases, error handling, and mocks.', schema: { variables: [{ name: 'language', type: 'dropdown', label: 'Language', options: ['JavaScript', 'TypeScript', 'Python', 'Java', 'Go'], required: true }, { name: 'code', type: 'textarea', label: 'Code to Test', required: true }, { name: 'framework', type: 'text', label: 'Test Framework', placeholder: 'e.g., Jest, pytest' }] }, tags: ['testing', 'unit-tests'], totalRuns: 7654, starsCount: 543 }, + { slug: 'sql-query-builder', title: 'SQL Query Builder', description: 'Generate optimized SQL queries from natural language.', category: 'Development', template: 'Generate a SQL query for:\n\n{{request}}\n\nDatabase: {{database}}\nTables: {{tables}}\n\nOptimize for performance and include comments.', schema: { variables: [{ name: 'request', type: 'textarea', label: 'What do you need?', required: true }, { name: 'database', type: 'dropdown', label: 'Database', options: ['PostgreSQL', 'MySQL', 'SQLite', 'SQL Server'] }, { name: 'tables', type: 'textarea', label: 'Table Schemas' }] }, tags: ['sql', 'database'], totalRuns: 8765, starsCount: 654 }, + { slug: 'git-commit-message', title: 'Git Commit Message Generator', description: 'Write conventional, descriptive commit messages.', category: 'Development', template: 'Write a git commit message for these changes:\n\n{{changes}}\n\nStyle: {{style}}\n\nFollow conventional commits format.', schema: { variables: [{ name: 'changes', type: 'textarea', label: 'Describe your changes', required: true }, { name: 'style', type: 'dropdown', label: 'Style', options: ['Conventional Commits', 'Detailed', 'Brief'] }] }, tags: ['git', 'commits'], totalRuns: 12345, starsCount: 876 }, + { slug: 'dockerfile-generator', title: 'Dockerfile Generator', description: 'Create optimized Dockerfiles for your applications.', category: 'Development', template: 'Create a Dockerfile for:\n\nApp Type: {{appType}}\nBase Image: {{base}}\nRequirements: {{requirements}}\n\nOptimize for size and security.', schema: { variables: [{ name: 'appType', type: 'dropdown', label: 'Application Type', options: ['Node.js', 'Python', 'Go', 'Java', 'Rust', 'Multi-stage'], required: true }, { name: 'base', type: 'text', label: 'Base Image', placeholder: 'e.g., node:20-alpine' }, { name: 'requirements', type: 'textarea', label: 'Additional Requirements' }] }, tags: ['docker', 'devops'], totalRuns: 5678, starsCount: 432 }, + { slug: 'error-debugger', title: 'Error Message Debugger', description: 'Debug error messages and get solutions.', category: 'Development', template: 'Help me debug this error:\n\n```\n{{error}}\n```\n\nContext: {{context}}\nLanguage/Framework: {{language}}\n\nExplain the cause and provide solutions.', schema: { variables: [{ name: 'error', type: 'textarea', label: 'Error Message', required: true }, { name: 'context', type: 'textarea', label: 'What were you doing?' }, { name: 'language', type: 'text', label: 'Language/Framework' }] }, tags: ['debugging', 'errors'], totalRuns: 15678, starsCount: 1234 }, + { slug: 'api-request-builder', title: 'API Request Builder', description: 'Generate API requests in multiple languages.', category: 'Development', template: 'Generate API request code for:\n\nEndpoint: {{endpoint}}\nMethod: {{method}}\nHeaders: {{headers}}\nBody: {{body}}\n\nLanguages: {{languages}}', schema: { variables: [{ name: 'endpoint', type: 'text', label: 'API Endpoint', required: true }, { name: 'method', type: 'dropdown', label: 'Method', options: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] }, { name: 'headers', type: 'textarea', label: 'Headers (JSON)' }, { name: 'body', type: 'textarea', label: 'Request Body' }, { name: 'languages', type: 'text', label: 'Languages', default: 'JavaScript, Python, cURL' }] }, tags: ['api', 'http'], totalRuns: 6789, starsCount: 543 }, + { slug: 'readme-generator', title: 'README.md Generator', description: 'Create professional README files for your projects.', category: 'Development', template: 'Generate a README.md for:\n\nProject: {{project}}\nDescription: {{description}}\nTech Stack: {{tech}}\nFeatures: {{features}}\n\nInclude badges, installation, usage, contributing.', schema: { variables: [{ name: 'project', type: 'text', label: 'Project Name', required: true }, { name: 'description', type: 'textarea', label: 'Description', required: true }, { name: 'tech', type: 'text', label: 'Tech Stack' }, { name: 'features', type: 'textarea', label: 'Key Features' }] }, tags: ['readme', 'documentation'], totalRuns: 9876, starsCount: 765 }, + { slug: 'cron-expression', title: 'Cron Expression Generator', description: 'Generate cron expressions from natural language.', category: 'Development', template: 'Generate a cron expression for:\n\n{{schedule}}\n\nProvide:\n- Cron expression\n- Explanation of each field\n- Example run times', schema: { variables: [{ name: 'schedule', type: 'text', label: 'Schedule Description', placeholder: 'e.g., Every Monday at 9 AM', required: true }] }, tags: ['cron', 'scheduling'], totalRuns: 4567, starsCount: 345 }, + { slug: 'shell-script', title: 'Shell Script Generator', description: 'Generate bash/shell scripts for automation.', category: 'Development', template: 'Write a shell script to:\n\n{{task}}\n\nOS: {{os}}\nShell: {{shell}}\n\nInclude error handling and comments.', schema: { variables: [{ name: 'task', type: 'textarea', label: 'What should the script do?', required: true }, { name: 'os', type: 'dropdown', label: 'Operating System', options: ['Linux', 'macOS', 'Windows (PowerShell)'] }, { name: 'shell', type: 'dropdown', label: 'Shell', options: ['bash', 'zsh', 'sh', 'PowerShell'] }] }, tags: ['bash', 'automation', 'scripts'], totalRuns: 7890, starsCount: 567 }, + { slug: 'prisma-schema', title: 'Prisma Schema Generator', description: 'Generate Prisma schemas from requirements.', category: 'Development', template: 'Generate a Prisma schema for:\n\n{{requirements}}\n\nDatabase: {{database}}\n\nInclude relations, indexes, and enums as needed.', schema: { variables: [{ name: 'requirements', type: 'textarea', label: 'Describe your data model', required: true }, { name: 'database', type: 'dropdown', label: 'Database', options: ['PostgreSQL', 'MySQL', 'SQLite', 'MongoDB'] }] }, tags: ['prisma', 'database', 'orm'], totalRuns: 3456, starsCount: 234 }, + + // ============ MARKETING (8 more) ============ + { slug: 'email-sequence', title: 'Email Sequence Creator', description: 'Create automated email sequences that convert.', category: 'Marketing', template: 'Create a {{emails}}-email sequence for:\n\nGoal: {{goal}}\nProduct: {{product}}\nAudience: {{audience}}\n\nInclude subject lines, preview text, and body for each.', schema: { variables: [{ name: 'emails', type: 'dropdown', label: 'Number of Emails', options: ['3', '5', '7', '10'], required: true }, { name: 'goal', type: 'dropdown', label: 'Sequence Goal', options: ['Welcome', 'Sales', 'Onboarding', 'Re-engagement'] }, { name: 'product', type: 'text', label: 'Product/Service' }, { name: 'audience', type: 'text', label: 'Target Audience' }] }, tags: ['email-marketing', 'automation'], totalRuns: 5678, starsCount: 432 }, + { slug: 'seo-keywords', title: 'SEO Keyword Research', description: 'Generate keyword ideas with search intent analysis.', category: 'Marketing', template: 'Generate keyword ideas for:\n\nTopic: {{topic}}\nNiche: {{niche}}\n\nFor each keyword, include:\n- Search intent\n- Difficulty estimate\n- Content type recommendation', schema: { variables: [{ name: 'topic', type: 'text', label: 'Main Topic', required: true }, { name: 'niche', type: 'text', label: 'Industry/Niche' }] }, tags: ['seo', 'keywords'], totalRuns: 7654, starsCount: 543 }, + { slug: 'ab-test-ideas', title: 'A/B Test Ideas Generator', description: 'Generate A/B test hypotheses to improve conversion.', category: 'Marketing', template: 'Generate A/B test ideas for:\n\nPage Type: {{page}}\nCurrent Conversion Rate: {{rate}}\nGoal: {{goal}}\n\nFor each test, include hypothesis, expected impact, and how to measure.', schema: { variables: [{ name: 'page', type: 'dropdown', label: 'Page Type', options: ['Landing Page', 'Checkout', 'Pricing', 'Homepage', 'Product Page'], required: true }, { name: 'rate', type: 'text', label: 'Current Conversion Rate' }, { name: 'goal', type: 'text', label: 'Improvement Goal' }] }, tags: ['ab-testing', 'cro'], totalRuns: 3456, starsCount: 234 }, + { slug: 'brand-voice', title: 'Brand Voice Guidelines', description: 'Define your brand voice and communication style.', category: 'Marketing', template: 'Create brand voice guidelines for:\n\nBrand: {{brand}}\nIndustry: {{industry}}\nTarget Audience: {{audience}}\nPersonality: {{personality}}\n\nInclude dos, don\'ts, and examples.', schema: { variables: [{ name: 'brand', type: 'text', label: 'Brand Name', required: true }, { name: 'industry', type: 'text', label: 'Industry' }, { name: 'audience', type: 'text', label: 'Target Audience' }, { name: 'personality', type: 'text', label: 'Brand Personality Traits' }] }, tags: ['branding', 'voice'], totalRuns: 4567, starsCount: 345 }, + { slug: 'competitor-analysis', title: 'Competitor Analysis', description: 'Analyze competitors and find opportunities.', category: 'Marketing', template: 'Analyze these competitors for {{company}}:\n\nCompetitors: {{competitors}}\n\nAnalyze:\n- Strengths & weaknesses\n- Pricing strategies\n- Marketing channels\n- Opportunity gaps', schema: { variables: [{ name: 'company', type: 'text', label: 'Your Company', required: true }, { name: 'competitors', type: 'textarea', label: 'Competitor Names', required: true }] }, tags: ['competitive-analysis', 'strategy'], totalRuns: 2345, starsCount: 187 }, + { slug: 'utm-generator', title: 'UTM Parameter Generator', description: 'Generate UTM parameters for campaign tracking.', category: 'Marketing', template: 'Generate UTM parameters for:\n\nCampaign: {{campaign}}\nChannels: {{channels}}\nBase URL: {{url}}\n\nProvide full URLs with proper naming conventions.', schema: { variables: [{ name: 'campaign', type: 'text', label: 'Campaign Name', required: true }, { name: 'channels', type: 'text', label: 'Marketing Channels', placeholder: 'e.g., email, twitter, facebook' }, { name: 'url', type: 'text', label: 'Base URL', required: true }] }, tags: ['utm', 'analytics'], totalRuns: 5678, starsCount: 432 }, + { slug: 'value-proposition', title: 'Value Proposition Canvas', description: 'Create a compelling value proposition.', category: 'Marketing', template: 'Create a value proposition for:\n\nProduct: {{product}}\nTarget Customer: {{customer}}\nMain Problem: {{problem}}\n\nUse the Value Proposition Canvas framework.', schema: { variables: [{ name: 'product', type: 'text', label: 'Product/Service', required: true }, { name: 'customer', type: 'text', label: 'Target Customer', required: true }, { name: 'problem', type: 'textarea', label: 'Main Problem You Solve' }] }, tags: ['value-proposition', 'positioning'], totalRuns: 4567, starsCount: 345 }, + { slug: 'influencer-brief', title: 'Influencer Brief Creator', description: 'Create briefs for influencer collaborations.', category: 'Marketing', template: 'Create an influencer brief for:\n\nBrand: {{brand}}\nCampaign: {{campaign}}\nPlatform: {{platform}}\nDeliverables: {{deliverables}}\n\nInclude brand guidelines, key messages, dos and don\'ts.', schema: { variables: [{ name: 'brand', type: 'text', label: 'Brand Name', required: true }, { name: 'campaign', type: 'text', label: 'Campaign Name' }, { name: 'platform', type: 'dropdown', label: 'Platform', options: ['Instagram', 'TikTok', 'YouTube', 'Twitter'] }, { name: 'deliverables', type: 'textarea', label: 'Deliverables' }] }, tags: ['influencer', 'social-media'], totalRuns: 3456, starsCount: 234 }, + + // ============ BUSINESS (8 more) ============ + { slug: 'meeting-agenda', title: 'Meeting Agenda Generator', description: 'Create structured meeting agendas.', category: 'Business', template: 'Create a meeting agenda for:\n\nMeeting Type: {{type}}\nDuration: {{duration}} minutes\nTopics: {{topics}}\nAttendees: {{attendees}}\n\nInclude time allocations and action items section.', schema: { variables: [{ name: 'type', type: 'dropdown', label: 'Meeting Type', options: ['Team Standup', 'Project Review', 'Brainstorm', 'Client Call', 'All Hands'], required: true }, { name: 'duration', type: 'dropdown', label: 'Duration (min)', options: ['15', '30', '45', '60'] }, { name: 'topics', type: 'textarea', label: 'Topics to Discuss' }, { name: 'attendees', type: 'text', label: 'Key Attendees' }] }, tags: ['meetings', 'productivity'], totalRuns: 8765, starsCount: 654 }, + { slug: 'okr-generator', title: 'OKR Generator', description: 'Create objectives and key results for teams.', category: 'Business', template: 'Generate OKRs for:\n\nTeam: {{team}}\nQuarter: {{quarter}}\nFocus Area: {{focus}}\nCurrent Challenges: {{challenges}}\n\nCreate 3-5 objectives with 3-4 key results each.', schema: { variables: [{ name: 'team', type: 'text', label: 'Team/Department', required: true }, { name: 'quarter', type: 'dropdown', label: 'Quarter', options: ['Q1', 'Q2', 'Q3', 'Q4'] }, { name: 'focus', type: 'text', label: 'Focus Area' }, { name: 'challenges', type: 'textarea', label: 'Current Challenges' }] }, tags: ['okrs', 'goals', 'planning'], totalRuns: 4567, starsCount: 345 }, + { slug: 'job-description', title: 'Job Description Writer', description: 'Write compelling job descriptions that attract talent.', category: 'Business', template: 'Write a job description for:\n\nPosition: {{position}}\nCompany: {{company}}\nLevel: {{level}}\nLocation: {{location}}\nKey Skills: {{skills}}\n\nMake it engaging and inclusive.', schema: { variables: [{ name: 'position', type: 'text', label: 'Job Title', required: true }, { name: 'company', type: 'text', label: 'Company Name' }, { name: 'level', type: 'dropdown', label: 'Level', options: ['Entry', 'Mid', 'Senior', 'Lead', 'Manager', 'Director'] }, { name: 'location', type: 'text', label: 'Location' }, { name: 'skills', type: 'textarea', label: 'Required Skills' }] }, tags: ['hiring', 'hr', 'jobs'], totalRuns: 6543, starsCount: 456 }, + { slug: 'swot-analysis', title: 'SWOT Analysis Generator', description: 'Create comprehensive SWOT analyses.', category: 'Business', template: 'Create a SWOT analysis for:\n\nCompany/Project: {{subject}}\nIndustry: {{industry}}\nContext: {{context}}\n\nProvide detailed Strengths, Weaknesses, Opportunities, and Threats.', schema: { variables: [{ name: 'subject', type: 'text', label: 'Company/Project', required: true }, { name: 'industry', type: 'text', label: 'Industry' }, { name: 'context', type: 'textarea', label: 'Context/Background' }] }, tags: ['swot', 'strategy', 'analysis'], totalRuns: 5678, starsCount: 432 }, + { slug: 'performance-review', title: 'Performance Review Helper', description: 'Write constructive performance reviews.', category: 'Business', template: 'Help write a performance review for:\n\nRole: {{role}}\nAchievements: {{achievements}}\nAreas to Improve: {{improvements}}\nTone: {{tone}}\n\nBe constructive and specific.', schema: { variables: [{ name: 'role', type: 'text', label: 'Employee Role', required: true }, { name: 'achievements', type: 'textarea', label: 'Key Achievements' }, { name: 'improvements', type: 'textarea', label: 'Areas for Improvement' }, { name: 'tone', type: 'dropdown', label: 'Tone', options: ['Highly Positive', 'Positive', 'Constructive', 'Needs Improvement'] }] }, tags: ['hr', 'reviews', 'management'], totalRuns: 7654, starsCount: 543 }, + { slug: 'invoice-email', title: 'Invoice & Payment Email', description: 'Write professional invoice and payment emails.', category: 'Business', template: 'Write {{type}} email for:\n\nClient: {{client}}\nAmount: {{amount}}\nProject: {{project}}\nDue Date: {{due}}\n\nBe professional but friendly.', schema: { variables: [{ name: 'type', type: 'dropdown', label: 'Email Type', options: ['Invoice', 'Payment Reminder', 'Overdue Notice', 'Payment Received'], required: true }, { name: 'client', type: 'text', label: 'Client Name' }, { name: 'amount', type: 'text', label: 'Amount' }, { name: 'project', type: 'text', label: 'Project Name' }, { name: 'due', type: 'text', label: 'Due Date' }] }, tags: ['invoice', 'payment', 'finance'], totalRuns: 4567, starsCount: 345 }, + { slug: 'sop-writer', title: 'SOP Document Writer', description: 'Create Standard Operating Procedures.', category: 'Business', template: 'Create an SOP for:\n\nProcess: {{process}}\nDepartment: {{department}}\nComplexity: {{complexity}}\n\nInclude purpose, scope, procedure steps, and exceptions.', schema: { variables: [{ name: 'process', type: 'text', label: 'Process Name', required: true }, { name: 'department', type: 'text', label: 'Department' }, { name: 'complexity', type: 'dropdown', label: 'Complexity', options: ['Simple', 'Moderate', 'Complex'] }] }, tags: ['sop', 'documentation', 'processes'], totalRuns: 3456, starsCount: 234 }, + { slug: 'pitch-deck', title: 'Pitch Deck Outline', description: 'Create investor pitch deck structure.', category: 'Business', template: 'Create a pitch deck outline for:\n\nStartup: {{startup}}\nStage: {{stage}}\nAsking: {{ask}}\nProblem: {{problem}}\n\nInclude all essential slides with talking points.', schema: { variables: [{ name: 'startup', type: 'text', label: 'Startup Name', required: true }, { name: 'stage', type: 'dropdown', label: 'Stage', options: ['Pre-seed', 'Seed', 'Series A', 'Series B+'] }, { name: 'ask', type: 'text', label: 'Funding Ask' }, { name: 'problem', type: 'textarea', label: 'Problem You Solve' }] }, tags: ['pitch', 'investors', 'startup'], totalRuns: 5678, starsCount: 432 }, + + // ============ EDUCATION (6 more) ============ + { slug: 'quiz-generator', title: 'Quiz Generator', description: 'Create quizzes and tests on any topic.', category: 'Education', template: 'Create a quiz on:\n\nTopic: {{topic}}\nDifficulty: {{difficulty}}\nQuestions: {{count}}\nType: {{type}}\n\nInclude answers and explanations.', schema: { variables: [{ name: 'topic', type: 'text', label: 'Topic', required: true }, { name: 'difficulty', type: 'dropdown', label: 'Difficulty', options: ['Easy', 'Medium', 'Hard'] }, { name: 'count', type: 'dropdown', label: 'Questions', options: ['5', '10', '15', '20'] }, { name: 'type', type: 'dropdown', label: 'Question Type', options: ['Multiple Choice', 'True/False', 'Short Answer', 'Mixed'] }] }, tags: ['quiz', 'testing', 'education'], totalRuns: 8765, starsCount: 654 }, + { slug: 'study-guide', title: 'Study Guide Creator', description: 'Create comprehensive study guides.', category: 'Education', template: 'Create a study guide for:\n\nSubject: {{subject}}\nTopics: {{topics}}\nExam Type: {{exam}}\n\nInclude key concepts, practice questions, and memory tips.', schema: { variables: [{ name: 'subject', type: 'text', label: 'Subject', required: true }, { name: 'topics', type: 'textarea', label: 'Topics to Cover' }, { name: 'exam', type: 'dropdown', label: 'Exam Type', options: ['Multiple Choice', 'Essay', 'Practical', 'Mixed'] }] }, tags: ['study', 'exam', 'learning'], totalRuns: 6543, starsCount: 456 }, + { slug: 'flashcard-maker', title: 'Flashcard Generator', description: 'Create flashcards for spaced repetition learning.', category: 'Education', template: 'Create {{count}} flashcards for:\n\nTopic: {{topic}}\nLevel: {{level}}\n\nFormat: Front | Back\nInclude hints where helpful.', schema: { variables: [{ name: 'topic', type: 'text', label: 'Topic', required: true }, { name: 'count', type: 'dropdown', label: 'Number', options: ['10', '20', '30', '50'] }, { name: 'level', type: 'dropdown', label: 'Level', options: ['Beginner', 'Intermediate', 'Advanced'] }] }, tags: ['flashcards', 'memorization'], totalRuns: 7654, starsCount: 543 }, + { slug: 'essay-outline', title: 'Essay Outline Generator', description: 'Structure essays with compelling arguments.', category: 'Education', template: 'Create an essay outline for:\n\nTopic: {{topic}}\nThesis: {{thesis}}\nLength: {{length}} words\nStyle: {{style}}\n\nInclude intro, body paragraphs, and conclusion structure.', schema: { variables: [{ name: 'topic', type: 'text', label: 'Essay Topic', required: true }, { name: 'thesis', type: 'text', label: 'Thesis Statement' }, { name: 'length', type: 'dropdown', label: 'Length (words)', options: ['500', '1000', '1500', '2000', '3000'] }, { name: 'style', type: 'dropdown', label: 'Style', options: ['Argumentative', 'Expository', 'Narrative', 'Persuasive'] }] }, tags: ['essay', 'writing', 'academic'], totalRuns: 9876, starsCount: 765 }, + { slug: 'presentation-outline', title: 'Presentation Outline', description: 'Create structured presentation outlines.', category: 'Education', template: 'Create a presentation outline for:\n\nTopic: {{topic}}\nSlides: {{slides}}\nAudience: {{audience}}\nDuration: {{duration}} minutes\n\nInclude slide titles and key points.', schema: { variables: [{ name: 'topic', type: 'text', label: 'Presentation Topic', required: true }, { name: 'slides', type: 'dropdown', label: 'Number of Slides', options: ['5', '10', '15', '20'] }, { name: 'audience', type: 'text', label: 'Audience' }, { name: 'duration', type: 'dropdown', label: 'Duration (min)', options: ['5', '10', '15', '30'] }] }, tags: ['presentation', 'slides', 'speaking'], totalRuns: 5678, starsCount: 432 }, + { slug: 'language-tutor', title: 'Language Learning Tutor', description: 'Practice conversations in any language.', category: 'Education', template: 'Help me practice {{language}}.\n\nLevel: {{level}}\nScenario: {{scenario}}\nFocus: {{focus}}\n\nCorrect my mistakes and explain grammar.', schema: { variables: [{ name: 'language', type: 'dropdown', label: 'Language', options: ['Spanish', 'French', 'German', 'Japanese', 'Chinese', 'Italian', 'Portuguese', 'Korean'], required: true }, { name: 'level', type: 'dropdown', label: 'Level', options: ['Beginner', 'Intermediate', 'Advanced'] }, { name: 'scenario', type: 'text', label: 'Scenario', placeholder: 'e.g., ordering at a restaurant' }, { name: 'focus', type: 'dropdown', label: 'Focus Area', options: ['Conversation', 'Grammar', 'Vocabulary', 'Pronunciation'] }] }, tags: ['language', 'learning', 'tutor'], totalRuns: 12345, starsCount: 876 }, + + // ============ CREATIVE (6 more) ============ + { slug: 'character-creator', title: 'Character Creator', description: 'Create detailed fictional characters.', category: 'Creative', template: 'Create a character for {{genre}} fiction:\n\nRole: {{role}}\nPersonality: {{personality}}\nBackground: {{background}}\n\nInclude appearance, motivation, flaws, and quirks.', schema: { variables: [{ name: 'genre', type: 'dropdown', label: 'Genre', options: ['Fantasy', 'Sci-Fi', 'Mystery', 'Romance', 'Horror', 'Literary'], required: true }, { name: 'role', type: 'text', label: 'Character Role', placeholder: 'e.g., protagonist, villain' }, { name: 'personality', type: 'text', label: 'Personality Traits' }, { name: 'background', type: 'text', label: 'Background' }] }, tags: ['character', 'fiction', 'writing'], totalRuns: 6543, starsCount: 456 }, + { slug: 'world-builder', title: 'World Builder', description: 'Create detailed fictional worlds.', category: 'Creative', template: 'Build a world for {{genre}} fiction:\n\nSetting: {{setting}}\nMagic/Tech Level: {{tech}}\nKey Features: {{features}}\n\nInclude geography, culture, history, and unique elements.', schema: { variables: [{ name: 'genre', type: 'dropdown', label: 'Genre', options: ['Fantasy', 'Sci-Fi', 'Post-Apocalyptic', 'Steampunk', 'Urban Fantasy'], required: true }, { name: 'setting', type: 'text', label: 'Basic Setting', placeholder: 'e.g., floating cities' }, { name: 'tech', type: 'dropdown', label: 'Tech/Magic Level', options: ['Low', 'Medium', 'High', 'Mixed'] }, { name: 'features', type: 'textarea', label: 'Key Features' }] }, tags: ['worldbuilding', 'fiction'], totalRuns: 4567, starsCount: 345 }, + { slug: 'poetry-generator', title: 'Poetry Generator', description: 'Write poems in various styles.', category: 'Creative', template: 'Write a {{style}} poem about:\n\n{{topic}}\n\nMood: {{mood}}\nLength: {{length}}\n\nInclude vivid imagery and emotion.', schema: { variables: [{ name: 'style', type: 'dropdown', label: 'Style', options: ['Free Verse', 'Sonnet', 'Haiku', 'Limerick', 'Ballad', 'Ode'], required: true }, { name: 'topic', type: 'text', label: 'Topic/Theme', required: true }, { name: 'mood', type: 'dropdown', label: 'Mood', options: ['Happy', 'Sad', 'Romantic', 'Angry', 'Peaceful', 'Dark'] }, { name: 'length', type: 'dropdown', label: 'Length', options: ['Short', 'Medium', 'Long'] }] }, tags: ['poetry', 'creative-writing'], totalRuns: 5678, starsCount: 432 }, + { slug: 'dialogue-writer', title: 'Dialogue Writer', description: 'Write realistic dialogue between characters.', category: 'Creative', template: 'Write dialogue between:\n\nCharacter 1: {{char1}}\nCharacter 2: {{char2}}\nSituation: {{situation}}\nTone: {{tone}}\n\nMake it natural and reveal character.', schema: { variables: [{ name: 'char1', type: 'text', label: 'Character 1', required: true }, { name: 'char2', type: 'text', label: 'Character 2', required: true }, { name: 'situation', type: 'textarea', label: 'Situation/Context' }, { name: 'tone', type: 'dropdown', label: 'Tone', options: ['Serious', 'Humorous', 'Tense', 'Romantic', 'Casual'] }] }, tags: ['dialogue', 'screenplay'], totalRuns: 4567, starsCount: 345 }, + { slug: 'plot-twist', title: 'Plot Twist Generator', description: 'Generate surprising plot twists.', category: 'Creative', template: 'Generate plot twists for:\n\nGenre: {{genre}}\nCurrent Setup: {{setup}}\nCharacters: {{characters}}\n\nProvide 5 plot twist ideas from subtle to shocking.', schema: { variables: [{ name: 'genre', type: 'dropdown', label: 'Genre', options: ['Mystery', 'Thriller', 'Fantasy', 'Romance', 'Horror', 'Drama'], required: true }, { name: 'setup', type: 'textarea', label: 'Current Plot Setup', required: true }, { name: 'characters', type: 'textarea', label: 'Main Characters' }] }, tags: ['plot', 'storytelling'], totalRuns: 3456, starsCount: 234 }, + { slug: 'name-generator', title: 'Character Name Generator', description: 'Generate character names for any setting.', category: 'Creative', template: 'Generate {{count}} names for:\n\nSetting: {{setting}}\nGender: {{gender}}\nVibe: {{vibe}}\n\nInclude meaning or origin if relevant.', schema: { variables: [{ name: 'count', type: 'dropdown', label: 'Number of Names', options: ['5', '10', '20'], required: true }, { name: 'setting', type: 'dropdown', label: 'Setting', options: ['Fantasy', 'Sci-Fi', 'Historical', 'Modern', 'Mythological'] }, { name: 'gender', type: 'dropdown', label: 'Gender', options: ['Male', 'Female', 'Neutral', 'Mixed'] }, { name: 'vibe', type: 'text', label: 'Vibe/Feeling', placeholder: 'e.g., elegant, fierce, mysterious' }] }, tags: ['names', 'fantasy', 'characters'], totalRuns: 8765, starsCount: 654 }, + + // ============ RESEARCH (2 more) ============ + { slug: 'literature-review', title: 'Literature Review Helper', description: 'Structure and write literature reviews.', category: 'Research', template: 'Help write a literature review on:\n\nTopic: {{topic}}\nField: {{field}}\nSources Summary: {{sources}}\n\nOrganize thematically with synthesis and gaps.', schema: { variables: [{ name: 'topic', type: 'text', label: 'Research Topic', required: true }, { name: 'field', type: 'text', label: 'Academic Field' }, { name: 'sources', type: 'textarea', label: 'Brief Summary of Sources' }] }, tags: ['literature-review', 'academic'], totalRuns: 3456, starsCount: 234 }, + { slug: 'hypothesis-generator', title: 'Research Hypothesis Generator', description: 'Generate testable research hypotheses.', category: 'Research', template: 'Generate research hypotheses for:\n\nResearch Question: {{question}}\nField: {{field}}\nVariables: {{variables}}\n\nInclude null and alternative hypotheses with rationale.', schema: { variables: [{ name: 'question', type: 'textarea', label: 'Research Question', required: true }, { name: 'field', type: 'text', label: 'Research Field' }, { name: 'variables', type: 'textarea', label: 'Key Variables' }] }, tags: ['hypothesis', 'research-methods'], totalRuns: 2345, starsCount: 187 }, +] + +async function seedMore() { + console.log('๐ŸŒฑ Adding 50 more prompts...\n') + + let created = 0 + let skipped = 0 + + for (const prompt of morePrompts) { + const existing = await prisma.prompt.findUnique({ + where: { slug: prompt.slug }, + }) + + if (existing) { + console.log(` โญ๏ธ Skipping "${prompt.title}"`) + skipped++ + continue + } + + await prisma.prompt.create({ + data: { + slug: prompt.slug, + title: prompt.title, + description: prompt.description, + template: prompt.template, + schema: prompt.schema, + category: prompt.category, + tags: prompt.tags, + totalRuns: prompt.totalRuns, + starsCount: prompt.starsCount, + remixesCount: 0, + modelDefault: 'gpt-4o-mini', + modelAllowed: ['gpt-4o-mini', 'gpt-4o', 'claude-3-5-sonnet'], + visibility: 'public', + }, + }) + console.log(` โœ… Created "${prompt.title}" [${prompt.category}]`) + created++ + } + + console.log(`\nโœจ Done! Created ${created} prompts, skipped ${skipped}`) +} + +seedMore() + .catch((e) => { + console.error('โŒ Seeding failed:', e) + process.exit(1) + }) + .finally(async () => { + await prisma.$disconnect() + await pool.end() + }) diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000000000000000000000000000000000000..598d400f29fa2be8c8e52e372b93cddda05fb76f --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,644 @@ +import { Pool } from 'pg' +import { PrismaPg } from '@prisma/adapter-pg' +import { PrismaClient } from '@prisma/client' +import 'dotenv/config' + +const connectionString = process.env.DATABASE_URL +if (!connectionString) { + throw new Error('DATABASE_URL not set') +} + +const pool = new Pool({ connectionString }) +const adapter = new PrismaPg(pool) +const prisma = new PrismaClient({ adapter }) + +const seedPrompts = [ + // ============ CONTENT ============ + { + slug: 'blog-writer-pro', + title: 'AI Blog Writer Pro', + description: 'Generate SEO-optimized, engaging blog posts on any topic with customizable tone and length.', + template: `Write a comprehensive blog post about {{topic}}. + +Tone: {{tone}} +Target Length: {{length}} words +Target Audience: {{audience}} + +Requirements: +- Write an attention-grabbing headline +- Include an engaging introduction that hooks the reader +- Cover 3-5 main points with detailed explanations +- Use subheadings for better readability +- Include relevant examples or case studies +- End with a strong conclusion and call-to-action +- Optimize for SEO with natural keyword usage`, + schema: { + variables: [ + { name: 'topic', type: 'text', label: 'Blog Topic', placeholder: 'e.g., The Future of AI in Healthcare', required: true }, + { name: 'tone', type: 'dropdown', label: 'Writing Tone', options: ['Professional', 'Casual', 'Humorous', 'Academic', 'Inspirational'], default: 'Professional' }, + { name: 'length', type: 'dropdown', label: 'Target Length (words)', options: ['500', '1000', '1500', '2000'], default: '1000' }, + { name: 'audience', type: 'text', label: 'Target Audience', placeholder: 'e.g., Tech professionals', default: 'General audience' }, + ], + }, + category: 'Content', + tags: ['blog', 'writing', 'seo', 'content-marketing'], + totalRuns: 12453, + starsCount: 892, + }, + { + slug: 'twitter-thread-generator', + title: 'Viral Twitter Thread Generator', + description: 'Create engaging Twitter/X threads that get likes and retweets.', + template: `Create a viral Twitter thread about {{topic}}. + +Style: {{style}} +Number of tweets: {{count}} +Call-to-action: {{cta}} + +Each tweet should: +- Start with a hook +- Be under 280 characters +- Use emojis strategically +- End with engagement prompts + +Format as: +๐Ÿงต 1/{{count}} +[Tweet content] + +Continue for all tweets.`, + schema: { + variables: [ + { name: 'topic', type: 'text', label: 'Thread Topic', placeholder: 'e.g., 10 AI tools that will 10x your productivity', required: true }, + { name: 'style', type: 'dropdown', label: 'Style', options: ['Educational', 'Storytelling', 'Tips & Tricks', 'Hot Take', 'Thread of Resources'] }, + { name: 'count', type: 'dropdown', label: 'Number of Tweets', options: ['5', '7', '10', '15'], default: '10' }, + { name: 'cta', type: 'text', label: 'Call-to-Action', placeholder: 'e.g., Follow for more AI tips', default: 'Like & Retweet if helpful!' }, + ], + }, + category: 'Content', + tags: ['twitter', 'social-media', 'viral', 'threads'], + totalRuns: 8234, + starsCount: 567, + }, + { + slug: 'youtube-script-writer', + title: 'YouTube Video Script Writer', + description: 'Create engaging YouTube scripts with hooks, chapters, and CTAs.', + template: `Write a YouTube video script about {{topic}}. + +Video Length: {{length}} minutes +Style: {{style}} +Target Audience: {{audience}} + +Include: +1. **HOOK** (First 30 seconds) - Grab attention immediately +2. **INTRO** - Brief channel intro and video overview +3. **MAIN CONTENT** - Divided into timestamped chapters +4. **EXAMPLES** - Real-world examples or demonstrations +5. **OUTRO** - Summary + CTA (like, subscribe, comment) + +Format with timestamps like: +[0:00] Hook +[0:30] Intro +...`, + schema: { + variables: [ + { name: 'topic', type: 'text', label: 'Video Topic', placeholder: 'e.g., How to build a SaaS in 30 days', required: true }, + { name: 'length', type: 'dropdown', label: 'Video Length', options: ['5', '10', '15', '20'], default: '10' }, + { name: 'style', type: 'dropdown', label: 'Content Style', options: ['Tutorial', 'Review', 'Commentary', 'Story', 'Listicle'] }, + { name: 'audience', type: 'text', label: 'Target Audience', placeholder: 'e.g., Beginner developers' }, + ], + }, + category: 'Content', + tags: ['youtube', 'video', 'script', 'content-creation'], + totalRuns: 6789, + starsCount: 445, + }, + + // ============ DEVELOPMENT ============ + { + slug: 'code-review-assistant', + title: 'Senior Dev Code Review', + description: 'Get detailed, constructive code reviews like from a senior developer.', + template: `Act as a senior software engineer doing a thorough code review. + +Language: {{language}} + +\`\`\`{{language}} +{{code}} +\`\`\` + +Provide your review with: + +## ๐Ÿ“Š Overall Assessment +Brief quality rating and summary + +## โœ… What's Good +Highlight good practices + +## ๐Ÿšจ Critical Issues +Security vulnerabilities, bugs, performance issues + +## โš ๏ธ Suggestions +Code improvements and best practices + +## ๐Ÿ”ง Refactored Code +Show the improved version with comments`, + schema: { + variables: [ + { name: 'language', type: 'dropdown', label: 'Language', options: ['JavaScript', 'TypeScript', 'Python', 'Java', 'Go', 'Rust', 'C++', 'C#'], default: 'TypeScript', required: true }, + { name: 'code', type: 'textarea', label: 'Code to Review', placeholder: 'Paste your code here...', required: true }, + ], + }, + category: 'Development', + tags: ['code-review', 'programming', 'best-practices'], + totalRuns: 15672, + starsCount: 1024, + }, + { + slug: 'regex-generator', + title: 'Regex Pattern Generator', + description: 'Generate and explain regex patterns for any use case.', + template: `Create a regex pattern for: {{description}} + +Language/Tool: {{language}} + +Please provide: + +1. **The Regex Pattern** +\`\`\` +[pattern here] +\`\`\` + +2. **Explanation** +Break down each part of the regex + +3. **Test Cases** +- โœ… Should match: [examples] +- โŒ Should NOT match: [examples] + +4. **Code Example** +Show how to use it in {{language}} + +5. **Common Variations** +Any alternative patterns for edge cases`, + schema: { + variables: [ + { name: 'description', type: 'textarea', label: 'What should the regex match?', placeholder: 'e.g., Email addresses with common domains only', required: true }, + { name: 'language', type: 'dropdown', label: 'Language/Tool', options: ['JavaScript', 'Python', 'Java', 'PHP', 'Go', 'grep', 'sed'], default: 'JavaScript' }, + ], + }, + category: 'Development', + tags: ['regex', 'programming', 'patterns'], + totalRuns: 9876, + starsCount: 678, + }, + { + slug: 'api-documentation', + title: 'API Documentation Generator', + description: 'Generate comprehensive API documentation from code or descriptions.', + template: `Generate professional API documentation for: + +{{api_description}} + +Format: {{format}} + +Include: +- **Endpoint Overview** +- **Authentication** requirements +- **Request** (method, URL, headers, body with types) +- **Response** (success and error responses with examples) +- **Code Examples** in {{languages}} +- **Rate Limits** and error handling +- **Changelog** section`, + schema: { + variables: [ + { name: 'api_description', type: 'textarea', label: 'API Description or Code', placeholder: 'Describe your API endpoints or paste code...', required: true }, + { name: 'format', type: 'dropdown', label: 'Documentation Format', options: ['OpenAPI/Swagger', 'Markdown', 'REST API Blueprint', 'Postman Collection'], default: 'Markdown' }, + { name: 'languages', type: 'text', label: 'Code Example Languages', placeholder: 'e.g., JavaScript, Python, cURL', default: 'JavaScript, Python, cURL' }, + ], + }, + category: 'Development', + tags: ['api', 'documentation', 'swagger', 'developer-tools'], + totalRuns: 5432, + starsCount: 389, + }, + + // ============ MARKETING ============ + { + slug: 'landing-page-copy', + title: 'High-Converting Landing Page Copy', + description: 'Generate landing page copy that converts visitors into customers.', + template: `Create high-converting landing page copy for: + +Product/Service: {{product}} +Target Audience: {{audience}} +Unique Value: {{uvp}} +Key Benefits: {{benefits}} + +Generate: + +# ๐ŸŽฏ HERO SECTION +- Headline (max 10 words, powerful) +- Subheadline (expand the promise) +- CTA button text + +# ๐Ÿ˜ฐ PROBLEM SECTION +Pain points your audience faces + +# โœจ SOLUTION SECTION +How you solve it + +# ๐Ÿ’Ž BENEFITS (not features) +3-4 benefit blocks with icons + +# ๐Ÿ† SOCIAL PROOF +Testimonial templates and stats placement + +# ๐Ÿš€ FINAL CTA +Urgency-driven closing`, + schema: { + variables: [ + { name: 'product', type: 'text', label: 'Product/Service', placeholder: 'e.g., CloudSync - AI-Powered Note Taking', required: true }, + { name: 'audience', type: 'text', label: 'Target Audience', placeholder: 'e.g., Busy professionals who take lots of notes', required: true }, + { name: 'uvp', type: 'textarea', label: 'Unique Value Proposition', placeholder: 'What makes you different?', required: true }, + { name: 'benefits', type: 'textarea', label: 'Key Benefits', placeholder: 'List 3-5 main benefits' }, + ], + }, + category: 'Marketing', + tags: ['copywriting', 'landing-page', 'conversion'], + totalRuns: 11234, + starsCount: 876, + }, + { + slug: 'ad-copy-generator', + title: 'Facebook/Google Ad Copy', + description: 'Create high-CTR ad copy for paid campaigns.', + template: `Create {{platform}} ad copy for: + +Product: {{product}} +Target Audience: {{audience}} +Offer: {{offer}} +Tone: {{tone}} + +Generate 5 variations of: +- **Headline** ({{platform}} character limit) +- **Description** +- **Call-to-Action** + +For each variation, include: +- ๐Ÿ“Š Estimated CTR potential +- ๐ŸŽฏ Best audience type +- ๐Ÿ’ก A/B testing suggestion`, + schema: { + variables: [ + { name: 'platform', type: 'dropdown', label: 'Platform', options: ['Facebook/Instagram', 'Google Ads', 'LinkedIn', 'TikTok'], default: 'Facebook/Instagram', required: true }, + { name: 'product', type: 'text', label: 'Product/Service', placeholder: 'e.g., Online Fitness Coaching', required: true }, + { name: 'audience', type: 'text', label: 'Target Audience', placeholder: 'e.g., Women 25-45 interested in weight loss' }, + { name: 'offer', type: 'text', label: 'Offer/Discount', placeholder: 'e.g., 50% off first month' }, + { name: 'tone', type: 'dropdown', label: 'Tone', options: ['Professional', 'Friendly', 'Urgent', 'Playful', 'Luxury'], default: 'Friendly' }, + ], + }, + category: 'Marketing', + tags: ['ads', 'facebook', 'google-ads', 'copywriting'], + totalRuns: 8765, + starsCount: 654, + }, + + // ============ BUSINESS ============ + { + slug: 'professional-email', + title: 'Professional Email Composer', + description: 'Write perfect professional emails for any situation.', + template: `Write a professional email for: + +Purpose: {{purpose}} +Recipient: {{recipient}} +Key Points: {{key_points}} +Tone: {{tone}} + +Include: +- Appropriate subject line +- Professional greeting +- Clear, concise body +- Specific call-to-action +- Professional sign-off + +Context: {{context}}`, + schema: { + variables: [ + { name: 'purpose', type: 'dropdown', label: 'Email Purpose', options: ['Follow-up', 'Cold Outreach', 'Thank You', 'Request', 'Apology', 'Announcement', 'Negotiation', 'Introduction'], required: true }, + { name: 'recipient', type: 'text', label: 'Recipient', placeholder: 'e.g., Hiring Manager at Google', required: true }, + { name: 'key_points', type: 'textarea', label: 'Key Points', placeholder: 'What do you need to communicate?', required: true }, + { name: 'tone', type: 'dropdown', label: 'Tone', options: ['Formal', 'Friendly Professional', 'Casual', 'Urgent'], default: 'Friendly Professional' }, + { name: 'context', type: 'textarea', label: 'Additional Context', placeholder: 'Any relevant background...' }, + ], + }, + category: 'Business', + tags: ['email', 'professional', 'communication'], + totalRuns: 18234, + starsCount: 1234, + }, + { + slug: 'business-proposal', + title: 'Business Proposal Generator', + description: 'Create compelling business proposals that win clients.', + template: `Create a professional business proposal for: + +Client: {{client}} +Project: {{project}} +Budget Range: {{budget}} +Timeline: {{timeline}} + +Include these sections: + +1. **Executive Summary** +2. **Understanding of Needs** +3. **Proposed Solution** +4. **Scope of Work** (detailed deliverables) +5. **Timeline & Milestones** +6. **Investment** (pricing breakdown) +7. **About Us** +8. **Next Steps**`, + schema: { + variables: [ + { name: 'client', type: 'text', label: 'Client Name/Company', placeholder: 'e.g., Acme Corporation', required: true }, + { name: 'project', type: 'textarea', label: 'Project Description', placeholder: 'Describe the project...', required: true }, + { name: 'budget', type: 'text', label: 'Budget Range', placeholder: 'e.g., $5,000 - $10,000' }, + { name: 'timeline', type: 'text', label: 'Timeline', placeholder: 'e.g., 4-6 weeks' }, + ], + }, + category: 'Business', + tags: ['proposal', 'business', 'sales', 'client'], + totalRuns: 6543, + starsCount: 456, + }, + + // ============ EDUCATION ============ + { + slug: 'lesson-plan-creator', + title: 'AI Lesson Plan Creator', + description: 'Create comprehensive lesson plans for any subject and grade level.', + template: `Create a detailed lesson plan for: + +Subject: {{subject}} +Topic: {{topic}} +Grade Level: {{grade}} +Duration: {{duration}} minutes + +Include: +1. **Learning Objectives** (3-5 measurable goals) +2. **Materials Needed** +3. **Warm-Up Activity** (5-10 min) +4. **Main Instruction** (step-by-step) +5. **Guided Practice** +6. **Independent Practice** +7. **Assessment** (formative/summative) +8. **Differentiation** (for different learners) +9. **Homework/Extension**`, + schema: { + variables: [ + { name: 'subject', type: 'dropdown', label: 'Subject', options: ['Math', 'Science', 'English', 'History', 'Art', 'Music', 'Computer Science', 'Physical Education'], required: true }, + { name: 'topic', type: 'text', label: 'Topic', placeholder: 'e.g., Introduction to Fractions', required: true }, + { name: 'grade', type: 'dropdown', label: 'Grade Level', options: ['K-2', '3-5', '6-8', '9-12', 'College', 'Adult'], default: '6-8' }, + { name: 'duration', type: 'dropdown', label: 'Duration (minutes)', options: ['30', '45', '60', '90'], default: '45' }, + ], + }, + category: 'Education', + tags: ['lesson-plan', 'teaching', 'education'], + totalRuns: 7654, + starsCount: 543, + }, + { + slug: 'explain-like-im-5', + title: 'Explain Like I\'m 5', + description: 'Break down complex topics into simple, fun explanations.', + template: `Explain {{topic}} like I'm {{age}} years old. + +Use: +- Simple words +- Fun analogies (like games, toys, food) +- Short sentences +- Emojis where appropriate +- A fun example at the end + +Topic complexity: {{complexity}} + +Make it engaging and memorable!`, + schema: { + variables: [ + { name: 'topic', type: 'text', label: 'Topic to Explain', placeholder: 'e.g., How does WiFi work?', required: true }, + { name: 'age', type: 'dropdown', label: 'Target Age', options: ['5', '8', '10', '12', '15'], default: '5' }, + { name: 'complexity', type: 'dropdown', label: 'Original Complexity', options: ['Simple', 'Moderate', 'Complex', 'Expert-level'], default: 'Complex' }, + ], + }, + category: 'Education', + tags: ['learning', 'simple', 'explanation', 'eli5'], + totalRuns: 12345, + starsCount: 876, + }, + + // ============ CREATIVE ============ + { + slug: 'story-generator', + title: 'Creative Story Generator', + description: 'Generate creative stories in any genre with compelling characters.', + template: `Write a {{genre}} story with: + +Main Character: {{character}} +Setting: {{setting}} +Conflict: {{conflict}} +Length: {{length}} +Tone: {{tone}} + +Include: +- Vivid descriptions +- Dialogue +- Character development +- Satisfying resolution`, + schema: { + variables: [ + { name: 'genre', type: 'dropdown', label: 'Genre', options: ['Fantasy', 'Sci-Fi', 'Romance', 'Mystery', 'Horror', 'Adventure', 'Comedy', 'Drama'], required: true }, + { name: 'character', type: 'text', label: 'Main Character', placeholder: 'e.g., A time-traveling librarian', required: true }, + { name: 'setting', type: 'text', label: 'Setting', placeholder: 'e.g., Victorian London' }, + { name: 'conflict', type: 'text', label: 'Central Conflict', placeholder: 'e.g., Must prevent a paradox' }, + { name: 'length', type: 'dropdown', label: 'Length', options: ['Flash Fiction (500 words)', 'Short Story (1500 words)', 'Long Story (3000 words)'], default: 'Short Story (1500 words)' }, + { name: 'tone', type: 'dropdown', label: 'Tone', options: ['Light & Fun', 'Dark & Serious', 'Suspenseful', 'Heartwarming'], default: 'Light & Fun' }, + ], + }, + category: 'Creative', + tags: ['story', 'fiction', 'creative-writing'], + totalRuns: 9876, + starsCount: 765, + }, + { + slug: 'song-lyrics-writer', + title: 'Song Lyrics Writer', + description: 'Create original song lyrics in any genre with custom themes.', + template: `Write song lyrics about {{theme}}. + +Genre: {{genre}} +Mood: {{mood}} +Structure: {{structure}} + +Include: +- Verse 1 +- Chorus +- Verse 2 +- Chorus +- Bridge +- Final Chorus + +Make it catchy, emotional, and singable!`, + schema: { + variables: [ + { name: 'theme', type: 'text', label: 'Song Theme', placeholder: 'e.g., Overcoming heartbreak', required: true }, + { name: 'genre', type: 'dropdown', label: 'Genre', options: ['Pop', 'Rock', 'Hip-Hop', 'Country', 'R&B', 'Indie', 'EDM'], default: 'Pop' }, + { name: 'mood', type: 'dropdown', label: 'Mood', options: ['Happy', 'Sad', 'Empowering', 'Romantic', 'Angry', 'Nostalgic'], default: 'Empowering' }, + { name: 'structure', type: 'dropdown', label: 'Structure', options: ['Standard', 'Extended', 'Minimal'], default: 'Standard' }, + ], + }, + category: 'Creative', + tags: ['music', 'lyrics', 'songwriting'], + totalRuns: 5678, + starsCount: 432, + }, + + // ============ RESEARCH ============ + { + slug: 'research-summarizer', + title: 'Research Paper Summarizer', + description: 'Summarize academic papers and research into digestible insights.', + template: `Summarize this research: + +{{content}} + +Provide: + +## ๐Ÿ“‹ TL;DR +One paragraph summary + +## ๐ŸŽฏ Key Findings +Bullet points of main discoveries + +## ๐Ÿ”ฌ Methodology +How the research was conducted + +## ๐Ÿ“Š Data & Results +Key statistics and outcomes + +## ๐Ÿ’ก Implications +What this means for {{field}} + +## โ“ Limitations +Study limitations and gaps + +## ๐Ÿ“š Citation +Proper academic citation format`, + schema: { + variables: [ + { name: 'content', type: 'textarea', label: 'Paste Research Content', placeholder: 'Paste the abstract, paper, or research text...', required: true }, + { name: 'field', type: 'text', label: 'Research Field', placeholder: 'e.g., Machine Learning, Medicine', default: 'the field' }, + ], + }, + category: 'Research', + tags: ['research', 'academic', 'summary', 'papers'], + totalRuns: 4567, + starsCount: 345, + }, + { + slug: 'fact-checker', + title: 'AI Fact Checker', + description: 'Verify claims and get evidence-based analysis.', + template: `Analyze this claim for accuracy: + +Claim: "{{claim}}" + +Provide: + +## ๐Ÿ“Š Verdict +[TRUE / MOSTLY TRUE / MIXED / MOSTLY FALSE / FALSE] + +## ๐Ÿ” Analysis +Detailed breakdown of the claim + +## ๐Ÿ“š Evidence +Supporting or refuting evidence + +## ๐ŸŒ Sources +Where to verify (types of sources to check) + +## โš ๏ธ Context +Important context that affects accuracy + +## ๐ŸŽฏ Bottom Line +One sentence summary`, + schema: { + variables: [ + { name: 'claim', type: 'textarea', label: 'Claim to Check', placeholder: 'e.g., Drinking 8 glasses of water a day is necessary for health', required: true }, + ], + }, + category: 'Research', + tags: ['fact-check', 'verification', 'research'], + totalRuns: 3456, + starsCount: 234, + }, +] + +async function seed() { + console.log('๐ŸŒฑ Seeding database with awesome prompts...\n') + + let created = 0 + let skipped = 0 + + for (const prompt of seedPrompts) { + const existing = await prisma.prompt.findUnique({ + where: { slug: prompt.slug }, + }) + + if (existing) { + console.log(` โญ๏ธ Skipping "${prompt.title}" (already exists)`) + skipped++ + continue + } + + await prisma.prompt.create({ + data: { + slug: prompt.slug, + title: prompt.title, + description: prompt.description, + template: prompt.template, + schema: prompt.schema, + category: prompt.category, + tags: prompt.tags, + totalRuns: prompt.totalRuns, + starsCount: prompt.starsCount, + remixesCount: 0, + modelDefault: 'gpt-4o-mini', + modelAllowed: ['gpt-4o-mini', 'gpt-4o', 'claude-3-5-sonnet'], + visibility: 'public', + }, + }) + console.log(` โœ… Created "${prompt.title}" [${prompt.category}]`) + created++ + } + + console.log(`\nโœจ Done! Created ${created} prompts, skipped ${skipped}`) + console.log('\n๐Ÿ“Š Prompts by category:') + console.log(' โ€ข Content: 3') + console.log(' โ€ข Development: 3') + console.log(' โ€ข Marketing: 2') + console.log(' โ€ข Business: 2') + console.log(' โ€ข Education: 2') + console.log(' โ€ข Creative: 2') + console.log(' โ€ข Research: 2') +} + +seed() + .catch((e) => { + console.error('โŒ Seeding failed:', e) + process.exit(1) + }) + .finally(async () => { + await prisma.$disconnect() + await pool.end() + }) diff --git a/prisma/tool-models.txt b/prisma/tool-models.txt new file mode 100644 index 0000000000000000000000000000000000000000..632515a53bebc5f0aa16e0b5451dde0c94f0a695 --- /dev/null +++ b/prisma/tool-models.txt @@ -0,0 +1,43 @@ + +// AI Tools System +model Tool { + id String @id @default(cuid()) + slug String @unique + name String + description String + category String // "prompting", "marketing", "branding", etc. + icon String? // Emoji or icon name + isActive Boolean @default(true) + isPremium Boolean @default(false) + + // Tool configuration + inputSchema Json // { fields: [{name, type, label, placeholder}] } + systemPrompt String @db.Text // The AI prompt template + model String @default("gpt-4o-mini") // AI model to use + + // Stats + usageCount Int @default(0) + + executions ToolExecution[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([category]) + @@index([slug]) +} + +model ToolExecution { + id String @id @default(cuid()) + toolId String + tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade) + userId String? + + inputs Json // User's inputs + output String @db.Text // AI-generated output + + createdAt DateTime @default(now()) + + @@index([toolId]) + @@index([userId]) +} diff --git a/prisma/update-models.ts b/prisma/update-models.ts new file mode 100644 index 0000000000000000000000000000000000000000..8518bad0aa4874c0e7c7675a0748c7f4c8ea73fa --- /dev/null +++ b/prisma/update-models.ts @@ -0,0 +1,34 @@ +import { Pool } from 'pg' +import { PrismaPg } from '@prisma/adapter-pg' +import { PrismaClient } from '@prisma/client' +import 'dotenv/config' + +const connectionString = process.env.DATABASE_URL +if (!connectionString) throw new Error('DATABASE_URL not set') + +const pool = new Pool({ connectionString }) +const adapter = new PrismaPg(pool) +const prisma = new PrismaClient({ adapter }) + +async function updateToGemini() { + console.log('๐Ÿ”„ Updating all prompts to use Gemini 2.5 Flash as default...\n') + + const result = await prisma.prompt.updateMany({ + data: { + modelDefault: 'gemini-2.5-flash', + modelAllowed: ['gemini-2.5-flash', 'gemini-2.0-flash', 'gpt-4o-mini', 'gpt-4o', 'claude-3-5-sonnet'], + }, + }) + + console.log(`โœ… Updated ${result.count} prompts to use Gemini 2.5 Flash!`) +} + +updateToGemini() + .catch((e) => { + console.error('โŒ Update failed:', e) + process.exit(1) + }) + .finally(async () => { + await prisma.$disconnect() + await pool.end() + }) diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..bdf7a0c328bb1ca0a62bd2a52620ba9e536acf99 --- /dev/null +++ b/public/favicon.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e64d99b64c8f1d377f25e88d46da1c3ec52df30404aab339e92659b3f6cb7846 +size 1407 diff --git a/public/file.svg b/public/file.svg new file mode 100644 index 0000000000000000000000000000000000000000..004145cddf3f9db91b57b9cb596683c8eb420862 --- /dev/null +++ b/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg new file mode 100644 index 0000000000000000000000000000000000000000..567f17b0d7c7fb662c16d4357dd74830caf2dccb --- /dev/null +++ b/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/google60f35921954050fd.html b/public/google60f35921954050fd.html new file mode 100644 index 0000000000000000000000000000000000000000..0803197a75b459b21443b08f3ca4a2642ee943f7 --- /dev/null +++ b/public/google60f35921954050fd.html @@ -0,0 +1 @@ +google-site-verification: google60f35921954050fd.html diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bbacc92147bf6c4fa111d972da7b2328b7662269 --- /dev/null +++ b/public/icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:342e2f56280bb12d8f88a4dd2f5ec651cd3e15ba32e94dc3faa8d24256f0da04 +size 35255 diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..39f202a282a1a6c1c079715700e7b497f22853dc --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/logos/icon.png b/public/logos/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bbacc92147bf6c4fa111d972da7b2328b7662269 --- /dev/null +++ b/public/logos/icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:342e2f56280bb12d8f88a4dd2f5ec651cd3e15ba32e94dc3faa8d24256f0da04 +size 35255 diff --git a/public/logos/logo.svg b/public/logos/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..39f202a282a1a6c1c079715700e7b497f22853dc --- /dev/null +++ b/public/logos/logo.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..cb221eaf97a53bdff3c173867b5936bac6521295 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,61 @@ +{ + "name": "OpenPrompt", + "short_name": "OpenPrompt", + "description": "The GitHub for AI Prompts - Transform AI prompts into shareable micro-apps", + "start_url": "/", + "display": "standalone", + "background_color": "#0d1117", + "theme_color": "#6366f1", + "orientation": "portrait-primary", + "icons": [ + { + "src": "/logos/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/logos/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/logos/icon.png", + "sizes": "180x180", + "type": "image/png" + }, + { + "src": "/logos/logo.svg", + "sizes": "any", + "type": "image/svg+xml" + } + ], + "categories": ["productivity", "utilities", "developer tools"], + "screenshots": [], + "shortcuts": [ + { + "name": "Explore Prompts", + "short_name": "Explore", + "description": "Browse AI prompts", + "url": "/explore", + "icons": [{ "src": "/logos/icon-192.png", "sizes": "192x192" }] + }, + { + "name": "AI Tools", + "short_name": "Tools", + "description": "177+ AI tools", + "url": "/tools", + "icons": [{ "src": "/logos/icon-192.png", "sizes": "192x192" }] + }, + { + "name": "Create Prompt", + "short_name": "Create", + "description": "Create a new prompt", + "url": "/create", + "icons": [{ "src": "/logos/icon-192.png", "sizes": "192x192" }] + } + ], + "related_applications": [], + "prefer_related_applications": false +} diff --git a/public/window.svg b/public/window.svg new file mode 100644 index 0000000000000000000000000000000000000000..b2b2a44f6ebc70c450043c05a002e7a93ba5d651 --- /dev/null +++ b/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0de03a99fccffed9ad6bc07ef025d297e7e9ef2e --- /dev/null +++ b/src/app/about/page.tsx @@ -0,0 +1,116 @@ +import { Metadata } from "next" +import { Sparkles, Target, Users, Zap, Heart } from "lucide-react" +import Link from "next/link" +import { generateSEO } from "@/lib/seo" + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const metadata: Metadata = generateSEO({ + title: "About OpenPrompt", + description: "Learn about OpenPrompt โ€” the open-source platform to create, share, remix, and run AI prompts as micro-apps. Our mission is to democratize prompt engineering.", + url: `${BASE_URL}/about`, + keywords: ["about OpenPrompt", "AI prompt platform", "open source AI"], +}) as Metadata + +export default function AboutPage() { + return ( +
+ {/* Hero Section */} +
+
+ + About OpenPrompt +
+

+ The GitHub for AI Prompts +

+

+ We're building the world's largest open platform for AI prompts. + Create, share, remix, and run prompts with zero friction. +

+
+ + {/* Mission Section */} +
+
+
+

Our Mission

+

+ AI prompts are the new code. But unlike code, prompts are scattered + across Reddit, Twitter, and Notion documents with no standardization, + versioning, or community. +

+

+ OpenPrompt changes that. We're creating a platform where prompts + become shareable micro-apps that anyone can use, remix, and improve. +

+
+
+ +

+ Democratizing AI +

+

+ Making powerful AI accessible to everyone through + community-curated prompts. +

+
+
+
+ + {/* Values Section */} +
+

Our Values

+
+
+ +

Community First

+

+ Everything we build is for the community. Open source, + transparent, and collaborative. +

+
+
+ +

Zero Friction

+

+ No complex setups. No barriers. Just create and share + prompts instantly. +

+
+
+ +

Quality Matters

+

+ We reward quality with badges, rankings, and visibility. + Great prompts rise to the top. +

+
+
+
+ + {/* CTA Section */} +
+

Join Our Community

+

+ Be part of the future of AI prompts. Start creating, sharing, + and discovering amazing prompts today. +

+
+ + Explore Prompts + + + Create a Prompt + +
+
+
+ ) +} diff --git a/src/app/analytics/layout.tsx b/src/app/analytics/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9e5a10762f50ec9ca614bce7fb89adcb8ecdbb60 --- /dev/null +++ b/src/app/analytics/layout.tsx @@ -0,0 +1,22 @@ +import { Suspense } from "react" +import { Loader2 } from "lucide-react" + +function AnalyticsLoading() { + return ( +
+ +
+ ) +} + +export default function AnalyticsLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + }> + {children} + + ) +} diff --git a/src/app/analytics/page.tsx b/src/app/analytics/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9358b736a8f14f6fc8f4bfb09df70dde11e3f116 --- /dev/null +++ b/src/app/analytics/page.tsx @@ -0,0 +1,119 @@ +import { Metadata } from "next" +import { redirect } from "next/navigation" +import { stackServerApp } from "@/lib/stack-server" +import prisma from "@/lib/prisma" +import { AnalyticsDashboard } from "@/components/analytics/analytics-dashboard" + +export const metadata: Metadata = { + title: "Analytics Dashboard | OpenPrompt", + description: "View your prompt analytics and performance metrics", +} + +export const dynamic = "force-dynamic" + +async function getCreatorAnalytics(userId: string) { + // Get all prompts by this user + const prompts = await prisma.prompt.findMany({ + where: { creatorId: userId }, + select: { + id: true, + title: true, + slug: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + createdAt: true, + }, + orderBy: { totalRuns: "desc" }, + }) + + // Get runs data for the last 30 days + const thirtyDaysAgo = new Date() + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30) + + const runs = await prisma.run.findMany({ + where: { + prompt: { creatorId: userId }, + createdAt: { gte: thirtyDaysAgo }, + }, + select: { + id: true, + model: true, + tokens: true, + createdAt: true, + promptId: true, + }, + orderBy: { createdAt: "desc" }, + }) + + // Aggregate runs by day + const runsByDay: Record = {} + runs.forEach((run: { createdAt: Date }) => { + const day = run.createdAt.toISOString().split("T")[0] + runsByDay[day] = (runsByDay[day] || 0) + 1 + }) + + // Prepare daily data for chart + const dailyData = [] + for (let i = 29; i >= 0; i--) { + const date = new Date() + date.setDate(date.getDate() - i) + const dateStr = date.toISOString().split("T")[0] + dailyData.push({ + date: dateStr, + runs: runsByDay[dateStr] || 0, + }) + } + + // Model usage stats + const modelUsage: Record = {} + runs.forEach((run: { model: string }) => { + modelUsage[run.model] = (modelUsage[run.model] || 0) + 1 + }) + + // Total tokens used + const totalTokens = runs.reduce((sum: number, run: { tokens: number | null }) => sum + (run.tokens || 0), 0) + + // Calculate totals + const totalRuns = prompts.reduce((sum: number, p: { totalRuns: number }) => sum + p.totalRuns, 0) + const totalStars = prompts.reduce((sum: number, p: { starsCount: number }) => sum + p.starsCount, 0) + const totalRemixes = prompts.reduce((sum: number, p: { remixesCount: number }) => sum + p.remixesCount, 0) + + return { + prompts, + dailyData, + modelUsage, + totalTokens, + totals: { + runs: totalRuns, + stars: totalStars, + remixes: totalRemixes, + prompts: prompts.length, + }, + } +} + +export default async function AnalyticsPage() { + const user = await stackServerApp.getUser() + + if (!user) { + redirect("/sign-in?returnUrl=/analytics") + } + + const analytics = await getCreatorAnalytics(user.id) + + return ( +
+
+

+ Analytics Dashboard +

+

+ Track your prompts performance and usage metrics +

+
+ + +
+ ) +} diff --git a/src/app/api/analytics/route.ts b/src/app/api/analytics/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ec5ad6ee7496d5190700164892622c54e70a2d7 --- /dev/null +++ b/src/app/api/analytics/route.ts @@ -0,0 +1,181 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" +import { stackServerApp } from "@/lib/stack-server" + +// GET - Get detailed analytics for a creator +export async function GET(request: NextRequest) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Unauthorized" }, + { status: 401 } + ) + } + + const { searchParams } = new URL(request.url) + const days = parseInt(searchParams.get("days") || "30") + + const daysAgo = new Date() + daysAgo.setDate(daysAgo.getDate() - days) + + // Get all prompts by this user + const prompts = await prisma.prompt.findMany({ + where: { creatorId: user.id }, + select: { + id: true, + title: true, + slug: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + framework: true, + badges: true, + parentId: true, + createdAt: true, + }, + orderBy: { totalRuns: "desc" }, + }) + + // Get runs data for the period + const runs = await prisma.run.findMany({ + where: { + prompt: { creatorId: user.id }, + createdAt: { gte: daysAgo }, + }, + select: { + id: true, + model: true, + tokens: true, + cached: true, + createdAt: true, + promptId: true, + }, + orderBy: { createdAt: "desc" }, + }) + + // Get engagement metrics (errors tracked separately) + const engagementMetrics = await prisma.engagementMetric.findMany({ + where: { + targetType: "prompt", + targetId: { in: prompts.map(p => p.id) }, + createdAt: { gte: daysAgo }, + }, + select: { + action: true, + createdAt: true, + targetId: true, + } + }) + + // Aggregate runs by day + const runsByDay: Record = {} + runs.forEach(run => { + const day = run.createdAt.toISOString().split("T")[0] + if (!runsByDay[day]) { + runsByDay[day] = { runs: 0, errors: 0, tokens: 0 } + } + runsByDay[day].runs += 1 + runsByDay[day].tokens += run.tokens || 0 + }) + + // Prepare daily data for chart + const dailyData = [] + for (let i = days - 1; i >= 0; i--) { + const date = new Date() + date.setDate(date.getDate() - i) + const dateStr = date.toISOString().split("T")[0] + const dayData = runsByDay[dateStr] || { runs: 0, errors: 0, tokens: 0 } + dailyData.push({ + date: dateStr, + runs: dayData.runs, + errors: dayData.errors, + tokens: dayData.tokens, + }) + } + + // Model usage stats + const modelUsage: Record = {} + runs.forEach(run => { + if (!modelUsage[run.model]) { + modelUsage[run.model] = { runs: 0, tokens: 0 } + } + modelUsage[run.model].runs += 1 + modelUsage[run.model].tokens += run.tokens || 0 + }) + + // Token usage per prompt + const tokensByPrompt: Record = {} + runs.forEach(run => { + if (!tokensByPrompt[run.promptId]) { + tokensByPrompt[run.promptId] = 0 + } + tokensByPrompt[run.promptId] += run.tokens || 0 + }) + + // Remix traffic - find remixes of user's prompts + const remixTraffic = await prisma.prompt.findMany({ + where: { + parentId: { in: prompts.map(p => p.id) }, + createdAt: { gte: daysAgo }, + }, + select: { + id: true, + title: true, + parentId: true, + totalRuns: true, + createdAt: true, + }, + orderBy: { createdAt: "desc" }, + take: 20, + }) + + // Engagement breakdown + const engagementByAction: Record = {} + engagementMetrics.forEach(metric => { + engagementByAction[metric.action] = (engagementByAction[metric.action] || 0) + 1 + }) + + // Total tokens used + const totalTokens = runs.reduce((sum, run) => sum + (run.tokens || 0), 0) + const cachedRuns = runs.filter(r => r.cached).length + const cacheHitRate = runs.length > 0 ? (cachedRuns / runs.length) * 100 : 0 + + // Calculate totals + const totalRuns = prompts.reduce((sum, p) => sum + p.totalRuns, 0) + const totalStars = prompts.reduce((sum, p) => sum + p.starsCount, 0) + const totalRemixes = prompts.reduce((sum, p) => sum + p.remixesCount, 0) + + // Error rate estimation (based on low token runs which might indicate errors) + const potentialErrors = runs.filter(r => r.tokens !== null && r.tokens < 10).length + const errorRate = runs.length > 0 ? (potentialErrors / runs.length) * 100 : 0 + + return NextResponse.json({ + prompts: prompts.map(p => ({ + ...p, + tokens: tokensByPrompt[p.id] || 0, + })), + dailyData, + modelUsage, + totalTokens, + cacheHitRate, + errorRate, + remixTraffic, + engagementByAction, + totals: { + runs: totalRuns, + stars: totalStars, + remixes: totalRemixes, + prompts: prompts.length, + periodRuns: runs.length, + periodTokens: totalTokens, + }, + }) + } catch (error) { + console.error("Error fetching analytics:", error) + return NextResponse.json( + { error: "Failed to fetch analytics" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/badges/route.ts b/src/app/api/badges/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..2bc1660c5461ca1647ef38ddc9b4825d324f3b1e --- /dev/null +++ b/src/app/api/badges/route.ts @@ -0,0 +1,205 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" + +// Badge types and their criteria +export type BadgeType = + | "verified-quality" // 95%+ success rate + | "framework-compliant" // Uses RACE, CARE, APE, etc. + | "high-performance" // Fast + low token usage + | "community-favorite" // High stars + runs + | "trending" // High recent activity + | "prolific-creator" // Many prompts created + +interface Badge { + type: BadgeType + label: string + description: string + icon: string +} + +const BADGE_DEFINITIONS: Record = { + "verified-quality": { + type: "verified-quality", + label: "Verified Quality", + description: "95%+ success rate", + icon: "โœ“" + }, + "framework-compliant": { + type: "framework-compliant", + label: "Framework Compliant", + description: "Uses structured prompting framework", + icon: "๐Ÿ“" + }, + "high-performance": { + type: "high-performance", + label: "High Performance", + description: "Fast and efficient", + icon: "โšก" + }, + "community-favorite": { + type: "community-favorite", + label: "Community Favorite", + description: "Loved by the community", + icon: "โค๏ธ" + }, + "trending": { + type: "trending", + label: "Trending", + description: "High recent activity", + icon: "๐Ÿ”ฅ" + }, + "prolific-creator": { + type: "prolific-creator", + label: "Prolific Creator", + description: "Created many quality prompts", + icon: "โญ" + } +} + +// Calculate badges for a prompt +export function calculatePromptBadges(prompt: { + totalRuns: number + starsCount: number + remixesCount: number + framework?: string | null + badges?: string[] +}): BadgeType[] { + const badges: BadgeType[] = [] + + // Framework Compliant - has a framework assigned + if (prompt.framework) { + badges.push("framework-compliant") + } + + // Community Favorite - 50+ stars or 1000+ runs + if (prompt.starsCount >= 50 || prompt.totalRuns >= 1000) { + badges.push("community-favorite") + } + + // High Performance - high usage indicates it works well + if (prompt.totalRuns >= 500 && prompt.starsCount >= 20) { + badges.push("high-performance") + } + + // Trending - high recent activity (approximated by total stats) + if (prompt.totalRuns >= 100 && prompt.remixesCount >= 5) { + badges.push("trending") + } + + // Verified Quality - good star-to-run ratio + const starRatio = prompt.totalRuns > 0 ? prompt.starsCount / prompt.totalRuns : 0 + if (starRatio >= 0.1 && prompt.totalRuns >= 50) { + badges.push("verified-quality") + } + + return badges +} + +// GET - Get badges for a prompt +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const promptId = searchParams.get("promptId") + const promptSlug = searchParams.get("slug") + + if (!promptId && !promptSlug) { + return NextResponse.json( + { error: "promptId or slug is required" }, + { status: 400 } + ) + } + + const prompt = await prisma.prompt.findFirst({ + where: promptId + ? { id: promptId } + : { slug: promptSlug! }, + select: { + id: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + framework: true, + badges: true, + } + }) + + if (!prompt) { + return NextResponse.json( + { error: "Prompt not found" }, + { status: 404 } + ) + } + + const calculatedBadges = calculatePromptBadges(prompt) + + // Return badge details + const badgeDetails = calculatedBadges.map(type => BADGE_DEFINITIONS[type]) + + return NextResponse.json({ + promptId: prompt.id, + badges: badgeDetails, + badgeTypes: calculatedBadges + }) + } catch (error) { + console.error("Error fetching badges:", error) + return NextResponse.json( + { error: "Failed to fetch badges" }, + { status: 500 } + ) + } +} + +// POST - Recalculate and update badges for a prompt +export async function POST(request: NextRequest) { + try { + const { promptId } = await request.json() + + if (!promptId) { + return NextResponse.json( + { error: "promptId is required" }, + { status: 400 } + ) + } + + const prompt = await prisma.prompt.findUnique({ + where: { id: promptId }, + select: { + id: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + framework: true, + } + }) + + if (!prompt) { + return NextResponse.json( + { error: "Prompt not found" }, + { status: 404 } + ) + } + + const calculatedBadges = calculatePromptBadges(prompt) + + // Update badges in database + await prisma.prompt.update({ + where: { id: promptId }, + data: { badges: calculatedBadges } + }) + + const badgeDetails = calculatedBadges.map(type => BADGE_DEFINITIONS[type]) + + return NextResponse.json({ + promptId: prompt.id, + badges: badgeDetails, + badgeTypes: calculatedBadges, + updated: true + }) + } catch (error) { + console.error("Error updating badges:", error) + return NextResponse.json( + { error: "Failed to update badges" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/badges/update/route.ts b/src/app/api/badges/update/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..5aece00f41c6c4991a05023f74c3e7d0444197e2 --- /dev/null +++ b/src/app/api/badges/update/route.ts @@ -0,0 +1,76 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { calculateBadges } from '@/lib/badges' + +export const dynamic = 'force-dynamic' + +/** + * Update badges for a single prompt or all prompts + * Should be run via cron job nightly + */ +export async function POST(req: Request) { + try { + const { promptId } = await req.json() + + if (promptId) { + // Update single prompt + const prompt = await prisma.prompt.findUnique({ + where: { id: promptId }, + }) + + if (!prompt) { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + // Get all prompts for comparison + const allPrompts = await prisma.prompt.findMany({ + where: { visibility: 'public' }, + select: { + id: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + createdAt: true, + framework: true, + description: true, + schema: true, + }, + }) + + const badges = calculateBadges(prompt as any, allPrompts as any) + + await prisma.prompt.update({ + where: { id: promptId }, + data: { badges }, + }) + + return NextResponse.json({ promptId, badges }) + } else { + // Update all prompts + const prompts = await prisma.prompt.findMany({ + where: { visibility: 'public' }, + }) + + let updated = 0 + + for (const prompt of prompts) { + const badges = calculateBadges(prompt as any, prompts as any) + + await prisma.prompt.update({ + where: { id: prompt.id }, + data: { badges }, + }) + + updated++ + } + + return NextResponse.json({ updated, total: prompts.length }) + } + } catch (error) { + console.error('Update badges error:', error) + return NextResponse.json( + { error: 'Failed to update badges' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/characters/memory/route.ts b/src/app/api/characters/memory/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..60bfc13220919a95dcfb158aecb6ec44cbbfd357 --- /dev/null +++ b/src/app/api/characters/memory/route.ts @@ -0,0 +1,185 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" +import { stackServerApp } from "@/lib/stack-server" +import { generateText } from "ai" +import { openai } from "@ai-sdk/openai" + +// GET - Get memory for a character +export async function GET(request: NextRequest) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const { searchParams } = new URL(request.url) + const characterId = searchParams.get("characterId") + + if (!characterId) { + return NextResponse.json( + { error: "characterId is required" }, + { status: 400 } + ) + } + + const memory = await prisma.characterMemory.findUnique({ + where: { + characterId_userId: { + characterId, + userId: user.id, + }, + }, + }) + + return NextResponse.json({ memory }) + } catch (error) { + console.error("Error fetching character memory:", error) + return NextResponse.json( + { error: "Failed to fetch memory" }, + { status: 500 } + ) + } +} + +// POST - Update memory with new messages +export async function POST(request: NextRequest) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const { characterId, messages, newMessage, characterResponse } = await request.json() + + if (!characterId) { + return NextResponse.json( + { error: "characterId is required" }, + { status: 400 } + ) + } + + // Get or create memory + let memory = await prisma.characterMemory.findUnique({ + where: { + characterId_userId: { + characterId, + userId: user.id, + }, + }, + }) + + if (!memory) { + memory = await prisma.characterMemory.create({ + data: { + characterId, + userId: user.id, + recentMessages: [], + userFacts: [], + messageCount: 0, + }, + }) + } + + // Update recent messages + const recentMessages = memory.recentMessages as Array<{ role: string; content: string }> + const updatedMessages = [ + ...recentMessages, + { role: "user", content: newMessage }, + { role: "assistant", content: characterResponse }, + ].slice(-20) // Keep last 20 messages + + // If we have enough messages, summarize the context + let contextSummary = memory.contextSummary + if (updatedMessages.length >= 10 && (!contextSummary || memory.messageCount % 10 === 0)) { + try { + const { text } = await generateText({ + model: openai("gpt-4o-mini"), + prompt: `Summarize the key points from this conversation for context retention. Focus on: +1. User preferences and interests +2. Important facts mentioned +3. Ongoing topics or tasks + +Conversation: +${updatedMessages.map(m => `${m.role}: ${m.content}`).join("\n")} + +Provide a brief summary (2-3 sentences):`, + }) + contextSummary = text + } catch (error) { + console.error("Failed to summarize context:", error) + } + } + + // Extract user facts (simple keyword extraction) + const userFacts = memory.userFacts as string[] + // This could be enhanced with AI extraction + + // Update memory + const updatedMemory = await prisma.characterMemory.update({ + where: { + characterId_userId: { + characterId, + userId: user.id, + }, + }, + data: { + recentMessages: updatedMessages, + contextSummary, + userFacts, + messageCount: { increment: 2 }, + }, + }) + + return NextResponse.json({ memory: updatedMemory }) + } catch (error) { + console.error("Error updating character memory:", error) + return NextResponse.json( + { error: "Failed to update memory" }, + { status: 500 } + ) + } +} + +// DELETE - Clear memory for a character +export async function DELETE(request: NextRequest) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const { searchParams } = new URL(request.url) + const characterId = searchParams.get("characterId") + + if (!characterId) { + return NextResponse.json( + { error: "characterId is required" }, + { status: 400 } + ) + } + + await prisma.characterMemory.deleteMany({ + where: { + characterId, + userId: user.id, + }, + }) + + return NextResponse.json({ success: true }) + } catch (error) { + console.error("Error clearing character memory:", error) + return NextResponse.json( + { error: "Failed to clear memory" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/characters/route.ts b/src/app/api/characters/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..dff5b586928391bb7accda3eafd24e622b3924e7 --- /dev/null +++ b/src/app/api/characters/route.ts @@ -0,0 +1,148 @@ +import { NextRequest, NextResponse } from "next/server"; +import { prisma } from "@/lib/prisma"; + +// GET /api/characters +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url); + const category = searchParams.get("category"); + const search = searchParams.get("search"); + const sortBy = searchParams.get("sortBy") || "popular"; + const limit = parseInt(searchParams.get("limit") || "20"); + const offset = parseInt(searchParams.get("offset") || "0"); + + const where: Record = { + visibility: "public", + }; + + if (category && category !== "all") { + where.category = category; + } + + if (search) { + where.OR = [ + { name: { contains: search, mode: "insensitive" } }, + { description: { contains: search, mode: "insensitive" } }, + { tags: { has: search.toLowerCase() } }, + ]; + } + + const orderBy: Record = {}; + switch (sortBy) { + case "newest": + orderBy.createdAt = "desc"; + break; + case "votes": + orderBy.votesCount = "desc"; + break; + case "chats": + orderBy.totalChats = "desc"; + break; + default: + orderBy.totalChats = "desc"; + } + + const [characters, total] = await Promise.all([ + prisma.character.findMany({ + where, + include: { + creator: { + select: { + id: true, + name: true, + username: true, + image: true, + }, + }, + }, + orderBy, + take: limit, + skip: offset, + }), + prisma.character.count({ where }), + ]); + + return NextResponse.json({ + characters, + total, + hasMore: offset + limit < total, + }); + } catch (error) { + console.error("Error fetching characters:", error); + return NextResponse.json( + { error: "Failed to fetch characters" }, + { status: 500 } + ); + } +} + +// POST /api/characters +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + const { + name, + description, + personality, + background, + systemPrompt, + avatar, + style, + category, + tags, + responseStyle, + temperature, + creatorId, + } = body; + + if (!name || !personality || !systemPrompt) { + return NextResponse.json( + { error: "name, personality, and systemPrompt are required" }, + { status: 400 } + ); + } + + // Generate slug from name + const slug = name + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/(^-|-$)/g, "") + + "-" + + Date.now().toString(36); + + const character = await prisma.character.create({ + data: { + slug, + name, + description, + personality, + background, + systemPrompt, + avatar, + style, + category, + tags: tags || [], + responseStyle, + temperature: temperature || 0.7, + creatorId, + }, + include: { + creator: { + select: { + id: true, + name: true, + username: true, + }, + }, + }, + }); + + return NextResponse.json(character); + } catch (error) { + console.error("Error creating character:", error); + return NextResponse.json( + { error: "Failed to create character" }, + { status: 500 } + ); + } +} diff --git a/src/app/api/coach/route.ts b/src/app/api/coach/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2ef27c264363ad199d5382a3d26010ada1a6075 --- /dev/null +++ b/src/app/api/coach/route.ts @@ -0,0 +1,68 @@ +import { NextRequest, NextResponse } from 'next/server' +import { streamText } from 'ai' +import { google } from '@ai-sdk/google' +import { getAuthUser } from '@/lib/auth' +import { checkRateLimit, getClientIdentifier, getRateLimitHeaders } from '@/lib/rate-limit' + +// POST /api/coach โ€” AI Prompt Improver +export async function POST(request: NextRequest) { + try { + const authUser = await getAuthUser() + const userId = authUser?.id ?? null + + // Rate limiting + const identifier = getClientIdentifier(request, userId ?? undefined) + const rateLimit = await checkRateLimit(identifier, !!userId) + + if (!rateLimit.success) { + return new Response( + JSON.stringify({ error: rateLimit.error }), + { status: 429, headers: { 'Content-Type': 'application/json' } } + ) + } + + const body = await request.json() + // Support both 'prompt' (legacy) and 'template' (from PromptCoach component) + const { prompt, template, action, category } = body + const inputText = template || prompt + + if (!inputText) { + return NextResponse.json({ error: 'Prompt or template is required' }, { status: 400 }) + } + + let systemPrompt = '' + + switch (action) { + case 'improve': + systemPrompt = `You are an expert prompt engineer. Improve the following AI prompt to get better results. Make it clearer, more specific, and add any missing context or instructions. Return ONLY the improved prompt, no explanations.` + break + case 'shorten': + systemPrompt = `You are an expert prompt engineer. Make the following AI prompt more concise while keeping its effectiveness. Remove redundancy and unnecessary words. Return ONLY the shortened prompt, no explanations.` + break + case 'expand': + systemPrompt = `You are an expert prompt engineer. Expand the following AI prompt with more detail, context, and specific instructions to get higher quality results. Return ONLY the expanded prompt, no explanations.` + break + case 'analyze': + default: + systemPrompt = `You are an expert prompt engineer and AI coach. +Give concise, actionable feedback on this prompt in under 120 words. +Focus ONLY on specific weaknesses and how to fix them. Do NOT repeat what is already good. +${category ? `The prompt is for the "${category}" category.` : ''} +End with one concrete rewrite suggestion for the weakest part.` + } + + const result = await streamText({ + model: google('gemini-2.0-flash'), + system: systemPrompt, + prompt: inputText.slice(0, 2000), + }) + + const headers = getRateLimitHeaders(rateLimit) + return result.toTextStreamResponse({ + headers: Object.fromEntries(headers.entries()), + }) + } catch (error) { + console.error('Coach error:', error) + return NextResponse.json({ error: 'Failed to improve prompt' }, { status: 500 }) + } +} diff --git a/src/app/api/collections/[id]/route.ts b/src/app/api/collections/[id]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a6234f05bf5200396ba3186e5b76d3f0215ed4a --- /dev/null +++ b/src/app/api/collections/[id]/route.ts @@ -0,0 +1,156 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +export const dynamic = 'force-dynamic' + +interface RouteContext { + params: Promise<{ id: string }> +} + +// GET - Fetch single collection by ID +export async function GET(req: Request, context: RouteContext) { + try { + const { id } = await context.params + + const collection = await prisma.collection.findUnique({ + where: { id }, + include: { + user: { + select: { + id: true, + name: true, + username: true, + image: true, + }, + }, + prompts: { + include: { + prompt: { + select: { + id: true, + slug: true, + title: true, + description: true, + category: true, + starsCount: true, + }, + }, + }, + orderBy: { + addedAt: 'desc', + }, + }, + }, + }) + + if (!collection) { + return NextResponse.json( + { error: 'Collection not found' }, + { status: 404 } + ) + } + + // Increment view count + await prisma.collection.update({ + where: { id }, + data: { viewCount: { increment: 1 } }, + }) + + return NextResponse.json(collection) + } catch (error) { + console.error('Get collection error:', error) + return NextResponse.json( + { error: 'Failed to fetch collection' }, + { status: 500 } + ) + } +} + +// PUT - Update collection +export async function PUT(req: Request, context: RouteContext) { + try { + const { id } = await context.params + const body = await req.json() + const { name, description, isPublic, userId } = body + + // Find the collection first + const existingCollection = await prisma.collection.findUnique({ + where: { id }, + }) + + if (!existingCollection) { + return NextResponse.json( + { error: 'Collection not found' }, + { status: 404 } + ) + } + + // Check if user owns the collection + if (existingCollection.userId !== userId) { + return NextResponse.json( + { error: 'You can only edit your own collections' }, + { status: 403 } + ) + } + + // Update the collection + const updatedCollection = await prisma.collection.update({ + where: { id }, + data: { + ...(name && { name }), + ...(description !== undefined && { description }), + ...(isPublic !== undefined && { isPublic }), + }, + }) + + return NextResponse.json(updatedCollection) + } catch (error) { + console.error('Update collection error:', error) + return NextResponse.json( + { error: 'Failed to update collection' }, + { status: 500 } + ) + } +} + +// DELETE - Delete collection +export async function DELETE(req: Request, context: RouteContext) { + try { + const { id } = await context.params + const { searchParams } = new URL(req.url) + const userId = searchParams.get('userId') + + // Find the collection first + const existingCollection = await prisma.collection.findUnique({ + where: { id }, + }) + + if (!existingCollection) { + return NextResponse.json( + { error: 'Collection not found' }, + { status: 404 } + ) + } + + // Check if user owns the collection + if (existingCollection.userId !== userId) { + return NextResponse.json( + { error: 'You can only delete your own collections' }, + { status: 403 } + ) + } + + // Delete the collection (cascades to CollectionPrompt entries) + await prisma.collection.delete({ + where: { id }, + }) + + return NextResponse.json({ success: true, message: 'Collection deleted' }) + } catch (error) { + console.error('Delete collection error:', error) + return NextResponse.json( + { error: 'Failed to delete collection' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/collections/prompts/route.ts b/src/app/api/collections/prompts/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..456c9ddfdc1222851709105646a192c058422bb5 --- /dev/null +++ b/src/app/api/collections/prompts/route.ts @@ -0,0 +1,91 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +export const dynamic = 'force-dynamic' + +// Add prompt to collection +export async function POST(req: Request) { + try { + const { collectionId, promptId } = await req.json() + + if (!collectionId || !promptId) { + return NextResponse.json( + { error: 'Collection ID and Prompt ID are required' }, + { status: 400 } + ) + } + + // Check if already exists + const existing = await prisma.collectionPrompt.findUnique({ + where: { + collectionId_promptId: { + collectionId, + promptId, + }, + }, + }) + + if (existing) { + return NextResponse.json( + { error: 'Prompt already in collection' }, + { status: 409 } + ) + } + + const item = await prisma.collectionPrompt.create({ + data: { + collectionId, + promptId, + }, + }) + + // Update collection updatedAt + await prisma.collection.update({ + where: { id: collectionId }, + data: { updatedAt: new Date() }, + }) + + return NextResponse.json(item) + + } catch (error) { + console.error('Add to collection error:', error) + return NextResponse.json( + { error: 'Failed to add prompt to collection' }, + { status: 500 } + ) + } +} + +// Remove prompt from collection +export async function DELETE(req: Request) { + try { + const { searchParams } = new URL(req.url) + const collectionId = searchParams.get('collectionId') + const promptId = searchParams.get('promptId') + + if (!collectionId || !promptId) { + return NextResponse.json( + { error: 'Collection ID and Prompt ID are required' }, + { status: 400 } + ) + } + + await prisma.collectionPrompt.delete({ + where: { + collectionId_promptId: { + collectionId, + promptId, + }, + }, + }) + + return NextResponse.json({ success: true }) + + } catch (error) { + console.error('Remove from collection error:', error) + return NextResponse.json( + { error: 'Failed to remove prompt from collection' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/collections/route.ts b/src/app/api/collections/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..43698c34ee2ce38a494c63106ef3f4768f6bc1cc --- /dev/null +++ b/src/app/api/collections/route.ts @@ -0,0 +1,193 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' +import { createCollectionSchema, updateCollectionSchema, parseBody } from '@/lib/validations' +import { checkRateLimit, getClientIdentifier, getRateLimitHeaders } from '@/lib/rate-limit' +import type { Prisma } from '@prisma/client' + +export const dynamic = 'force-dynamic' + +// Get user's collections โ€” with pagination +export async function GET(req: Request) { + try { + const { searchParams } = new URL(req.url) + const userId = searchParams.get('userId') + const isPublic = searchParams.get('public') === 'true' + const limit = Math.min(parseInt(searchParams.get('limit') || '20'), 100) + const offset = Math.max(parseInt(searchParams.get('offset') || '0'), 0) + + if (!userId) { + return NextResponse.json([], { status: 200 }) + } + + const where: Prisma.CollectionWhereInput = { userId } + if (isPublic) { + where.isPublic = true + } + + const [collections, total] = await Promise.all([ + prisma.collection.findMany({ + where, + include: { + prompts: { + include: { + prompt: { + select: { + id: true, + slug: true, + title: true, + description: true, + category: true, + }, + }, + }, + }, + user: { + select: { + name: true, + username: true, + image: true, + }, + }, + }, + orderBy: { updatedAt: 'desc' }, + take: limit, + skip: offset, + }), + prisma.collection.count({ where }), + ]) + + return NextResponse.json({ collections, total, hasMore: offset + collections.length < total }) + + } catch (error) { + console.error('Get collections error:', error) + return NextResponse.json( + { error: 'Failed to fetch collections' }, + { status: 500 } + ) + } +} + +// Create new collection โ€” requires auth +export async function POST(req: Request) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + // Rate limit + const identifier = getClientIdentifier(req, authUser.id) + const rateLimit = await checkRateLimit(`collections:${identifier}`, true) + if (!rateLimit.success) { + return NextResponse.json({ error: rateLimit.error }, { status: 429 }) + } + + const body = await req.json() + const parsed = parseBody(createCollectionSchema, body) + if (!parsed.success) return parsed.response + + const { name, description, isPublic } = parsed.data + + const collection = await prisma.collection.create({ + data: { + name, + description: description || null, + userId: authUser.id, + isPublic: isPublic || false, + }, + }) + + return NextResponse.json(collection) + + } catch (error) { + console.error('Create collection error:', error) + return NextResponse.json( + { error: 'Failed to create collection' }, + { status: 500 } + ) + } +} + +// Update collection โ€” requires auth + ownership +export async function PATCH(req: Request) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const body = await req.json() + const parsed = parseBody(updateCollectionSchema, body) + if (!parsed.success) return parsed.response + + const { id, name, description, isPublic } = parsed.data + + // Verify ownership + const existing = await prisma.collection.findUnique({ + where: { id }, + select: { userId: true }, + }) + if (!existing || existing.userId !== authUser.id) { + return NextResponse.json({ error: 'Not found or not authorized' }, { status: 403 }) + } + + const collection = await prisma.collection.update({ + where: { id }, + data: { + ...(name && { name }), + ...(description !== undefined && { description }), + ...(isPublic !== undefined && { isPublic }), + }, + }) + + return NextResponse.json(collection) + + } catch (error) { + console.error('Update collection error:', error) + return NextResponse.json( + { error: 'Failed to update collection' }, + { status: 500 } + ) + } +} + +// Delete collection โ€” requires auth + ownership +export async function DELETE(req: Request) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const { searchParams } = new URL(req.url) + const id = searchParams.get('id') + + if (!id) { + return NextResponse.json( + { error: 'Collection ID is required' }, + { status: 400 } + ) + } + + // Verify ownership + const existing = await prisma.collection.findUnique({ + where: { id }, + select: { userId: true }, + }) + if (!existing || existing.userId !== authUser.id) { + return NextResponse.json({ error: 'Not found or not authorized' }, { status: 403 }) + } + + await prisma.collection.delete({ where: { id } }) + + return NextResponse.json({ success: true }) + + } catch (error) { + console.error('Delete collection error:', error) + return NextResponse.json( + { error: 'Failed to delete collection' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/comments/route.ts b/src/app/api/comments/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa498afe978329d0de63bd6d41815483c65d50b8 --- /dev/null +++ b/src/app/api/comments/route.ts @@ -0,0 +1,262 @@ +import { NextRequest, NextResponse } from "next/server"; +import { prisma } from "@/lib/prisma"; +import { getAuthUser } from "@/lib/auth"; +import { createCommentSchema, updateCommentSchema, parseBody } from "@/lib/validations"; +import { checkRateLimit, getClientIdentifier } from "@/lib/rate-limit"; +import { sanitizeText } from "@/lib/api-utils"; + +// GET /api/comments?promptId=xxx โ€” public, with pagination +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url); + const promptId = searchParams.get("promptId"); + const limit = Math.min(parseInt(searchParams.get("limit") || "20"), 50); + const offset = Math.max(parseInt(searchParams.get("offset") || "0"), 0); + + if (!promptId) { + return NextResponse.json( + { error: "promptId is required" }, + { status: 400 } + ); + } + + const [comments, total] = await Promise.all([ + prisma.comment.findMany({ + where: { + promptId, + parentId: null, // Only top-level comments + }, + include: { + user: { + select: { + id: true, + name: true, + username: true, + image: true, + rank: true, + }, + }, + replies: { + include: { + user: { + select: { + id: true, + name: true, + username: true, + image: true, + rank: true, + }, + }, + }, + orderBy: { createdAt: "asc" }, + take: 50, // Limit nested replies + }, + }, + orderBy: { createdAt: "desc" }, + take: limit, + skip: offset, + }), + prisma.comment.count({ where: { promptId, parentId: null } }), + ]); + + return NextResponse.json({ comments, total, hasMore: offset + comments.length < total }); + } catch (error) { + console.error("Error fetching comments:", error); + return NextResponse.json( + { error: "Failed to fetch comments" }, + { status: 500 } + ); + } +} + +// POST /api/comments โ€” requires authentication + rate limited +export async function POST(request: NextRequest) { + try { + const authUser = await getAuthUser(); + if (!authUser) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ); + } + + // Rate limit + const identifier = getClientIdentifier(request, authUser.id); + const rateLimit = await checkRateLimit(`comments:${identifier}`, true); + if (!rateLimit.success) { + return NextResponse.json({ error: rateLimit.error }, { status: 429 }); + } + + const body = await request.json(); + const parsed = parseBody(createCommentSchema, body); + if (!parsed.success) return parsed.response; + + const { promptId, content, parentId } = parsed.data; + + // Sanitize content โ€” strip HTML tags, limit length + const sanitizedContent = sanitizeText(content, 5000); + if (!sanitizedContent) { + return NextResponse.json( + { error: "Comment content cannot be empty" }, + { status: 400 } + ); + } + + const comment = await prisma.comment.create({ + data: { + promptId, + userId: authUser.id, + content: sanitizedContent, + parentId: parentId || null, + }, + include: { + user: { + select: { + id: true, + name: true, + username: true, + image: true, + rank: true, + }, + }, + }, + }); + + return NextResponse.json(comment); + } catch (error) { + console.error("Error creating comment:", error); + return NextResponse.json( + { error: "Failed to create comment" }, + { status: 500 } + ); + } +} + +// PATCH /api/comments โ€” requires authentication +// Like/unlike uses a Redis-based per-user tracking to prevent spam +export async function PATCH(request: NextRequest) { + try { + const authUser = await getAuthUser(); + if (!authUser) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ); + } + + const body = await request.json(); + const parsed = parseBody(updateCommentSchema, body); + if (!parsed.success) return parsed.response; + + const { commentId, action, content } = parsed.data; + + if (action === "like" || action === "unlike") { + if (action === "like") { + try { + // Create a like record โ€” unique constraint prevents double-liking + await prisma.commentLike.create({ + data: { commentId, userId: authUser.id }, + }) + } catch { + // Unique constraint violation = already liked + return NextResponse.json({ error: "Already liked" }, { status: 409 }) + } + // Return updated like count + const count = await prisma.commentLike.count({ where: { commentId } }) + return NextResponse.json({ liked: true, likes: count }) + } + + if (action === "unlike") { + const deleted = await prisma.commentLike.deleteMany({ + where: { commentId, userId: authUser.id }, + }) + if (deleted.count === 0) { + return NextResponse.json({ error: "Not liked" }, { status: 409 }) + } + const count = await prisma.commentLike.count({ where: { commentId } }) + return NextResponse.json({ liked: false, likes: count }) + } + } + + if (action === "edit" && content) { + // Verify ownership before editing + const existingComment = await prisma.comment.findUnique({ + where: { id: commentId }, + select: { userId: true }, + }); + + if (!existingComment || existingComment.userId !== authUser.id) { + return NextResponse.json( + { error: "You can only edit your own comments" }, + { status: 403 } + ); + } + + const sanitizedContent = sanitizeText(content, 5000); + const comment = await prisma.comment.update({ + where: { id: commentId }, + data: { content: sanitizedContent }, + }); + return NextResponse.json(comment); + } + + return NextResponse.json( + { error: "Invalid action" }, + { status: 400 } + ); + } catch (error) { + console.error("Error updating comment:", error); + return NextResponse.json( + { error: "Failed to update comment" }, + { status: 500 } + ); + } +} + +// DELETE /api/comments โ€” requires authentication, delete only own comments +export async function DELETE(request: NextRequest) { + try { + const authUser = await getAuthUser(); + if (!authUser) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ); + } + + const { searchParams } = new URL(request.url); + const commentId = searchParams.get("commentId"); + + if (!commentId) { + return NextResponse.json( + { error: "commentId is required" }, + { status: 400 } + ); + } + + // Verify ownership before deleting + const existingComment = await prisma.comment.findUnique({ + where: { id: commentId }, + select: { userId: true }, + }); + + if (!existingComment || existingComment.userId !== authUser.id) { + return NextResponse.json( + { error: "You can only delete your own comments" }, + { status: 403 } + ); + } + + await prisma.comment.delete({ + where: { id: commentId }, + }); + + return NextResponse.json({ success: true }); + } catch (error) { + console.error("Error deleting comment:", error); + return NextResponse.json( + { error: "Failed to delete comment" }, + { status: 500 } + ); + } +} diff --git a/src/app/api/comparisons/route.ts b/src/app/api/comparisons/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d8fcf0b433351c2e2b8ec4ff96d16a357f17c7b --- /dev/null +++ b/src/app/api/comparisons/route.ts @@ -0,0 +1,63 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +// GET /api/comparisons - Get saved comparisons +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url) + const userId = searchParams.get('userId') + const type = searchParams.get('type') // "thunderdome" or "performance" + + try { + const where: any = {} + + if (userId) { + where.userId = userId + } + + if (type) { + where.type = type + } + + const comparisons = await prisma.savedComparison.findMany({ + where, + orderBy: { createdAt: 'desc' }, + take: 50, + }) + + return NextResponse.json({ comparisons }) + } catch (error) { + console.error('Error fetching comparisons:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// POST /api/comparisons - Save a comparison +export async function POST(request: NextRequest) { + try { + const body = await request.json() + const { userId, name, type, prompt, results, winner } = body + + if (!type || !prompt || !results) { + return NextResponse.json( + { error: 'type, prompt, and results are required' }, + { status: 400 } + ) + } + + const comparison = await prisma.savedComparison.create({ + data: { + type, + userId: userId || null, + name: name || null, + prompt, + results, + winner: winner || null, + } + }) + + return NextResponse.json(comparison, { status: 201 }) + } catch (error) { + console.error('Error saving comparison:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/engagement/route.ts b/src/app/api/engagement/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..03b240805cea6dec385eff41abb9e1d857f6a849 --- /dev/null +++ b/src/app/api/engagement/route.ts @@ -0,0 +1,159 @@ +import { NextRequest, NextResponse } from "next/server"; +import { prisma } from "@/lib/prisma"; +import { getAuthUser } from "@/lib/auth"; +import { engagementSchema, parseBody } from "@/lib/validations"; +import { checkRateLimit, getClientIdentifier } from "@/lib/rate-limit"; + +// POST /api/engagement - Track engagement events (server-side auth, rate limited) +export async function POST(request: NextRequest) { + try { + // Use server-side auth โ€” don't trust client userId + const authUser = await getAuthUser(); + + // Rate limit (allow anon but rate limit harder) + const identifier = getClientIdentifier(request, authUser?.id ?? undefined); + const rateLimit = await checkRateLimit(`engagement:${identifier}`, !!authUser); + if (!rateLimit.success) { + return NextResponse.json({ error: rateLimit.error }, { status: 429 }); + } + + const body = await request.json(); + const parsed = parseBody(engagementSchema, body); + if (!parsed.success) return parsed.response; + + const { targetType, targetId, action } = parsed.data; + + // Generate IP hash for anon tracking + const forwarded = request.headers.get("x-forwarded-for"); + const ip = forwarded?.split(",")[0] || request.headers.get("x-real-ip") || "unknown"; + + // Create engagement metric + await prisma.engagementMetric.create({ + data: { + targetType, + targetId, + action, + userId: authUser?.id || null, + ipHash: authUser ? null : ip, + }, + }); + + // Update counts based on action and target type + if (action === "use") { + if (targetType === "imagePrompt") { + await prisma.imagePrompt.update({ + where: { id: targetId }, + data: { totalUses: { increment: 1 } }, + }); + } else if (targetType === "character") { + await prisma.character.update({ + where: { id: targetId }, + data: { totalChats: { increment: 1 } }, + }); + } else if (targetType === "prompt") { + await prisma.prompt.update({ + where: { id: targetId }, + data: { totalRuns: { increment: 1 } }, + }); + } + } + + if (action === "save") { + if (targetType === "imagePrompt") { + await prisma.imagePrompt.update({ + where: { id: targetId }, + data: { savesCount: { increment: 1 } }, + }); + } else if (targetType === "character") { + await prisma.character.update({ + where: { id: targetId }, + data: { savesCount: { increment: 1 } }, + }); + } + } + + return NextResponse.json({ success: true }); + } catch (error) { + console.error("Error tracking engagement:", error); + return NextResponse.json( + { error: "Failed to track engagement" }, + { status: 500 } + ); + } +} + +// GET /api/engagement - Get engagement stats +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url); + const targetType = searchParams.get("targetType"); + const targetId = searchParams.get("targetId"); + const timeframe = searchParams.get("timeframe") || "all-time"; + + if (!targetType || !targetId) { + return NextResponse.json( + { error: "targetType and targetId are required" }, + { status: 400 } + ); + } + + // Calculate date filter + let dateFilter: Date | undefined; + if (timeframe === "daily") { + dateFilter = new Date(); + dateFilter.setDate(dateFilter.getDate() - 1); + } else if (timeframe === "weekly") { + dateFilter = new Date(); + dateFilter.setDate(dateFilter.getDate() - 7); + } else if (timeframe === "monthly") { + dateFilter = new Date(); + dateFilter.setMonth(dateFilter.getMonth() - 1); + } + + const where: Record = { + targetType, + targetId, + }; + + if (dateFilter) { + where.createdAt = { gte: dateFilter }; + } + + // Get counts per action + const stats = await prisma.engagementMetric.groupBy({ + by: ["action"], + where, + _count: true, + }); + + const result: Record = {}; + stats.forEach((stat: { action: string; _count: number }) => { + result[stat.action] = stat._count; + }); + + // Get unique users count + const uniqueUsers = await prisma.engagementMetric.findMany({ + where: { + ...where, + userId: { not: null }, + }, + select: { userId: true }, + distinct: ["userId"], + }); + + return NextResponse.json({ + views: result.view || 0, + uses: result.use || 0, + saves: result.save || 0, + shares: result.share || 0, + copies: result.copy || 0, + uniqueUsers: uniqueUsers.length, + }); + } catch (error) { + console.error("Error fetching engagement stats:", error); + return NextResponse.json( + { error: "Failed to fetch engagement stats" }, + { status: 500 } + ); + } +} diff --git a/src/app/api/extension/analytics/route.ts b/src/app/api/extension/analytics/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a043ec828365fe27711eca6b2104cede7b2e0ad --- /dev/null +++ b/src/app/api/extension/analytics/route.ts @@ -0,0 +1,132 @@ +import { NextRequest, NextResponse } from "next/server" +import { prisma } from "@/lib/prisma" + +// POST - Record extension analytics +export async function POST(request: NextRequest) { + try { + const body = await request.json() + const { + userId, + deviceId, + action, + platform, + platforms, + promptId, + promptTitle, + promptText, + metadata + } = body + + if (!deviceId || !action) { + return NextResponse.json( + { error: "deviceId and action are required" }, + { status: 400 } + ) + } + + const analytics = await prisma.extensionAnalytics.create({ + data: { + userId: userId || null, + deviceId, + action, + platform: platform || "unknown", + platforms: platforms || [], + promptId: promptId || null, + promptTitle: promptTitle || null, + promptText: promptText || null, + source: "extension", + metadata: metadata || null, + }, + }) + + return NextResponse.json({ success: true, id: analytics.id }) + } catch (error) { + console.error("Extension analytics error:", error) + return NextResponse.json( + { error: "Failed to record analytics" }, + { status: 500 } + ) + } +} + +// GET - Fetch extension analytics for a user/device +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const userId = searchParams.get("userId") + const deviceId = searchParams.get("deviceId") + const limit = parseInt(searchParams.get("limit") || "50") + + if (!userId && !deviceId) { + return NextResponse.json( + { error: "userId or deviceId required" }, + { status: 400 } + ) + } + + const where: { userId?: string; deviceId?: string } = {} + if (userId) where.userId = userId + if (deviceId) where.deviceId = deviceId + + // Get recent activity + const recentActivity = await prisma.extensionAnalytics.findMany({ + where, + orderBy: { createdAt: "desc" }, + take: limit, + }) + + // Get aggregated stats + const stats = await prisma.extensionAnalytics.groupBy({ + by: ["action"], + where, + _count: { action: true }, + }) + + const platformStats = await prisma.extensionAnalytics.groupBy({ + by: ["platform"], + where, + _count: { platform: true }, + }) + + // Get daily usage for last 30 days + const thirtyDaysAgo = new Date() + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30) + + // Use Prisma's safe query approach + const dailyUsage = await prisma.extensionAnalytics.groupBy({ + by: ['createdAt'], + where: { + ...where, + createdAt: { gte: thirtyDaysAgo }, + }, + _count: { id: true }, + }).then(results => { + // Group by date (day only) + const dateMap = new Map() + results.forEach(r => { + const dateStr = r.createdAt.toISOString().split('T')[0] + dateMap.set(dateStr, (dateMap.get(dateStr) || 0) + r._count.id) + }) + return Array.from(dateMap.entries()).map(([date, count]) => ({ date, count })) + }).catch(() => []) + + return NextResponse.json({ + recentActivity, + stats: stats.map((s: { action: string; _count: { action: number } }) => ({ + action: s.action, + count: s._count.action + })), + platformStats: platformStats.map((s: { platform: string; _count: { platform: number } }) => ({ + platform: s.platform, + count: s._count.platform + })), + dailyUsage, + }) + } catch (error) { + console.error("Extension analytics fetch error:", error) + return NextResponse.json( + { error: "Failed to fetch analytics" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/extension/capture/route.ts b/src/app/api/extension/capture/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..8858953012ebffe97ba23a2dd7cedfcc6c8d345e --- /dev/null +++ b/src/app/api/extension/capture/route.ts @@ -0,0 +1,132 @@ +import { NextRequest, NextResponse } from "next/server" +import { prisma } from "@/lib/prisma" + +// POST - Capture a prompt from AI chat +export async function POST(request: NextRequest) { + try { + const body = await request.json() + const { + userId, + deviceId, + title, + text, + platform, + url, + tags + } = body + + if (!deviceId || !text || !platform) { + return NextResponse.json( + { error: "deviceId, text, and platform are required" }, + { status: 400 } + ) + } + + const captured = await prisma.capturedPrompt.create({ + data: { + userId: userId || null, + deviceId, + title: title || null, + text, + platform, + url: url || null, + tags: tags || [], + }, + }) + + // Also record this as an analytics event + await prisma.extensionAnalytics.create({ + data: { + userId: userId || null, + deviceId, + action: "capture", + platform, + promptText: text.slice(0, 500), // Store first 500 chars + source: "extension", + }, + }) + + return NextResponse.json({ success: true, id: captured.id, captured }) + } catch (error) { + console.error("Capture prompt error:", error) + return NextResponse.json( + { error: "Failed to capture prompt" }, + { status: 500 } + ) + } +} + +// GET - Fetch captured prompts for a user/device +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const userId = searchParams.get("userId") + const deviceId = searchParams.get("deviceId") + const limit = parseInt(searchParams.get("limit") || "50") + + if (!userId && !deviceId) { + return NextResponse.json( + { error: "userId or deviceId required" }, + { status: 400 } + ) + } + + const where: { userId?: string; deviceId?: string } = {} + if (userId) where.userId = userId + if (deviceId) where.deviceId = deviceId + + const captured = await prisma.capturedPrompt.findMany({ + where, + orderBy: { createdAt: "desc" }, + take: limit, + }) + + return NextResponse.json({ captured }) + } catch (error) { + console.error("Fetch captured prompts error:", error) + return NextResponse.json( + { error: "Failed to fetch captured prompts" }, + { status: 500 } + ) + } +} + +// DELETE - Delete a captured prompt +export async function DELETE(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const id = searchParams.get("id") + const deviceId = searchParams.get("deviceId") + + if (!id || !deviceId) { + return NextResponse.json( + { error: "id and deviceId required" }, + { status: 400 } + ) + } + + // Verify ownership + const existing = await prisma.capturedPrompt.findFirst({ + where: { id, deviceId }, + }) + + if (!existing) { + return NextResponse.json( + { error: "Captured prompt not found" }, + { status: 404 } + ) + } + + await prisma.capturedPrompt.delete({ + where: { id }, + }) + + return NextResponse.json({ success: true }) + } catch (error) { + console.error("Delete captured prompt error:", error) + return NextResponse.json( + { error: "Failed to delete captured prompt" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/extension/capture/save/route.ts b/src/app/api/extension/capture/save/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..4dd9184edd7d798dfaa3c51e30e6070c302d1f5a --- /dev/null +++ b/src/app/api/extension/capture/save/route.ts @@ -0,0 +1,76 @@ +import { NextRequest, NextResponse } from "next/server" +import { prisma } from "@/lib/prisma" + +// POST - Save captured prompt to library +export async function POST(request: NextRequest) { + try { + const body = await request.json() + const { + capturedId, + userId, + title, + description, + category, + tags, + visibility + } = body + + if (!capturedId || !userId) { + return NextResponse.json( + { error: "capturedId and userId are required" }, + { status: 400 } + ) + } + + // Get the captured prompt + const captured = await prisma.capturedPrompt.findUnique({ + where: { id: capturedId }, + }) + + if (!captured) { + return NextResponse.json( + { error: "Captured prompt not found" }, + { status: 404 } + ) + } + + // Generate a unique slug + const baseSlug = (title || "captured-prompt") + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-|-$/g, "") + + const slug = `${baseSlug}-${Date.now().toString(36)}` + + // Create the prompt + const prompt = await prisma.prompt.create({ + data: { + slug, + title: title || `Captured from ${captured.platform}`, + description: description || `Prompt captured from ${captured.platform}`, + template: captured.text, + category: category || "general", + tags: tags || captured.tags, + visibility: visibility || "private", + creatorId: userId, + }, + }) + + // Update the captured prompt to mark as saved + await prisma.capturedPrompt.update({ + where: { id: capturedId }, + data: { + savedToLibrary: true, + promptId: prompt.id, + }, + }) + + return NextResponse.json({ success: true, prompt }) + } catch (error) { + console.error("Save to library error:", error) + return NextResponse.json( + { error: "Failed to save to library" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/follow/route.ts b/src/app/api/follow/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..225bd8f96e111268b9b89dffa2ba3aac8e2a4a8f --- /dev/null +++ b/src/app/api/follow/route.ts @@ -0,0 +1,107 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' + +// POST /api/follow โ€” toggle follow/unfollow a creator +export async function POST(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const { targetUserId } = await request.json() + + if (!targetUserId) { + return NextResponse.json({ error: 'targetUserId is required' }, { status: 400 }) + } + + if (targetUserId === authUser.id) { + return NextResponse.json({ error: 'Cannot follow yourself' }, { status: 400 }) + } + + // Check if already following + const existingFollow = await prisma.follow.findUnique({ + where: { + followerId_followingId: { + followerId: authUser.id, + followingId: targetUserId, + }, + }, + }) + + if (existingFollow) { + // Unfollow + await prisma.follow.delete({ + where: { id: existingFollow.id }, + }) + return NextResponse.json({ following: false }) + } else { + // Follow + create notification + await prisma.$transaction([ + prisma.follow.create({ + data: { + followerId: authUser.id, + followingId: targetUserId, + }, + }), + prisma.notification.create({ + data: { + userId: targetUserId, + type: 'follow', + title: 'New follower', + message: `${authUser.displayName || 'Someone'} started following you`, + actorId: authUser.id, + targetType: 'user', + targetId: authUser.id, + }, + }), + ]) + return NextResponse.json({ following: true }) + } + } catch (error) { + console.error('Error toggling follow:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// GET /api/follow?targetUserId=xxx โ€” check if following +export async function GET(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ following: false }) + } + + const { searchParams } = new URL(request.url) + const targetUserId = searchParams.get('targetUserId') + + if (!targetUserId) { + return NextResponse.json({ following: false }) + } + + const follow = await prisma.follow.findUnique({ + where: { + followerId_followingId: { + followerId: authUser.id, + followingId: targetUserId, + }, + }, + }) + + // Also get counts + const [followersCount, followingCount] = await Promise.all([ + prisma.follow.count({ where: { followingId: targetUserId } }), + prisma.follow.count({ where: { followerId: targetUserId } }), + ]) + + return NextResponse.json({ + following: !!follow, + followersCount, + followingCount, + }) + } catch (error) { + console.error('Error checking follow:', error) + return NextResponse.json({ following: false }) + } +} diff --git a/src/app/api/forum/[id]/route.ts b/src/app/api/forum/[id]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8555cbb046de250bb96ca9b7bde9861610e9019 --- /dev/null +++ b/src/app/api/forum/[id]/route.ts @@ -0,0 +1,201 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" +import { stackServerApp } from "@/lib/stack-server" + +// GET - Get a single forum post with replies +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + try { + const { id } = await params + + const post = await prisma.forumPost.findUnique({ + where: { id }, + include: { + replies: { + orderBy: { createdAt: "asc" }, + }, + }, + }) + + if (!post) { + return NextResponse.json( + { error: "Post not found" }, + { status: 404 } + ) + } + + // Increment view count + await prisma.forumPost.update({ + where: { id }, + data: { views: { increment: 1 } }, + }) + + // Get user info + const userIds = [post.userId, ...post.replies.map(r => r.userId)] + const users = await prisma.user.findMany({ + where: { id: { in: [...new Set(userIds)] } }, + select: { + id: true, + name: true, + username: true, + image: true, + }, + }) + const userMap = new Map(users.map(u => [u.id, u])) + + const postWithUser = { + ...post, + user: userMap.get(post.userId) || null, + replies: post.replies.map(reply => ({ + ...reply, + user: userMap.get(reply.userId) || null, + })), + } + + return NextResponse.json(postWithUser) + } catch (error) { + console.error("Error fetching forum post:", error) + return NextResponse.json( + { error: "Failed to fetch post" }, + { status: 500 } + ) + } +} + +// POST - Add a reply to a forum post +export async function POST( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const { id } = await params + const { content, parentId } = await request.json() + + if (!content) { + return NextResponse.json( + { error: "Content is required" }, + { status: 400 } + ) + } + + // Verify post exists + const post = await prisma.forumPost.findUnique({ + where: { id }, + }) + + if (!post) { + return NextResponse.json( + { error: "Post not found" }, + { status: 404 } + ) + } + + if (post.isClosed) { + return NextResponse.json( + { error: "This discussion is closed" }, + { status: 400 } + ) + } + + const reply = await prisma.forumReply.create({ + data: { + content, + postId: id, + userId: user.id, + parentId: parentId || null, + }, + }) + + return NextResponse.json(reply) + } catch (error) { + console.error("Error creating reply:", error) + return NextResponse.json( + { error: "Failed to create reply" }, + { status: 500 } + ) + } +} + +// PATCH - Update post (like, close, pin) +export async function PATCH( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const { id } = await params + const { action } = await request.json() + + const post = await prisma.forumPost.findUnique({ + where: { id }, + }) + + if (!post) { + return NextResponse.json( + { error: "Post not found" }, + { status: 404 } + ) + } + + let updateData: Record = {} + + switch (action) { + case "like": + updateData = { likes: { increment: 1 } } + break + case "close": + if (post.userId !== user.id) { + return NextResponse.json( + { error: "Only the author can close this" }, + { status: 403 } + ) + } + updateData = { isClosed: true } + break + case "reopen": + if (post.userId !== user.id) { + return NextResponse.json( + { error: "Only the author can reopen this" }, + { status: 403 } + ) + } + updateData = { isClosed: false } + break + default: + return NextResponse.json( + { error: "Invalid action" }, + { status: 400 } + ) + } + + const updated = await prisma.forumPost.update({ + where: { id }, + data: updateData, + }) + + return NextResponse.json(updated) + } catch (error) { + console.error("Error updating post:", error) + return NextResponse.json( + { error: "Failed to update post" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/forum/route.ts b/src/app/api/forum/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..72a90b139161709087bd257f70e62941b14966dc --- /dev/null +++ b/src/app/api/forum/route.ts @@ -0,0 +1,141 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" +import { getAuthUser } from "@/lib/auth" +import { createForumPostSchema, parseBody } from "@/lib/validations" +import { checkRateLimit, getClientIdentifier } from "@/lib/rate-limit" +import { sanitizeText } from "@/lib/api-utils" + +const FORUM_CATEGORIES = [ + "general", + "help", + "showcase", + "feature-request", + "tips", +] + +// GET - List forum posts (uses Prisma include instead of separate user query) +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const category = searchParams.get("category") + const search = searchParams.get("search") + const sort = searchParams.get("sort") || "recent" + const limit = Math.min(parseInt(searchParams.get("limit") || "20"), 100) + const offset = Math.max(parseInt(searchParams.get("offset") || "0"), 0) + + // Build where clause + const whereClause: Record = {} + + if (category && category !== "all") { + whereClause.category = category + } + + if (search) { + whereClause.OR = [ + { title: { contains: search, mode: "insensitive" } }, + { content: { contains: search, mode: "insensitive" } }, + ] + } + + // Build order by + let orderBy: Record[] = [{ createdAt: "desc" }] + if (sort === "popular") { + orderBy = [{ views: "desc" }, { likes: "desc" }] + } else if (sort === "unanswered") { + whereClause.replies = { none: {} } + } + + // Use Prisma include to get user data in single query (fixes N+1) + const [posts, total] = await Promise.all([ + prisma.forumPost.findMany({ + where: whereClause, + orderBy, + take: limit, + skip: offset, + include: { + user: { + select: { + id: true, + name: true, + username: true, + image: true, + }, + }, + _count: { + select: { replies: true } + } + } + }), + prisma.forumPost.count({ where: whereClause }), + ]) + + const postsWithCounts = posts.map(post => ({ + ...post, + replyCount: post._count.replies, + })) + + return NextResponse.json({ + posts: postsWithCounts, + total, + categories: FORUM_CATEGORIES, + hasMore: offset + posts.length < total, + }, { + headers: { + 'Cache-Control': 'public, s-maxage=30, stale-while-revalidate=120', + }, + }) + } catch (error) { + console.error("Error fetching forum posts:", error) + return NextResponse.json( + { error: "Failed to fetch posts" }, + { status: 500 } + ) + } +} + +// POST - Create a new forum post โ€” requires auth, rate limited, validated, sanitized +export async function POST(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + // Rate limit + const identifier = getClientIdentifier(request, authUser.id) + const rateLimit = await checkRateLimit(`forum:${identifier}`, true) + if (!rateLimit.success) { + return NextResponse.json({ error: rateLimit.error }, { status: 429 }) + } + + const body = await request.json() + const parsed = parseBody(createForumPostSchema, body) + if (!parsed.success) return parsed.response + + const { title, content, category } = parsed.data + + // Sanitize content (strip HTML) + const sanitizedContent = sanitizeText(content, 20000) + const sanitizedTitle = sanitizeText(title, 300) + + const post = await prisma.forumPost.create({ + data: { + title: sanitizedTitle, + content: sanitizedContent, + category, + userId: authUser.id, + }, + }) + + return NextResponse.json(post) + } catch (error) { + console.error("Error creating forum post:", error) + return NextResponse.json( + { error: "Failed to create post" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/image-prompts/route.ts b/src/app/api/image-prompts/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1af95f7f8feb9d4c3cd4b16dc9924bbbd3014e6 --- /dev/null +++ b/src/app/api/image-prompts/route.ts @@ -0,0 +1,155 @@ +import { NextRequest, NextResponse } from "next/server"; +import { prisma } from "@/lib/prisma"; + +// GET /api/image-prompts +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url); + const model = searchParams.get("model"); + const category = searchParams.get("category"); + const search = searchParams.get("search"); + const sortBy = searchParams.get("sortBy") || "popular"; + const limit = parseInt(searchParams.get("limit") || "20"); + const offset = parseInt(searchParams.get("offset") || "0"); + + const where: Record = { + visibility: "public", + }; + + if (model && model !== "all") { + where.model = model; + } + + if (category && category !== "all") { + where.category = category; + } + + if (search) { + where.OR = [ + { title: { contains: search, mode: "insensitive" } }, + { description: { contains: search, mode: "insensitive" } }, + { tags: { has: search.toLowerCase() } }, + ]; + } + + const orderBy: Record = {}; + switch (sortBy) { + case "newest": + orderBy.createdAt = "desc"; + break; + case "votes": + orderBy.votesCount = "desc"; + break; + case "uses": + orderBy.totalUses = "desc"; + break; + default: + orderBy.totalUses = "desc"; + } + + const [imagePrompts, total] = await Promise.all([ + prisma.imagePrompt.findMany({ + where, + include: { + creator: { + select: { + id: true, + name: true, + username: true, + image: true, + }, + }, + }, + orderBy, + take: limit, + skip: offset, + }), + prisma.imagePrompt.count({ where }), + ]); + + return NextResponse.json({ + imagePrompts, + total, + hasMore: offset + limit < total, + }); + } catch (error) { + console.error("Error fetching image prompts:", error); + return NextResponse.json( + { error: "Failed to fetch image prompts" }, + { status: 500 } + ); + } +} + +// POST /api/image-prompts +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + const { + title, + description, + prompt, + negativePrompt, + model, + modelVersion, + aspectRatio, + style, + previewImage, + gallery, + category, + tags, + creatorId, + } = body; + + if (!title || !prompt || !model) { + return NextResponse.json( + { error: "title, prompt, and model are required" }, + { status: 400 } + ); + } + + // Generate slug from title + const slug = title + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/(^-|-$)/g, "") + + "-" + + Date.now().toString(36); + + const imagePrompt = await prisma.imagePrompt.create({ + data: { + slug, + title, + description, + prompt, + negativePrompt, + model, + modelVersion, + aspectRatio, + style, + previewImage, + gallery: gallery || [], + category, + tags: tags || [], + creatorId, + }, + include: { + creator: { + select: { + id: true, + name: true, + username: true, + }, + }, + }, + }); + + return NextResponse.json(imagePrompt); + } catch (error) { + console.error("Error creating image prompt:", error); + return NextResponse.json( + { error: "Failed to create image prompt" }, + { status: 500 } + ); + } +} diff --git a/src/app/api/leaderboard/route.ts b/src/app/api/leaderboard/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..8663b3640ca12e8d585657156c2afc9fb70fca3c --- /dev/null +++ b/src/app/api/leaderboard/route.ts @@ -0,0 +1,149 @@ +import { NextRequest, NextResponse } from "next/server"; +import { prisma } from "@/lib/prisma"; + +interface LeaderboardUser { + id: string; + name: string | null; + username: string | null; + image: string | null; + bio: string | null; + rank: string | null; + totalRuns: number; + totalStars: number; + totalRemixes: number; + createdAt: Date; + _count: { + prompts: number; + }; +} + +// GET /api/leaderboard +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url); + const timeframe = searchParams.get("timeframe") || "all-time"; + const sortBy = searchParams.get("sortBy") || "total-runs"; + const limit = parseInt(searchParams.get("limit") || "50"); + const offset = parseInt(searchParams.get("offset") || "0"); + + // Calculate date filter based on timeframe + let dateFilter: Date | undefined; + if (timeframe === "weekly") { + dateFilter = new Date(); + dateFilter.setDate(dateFilter.getDate() - 7); + } else if (timeframe === "monthly") { + dateFilter = new Date(); + dateFilter.setMonth(dateFilter.getMonth() - 1); + } + + const orderBy: Record = {}; + switch (sortBy) { + case "stars": + orderBy.totalStars = "desc"; + break; + case "remixes": + orderBy.totalRemixes = "desc"; + break; + case "prompts": + // We'll sort by prompts count after fetching + orderBy.totalRuns = "desc"; + break; + default: + orderBy.totalRuns = "desc"; + } + + // Fetch top creators + const users = await prisma.user.findMany({ + where: { + prompts: { + some: { + visibility: "public", + }, + }, + }, + select: { + id: true, + name: true, + username: true, + image: true, + bio: true, + rank: true, + totalRuns: true, + totalStars: true, + totalRemixes: true, + createdAt: true, + _count: { + select: { + prompts: { + where: { + visibility: "public", + }, + }, + }, + }, + }, + orderBy, + take: limit, + skip: offset, + }); + + // Get total count + const total = await prisma.user.count({ + where: { + prompts: { + some: { + visibility: "public", + }, + }, + }, + }); + + // Transform data + const leaderboard = (users as LeaderboardUser[]).map((user: LeaderboardUser, index: number) => ({ + rank: offset + index + 1, + user: { + id: user.id, + name: user.name, + username: user.username, + image: user.image, + bio: user.bio, + rank: user.rank, + }, + stats: { + prompts: user._count.prompts, + totalRuns: user.totalRuns, + totalStars: user.totalStars, + totalRemixes: user.totalRemixes, + weeklyGrowth: Math.random() * 30, // Placeholder - would calculate from actual data + }, + })); + + // Get aggregate stats + const aggregateStats = await prisma.user.aggregate({ + _count: true, + _sum: { + totalRuns: true, + totalStars: true, + totalRemixes: true, + }, + }); + + return NextResponse.json({ + leaderboard, + total, + hasMore: offset + limit < total, + aggregateStats: { + totalCreators: aggregateStats._count, + totalRuns: aggregateStats._sum.totalRuns || 0, + totalStars: aggregateStats._sum.totalStars || 0, + totalRemixes: aggregateStats._sum.totalRemixes || 0, + }, + }); + } catch (error) { + console.error("Error fetching leaderboard:", error); + return NextResponse.json( + { error: "Failed to fetch leaderboard" }, + { status: 500 } + ); + } +} diff --git a/src/app/api/messages/[id]/route.ts b/src/app/api/messages/[id]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..674f8131768df370e1a40917052d962cb1e6b9cf --- /dev/null +++ b/src/app/api/messages/[id]/route.ts @@ -0,0 +1,161 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" +import { stackServerApp } from "@/lib/stack-server" + +// GET - Get messages in a conversation +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const { id } = await params + const { searchParams } = new URL(request.url) + const limit = parseInt(searchParams.get("limit") || "50") + const before = searchParams.get("before") + + // Verify user is participant + const conversation = await prisma.conversation.findUnique({ + where: { id }, + }) + + if (!conversation) { + return NextResponse.json( + { error: "Conversation not found" }, + { status: 404 } + ) + } + + if (conversation.participant1 !== user.id && conversation.participant2 !== user.id) { + return NextResponse.json( + { error: "Access denied" }, + { status: 403 } + ) + } + + const whereClause: Record = { conversationId: id } + if (before) { + whereClause.createdAt = { lt: new Date(before) } + } + + const messages = await prisma.message.findMany({ + where: whereClause, + orderBy: { createdAt: "desc" }, + take: limit, + }) + + // Mark messages as read + await prisma.message.updateMany({ + where: { + conversationId: id, + senderId: { not: user.id }, + isRead: false, + }, + data: { isRead: true }, + }) + + // Get other user info + const otherId = conversation.participant1 === user.id + ? conversation.participant2 + : conversation.participant1 + + const otherUser = await prisma.user.findUnique({ + where: { id: otherId }, + select: { + id: true, + name: true, + username: true, + image: true, + }, + }) + + return NextResponse.json({ + messages: messages.reverse(), + otherUser, + hasMore: messages.length === limit, + }) + } catch (error) { + console.error("Error fetching messages:", error) + return NextResponse.json( + { error: "Failed to fetch messages" }, + { status: 500 } + ) + } +} + +// POST - Send a message in conversation +export async function POST( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + try { + const user = await stackServerApp.getUser() + if (!user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const { id } = await params + const { content } = await request.json() + + if (!content) { + return NextResponse.json( + { error: "Content is required" }, + { status: 400 } + ) + } + + // Verify user is participant + const conversation = await prisma.conversation.findUnique({ + where: { id }, + }) + + if (!conversation) { + return NextResponse.json( + { error: "Conversation not found" }, + { status: 404 } + ) + } + + if (conversation.participant1 !== user.id && conversation.participant2 !== user.id) { + return NextResponse.json( + { error: "Access denied" }, + { status: 403 } + ) + } + + const message = await prisma.message.create({ + data: { + content, + senderId: user.id, + conversationId: id, + }, + }) + + // Update conversation + await prisma.conversation.update({ + where: { id }, + data: { + lastMessage: content, + lastActivity: new Date(), + }, + }) + + return NextResponse.json(message) + } catch (error) { + console.error("Error sending message:", error) + return NextResponse.json( + { error: "Failed to send message" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/messages/route.ts b/src/app/api/messages/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8c00a1013dbeca0d8825faac342bc5c86b8d2ca --- /dev/null +++ b/src/app/api/messages/route.ts @@ -0,0 +1,165 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" +import { getAuthUser } from "@/lib/auth" +import { sendMessageSchema, parseBody } from "@/lib/validations" +import { checkRateLimit, getClientIdentifier } from "@/lib/rate-limit" +import { sanitizeText } from "@/lib/api-utils" + +// GET - Get conversations for current user (fixed N+1 with participant include) +export async function GET(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + const conversations = await prisma.conversation.findMany({ + where: { + OR: [ + { participant1: authUser.id }, + { participant2: authUser.id }, + ], + }, + orderBy: { lastActivity: "desc" }, + include: { + messages: { + orderBy: { createdAt: "desc" }, + take: 1, + }, + _count: { + select: { + messages: { + where: { + isRead: false, + senderId: { not: authUser.id }, + }, + }, + }, + }, + }, + }) + + // Get other participant info (batch query instead of N+1) + const participantIds = conversations.map(c => + c.participant1 === authUser.id ? c.participant2 : c.participant1 + ) + + const users = await prisma.user.findMany({ + where: { id: { in: participantIds } }, + select: { + id: true, + name: true, + username: true, + image: true, + }, + }) + const userMap = new Map(users.map(u => [u.id, u])) + + const conversationsWithUsers = conversations.map(conv => { + const otherId = conv.participant1 === authUser.id ? conv.participant2 : conv.participant1 + return { + ...conv, + otherUser: userMap.get(otherId) || null, + unreadCount: conv._count.messages, + lastMessage: conv.messages[0] || null, + } + }) + + return NextResponse.json({ conversations: conversationsWithUsers }) + } catch (error) { + console.error("Error fetching conversations:", error) + return NextResponse.json( + { error: "Failed to fetch conversations" }, + { status: 500 } + ) + } +} + +// POST - Start a new conversation or send message (rate limited, validated, sanitized) +export async function POST(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ) + } + + // Rate limit + const identifier = getClientIdentifier(request, authUser.id) + const rateLimit = await checkRateLimit(`messages:${identifier}`, true) + if (!rateLimit.success) { + return NextResponse.json({ error: rateLimit.error }, { status: 429 }) + } + + const body = await request.json() + const parsed = parseBody(sendMessageSchema, body) + if (!parsed.success) return parsed.response + + const { recipientId, content } = parsed.data + + if (recipientId === authUser.id) { + return NextResponse.json( + { error: "Cannot message yourself" }, + { status: 400 } + ) + } + + // Sanitize content + const sanitizedContent = sanitizeText(content, 5000) + if (!sanitizedContent) { + return NextResponse.json( + { error: "Message content cannot be empty" }, + { status: 400 } + ) + } + + // Find or create conversation โ€” always sort IDs for consistent unique constraint + const [p1, p2] = [authUser.id, recipientId].sort() + + let conversation = await prisma.conversation.findUnique({ + where: { + participant1_participant2: { participant1: p1, participant2: p2 }, + }, + }) + + if (!conversation) { + conversation = await prisma.conversation.create({ + data: { + participant1: p1, + participant2: p2, + }, + }) + } + + // Create message + const message = await prisma.message.create({ + data: { + content: sanitizedContent, + senderId: authUser.id, + conversationId: conversation.id, + }, + }) + + // Update conversation + await prisma.conversation.update({ + where: { id: conversation.id }, + data: { + lastMessage: sanitizedContent, + lastActivity: new Date(), + }, + }) + + return NextResponse.json({ conversation, message }) + } catch (error) { + console.error("Error sending message:", error) + return NextResponse.json( + { error: "Failed to send message" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/notifications/route.ts b/src/app/api/notifications/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..f07705500d8a24acf154131e24786fb0fac3f500 --- /dev/null +++ b/src/app/api/notifications/route.ts @@ -0,0 +1,71 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' + +// GET /api/notifications โ€” get current user's notifications +export async function GET(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const { searchParams } = new URL(request.url) + const unreadOnly = searchParams.get('unread') === 'true' + const limit = Math.min(parseInt(searchParams.get('limit') || '20'), 50) + + const where: Record = { userId: authUser.id } + if (unreadOnly) { + where.isRead = false + } + + const [notifications, unreadCount] = await Promise.all([ + prisma.notification.findMany({ + where, + orderBy: { createdAt: 'desc' }, + take: limit, + }), + prisma.notification.count({ + where: { userId: authUser.id, isRead: false }, + }), + ]) + + return NextResponse.json({ notifications, unreadCount }) + } catch (error) { + console.error('Error fetching notifications:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// PATCH /api/notifications โ€” mark notifications as read +export async function PATCH(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const body = await request.json() + const { notificationIds, markAllRead } = body + + if (markAllRead) { + await prisma.notification.updateMany({ + where: { userId: authUser.id, isRead: false }, + data: { isRead: true }, + }) + } else if (notificationIds && Array.isArray(notificationIds)) { + await prisma.notification.updateMany({ + where: { + id: { in: notificationIds }, + userId: authUser.id, + }, + data: { isRead: true }, + }) + } + + return NextResponse.json({ success: true }) + } catch (error) { + console.error('Error updating notifications:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/og/route.tsx b/src/app/api/og/route.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2e99d6d4428b9a1fe17949edd786ee72a7f2262a --- /dev/null +++ b/src/app/api/og/route.tsx @@ -0,0 +1,253 @@ +import { ImageResponse } from 'next/og' +import { NextRequest } from 'next/server' + +export const runtime = 'edge' + +/** + * GET /api/og + * + * Generates dynamic Open Graph images for prompts, tools, and creators. + * + * Params: + * title - main heading text + * description - subtitle text + * type - default | prompt | tool | creator | collection + * category - category badge text + * runs - formatted run count (e.g. "1.2K") + * stars - formatted star count + * remixes - formatted remix count + * creator - creator name + * avatar - creator avatar URL + * badge - special badge text (e.g. "Trending ๐Ÿ”ฅ") + */ +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url) + + const title = searchParams.get('title') || 'OpenPrompt' + const description = searchParams.get('description') || 'The GitHub for AI Prompts' + const type = searchParams.get('type') || 'default' + const category = searchParams.get('category') || '' + const runs = searchParams.get('runs') || '' + const stars = searchParams.get('stars') || '' + const remixes = searchParams.get('remixes') || '' + const creator = searchParams.get('creator') || '' + const badge = searchParams.get('badge') || '' + + // Type to color & icon mapping + const typeConfig: Record = { + prompt: { color: '#6366f1', label: 'AI Prompt', emoji: '๐Ÿ“' }, + tool: { color: '#14b8a6', label: 'AI Tool', emoji: '๐Ÿ› ๏ธ' }, + creator: { color: '#f43f5e', label: 'Creator', emoji: '๐Ÿ‘ค' }, + collection: { color: '#8b5cf6', label: 'Collection', emoji: '๐Ÿ“' }, + default: { color: '#6366f1', label: '', emoji: '' }, + } + + const config = typeConfig[type] || typeConfig.default + const hasStats = runs || stars || remixes + + return new ImageResponse( + ( +
+ {/* Top accent bar */} +
+ + {/* Logo row */} +
+
+ โœฆ +
+ + OpenPrompt + + + {/* Spacer */} +
+ + {/* Type badge */} + {type !== 'default' && ( +
+ {config.emoji} + + {config.label} + +
+ )} +
+ + {/* Category + badge */} + {(category || badge) && ( +
+ {category && ( + + {category} + + )} + {badge && ( + + {badge} + + )} +
+ )} + + {/* Main title */} +

50 ? 44 : title.length > 30 ? 54 : 64, + fontWeight: 800, + color: 'white', + margin: 0, + lineHeight: 1.15, + maxWidth: '90%', + letterSpacing: '-0.02em', + }} + > + {title} +

+ + {/* Description */} + {description && ( +

+ {description.length > 120 ? description.slice(0, 117) + 'โ€ฆ' : description} +

+ )} + + {/* Spacer to push bottom content down */} +
+ + {/* Stats row */} + {hasStats && ( +
+ {runs && ( +
+ โ–ถ + {runs} + runs +
+ )} + {stars && ( +
+ โ˜… + {stars} + stars +
+ )} + {remixes && ( +
+ โ‘‚ + {remixes} + remixes +
+ )} + {creator && ( +
+ โ—ˆ + by + {creator} +
+ )} +
+ )} + + {/* Footer */} +
+
+ 177+ AI Tools + ยท + Multi-Model Support + ยท + Free to Use +
+ open-prompt.netlify.app +
+
+ ), + { + width: 1200, + height: 630, + }, + ) +} diff --git a/src/app/api/ollama/route.ts b/src/app/api/ollama/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..80a8b9ddae25b97f52d4c5045efae65946132afb --- /dev/null +++ b/src/app/api/ollama/route.ts @@ -0,0 +1,135 @@ +import { NextRequest, NextResponse } from 'next/server' + +const OLLAMA_CLOUD_URL = "https://ollama.com" +const DEFAULT_LOCAL_URL = "http://localhost:11434" + +// GET - List models (for both local and cloud) +export async function GET(request: NextRequest) { + const searchParams = request.nextUrl.searchParams + const mode = searchParams.get("mode") || "local" + const customUrl = searchParams.get("url") || DEFAULT_LOCAL_URL + const apiKey = request.headers.get("x-ollama-api-key") + + try { + const baseUrl = mode === "cloud" ? OLLAMA_CLOUD_URL : customUrl + const headers: HeadersInit = { + "Content-Type": "application/json", + } + + if (mode === "cloud" && apiKey) { + headers["Authorization"] = `Bearer ${apiKey}` + } + + const response = await fetch(`${baseUrl}/api/tags`, { + method: "GET", + headers, + }) + + if (!response.ok) { + if (response.status === 401) { + return NextResponse.json( + { error: "Invalid API key. Please check your Ollama Cloud API key." }, + { status: 401 } + ) + } + return NextResponse.json( + { error: `HTTP ${response.status}: ${response.statusText}` }, + { status: response.status } + ) + } + + const data = await response.json() + return NextResponse.json(data) + } catch (error) { + const message = error instanceof Error ? error.message : "Connection failed" + return NextResponse.json({ error: message }, { status: 500 }) + } +} + +// POST - Generate/Chat with models +export async function POST(request: NextRequest) { + try { + const body = await request.json() + const { + prompt, + model, + ollamaUrl = DEFAULT_LOCAL_URL, + mode = "local", + apiKey + } = body + + if (!prompt) { + return NextResponse.json({ error: 'Prompt is required' }, { status: 400 }) + } + + if (!model) { + return NextResponse.json({ error: 'Model is required' }, { status: 400 }) + } + + const baseUrl = mode === "cloud" ? OLLAMA_CLOUD_URL : ollamaUrl + const headers: HeadersInit = { 'Content-Type': 'application/json' } + + if (mode === "cloud" && apiKey) { + headers["Authorization"] = `Bearer ${apiKey}` + } + + // Stream the response from Ollama + const response = await fetch(`${baseUrl}/api/generate`, { + method: 'POST', + headers, + body: JSON.stringify({ + model, + prompt, + stream: true, + }), + }) + + if (!response.ok) { + const error = await response.text() + return NextResponse.json( + { error: `Ollama error: ${error}` }, + { status: response.status } + ) + } + + // Create a TransformStream to process the Ollama response + const encoder = new TextEncoder() + const decoder = new TextDecoder() + + const transformStream = new TransformStream({ + async transform(chunk, controller) { + const text = decoder.decode(chunk) + + // Ollama sends newline-delimited JSON + const lines = text.split('\n').filter(line => line.trim()) + + for (const line of lines) { + try { + const json = JSON.parse(line) + if (json.response) { + controller.enqueue(encoder.encode(json.response)) + } + } catch (e) { + // Skip malformed JSON + } + } + }, + }) + + // Pipe the response through our transform + const readable = response.body?.pipeThrough(transformStream) + + return new Response(readable, { + headers: { + 'Content-Type': 'text/plain; charset=utf-8', + 'Transfer-Encoding': 'chunked', + }, + }) + } catch (error) { + console.error('Ollama API error:', error) + return NextResponse.json( + { error: error instanceof Error ? error.message : 'Failed to connect to Ollama' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/profile/route.ts b/src/app/api/profile/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d77caf62bebfcbff371fceeded00072f0309047 --- /dev/null +++ b/src/app/api/profile/route.ts @@ -0,0 +1,215 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' +import { updateProfileSchema, syncProfileSchema, parseBody } from '@/lib/validations' + +export const dynamic = 'force-dynamic' + +// GET - Fetch user profile +// Only the profile owner can see private fields (email, notification prefs) +export async function GET(req: Request) { + try { + const { searchParams } = new URL(req.url) + const userId = searchParams.get('userId') + const username = searchParams.get('username') + + if (!userId && !username) { + return NextResponse.json( + { error: 'userId or username required' }, + { status: 400 } + ) + } + + // Check if the viewer is the profile owner + const authUser = await getAuthUser() + const isOwner = authUser && ( + (userId && authUser.id === userId) || + false // username check happens after fetch + ) + + const user = await prisma.user.findFirst({ + where: userId ? { id: userId } : { username }, + select: { + id: true, + name: true, + username: true, + image: true, + bio: true, + rank: true, + totalRuns: true, + totalStars: true, + totalRemixes: true, + socialLinks: true, + createdAt: true, + // Sensitive fields โ€” only for owner + email: true, + notifyEmail: true, + notifyStars: true, + notifyRemixes: true, + _count: { + select: { + prompts: true, + collections: true, + }, + }, + }, + }) + + if (!user) { + return NextResponse.json( + { error: 'User not found' }, + { status: 404 } + ) + } + + // Strip sensitive fields if not the owner + const isRealOwner = isOwner || (authUser && authUser.id === user.id) + if (!isRealOwner) { + return NextResponse.json({ + id: user.id, + name: user.name, + username: user.username, + image: user.image, + bio: user.bio, + rank: user.rank, + totalRuns: user.totalRuns, + totalStars: user.totalStars, + totalRemixes: user.totalRemixes, + socialLinks: user.socialLinks, + createdAt: user.createdAt, + _count: user._count, + }) + } + + return NextResponse.json(user) + } catch (error) { + console.error('Get profile error:', error) + return NextResponse.json( + { error: 'Failed to fetch profile' }, + { status: 500 } + ) + } +} + +// PUT - Update user profile โ€” requires authentication (uses server-side auth, not client userId) +export async function PUT(req: Request) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const body = await req.json() + const parsed = parseBody(updateProfileSchema, body) + if (!parsed.success) return parsed.response + + const { + name, + username, + bio, + socialLinks, + image, + notifyEmail, + notifyStars, + notifyRemixes + } = parsed.data + + // Check if username is taken (if changing username) + if (username) { + const existingUser = await prisma.user.findFirst({ + where: { + username, + NOT: { id: authUser.id }, + }, + }) + + if (existingUser) { + return NextResponse.json( + { error: 'Username is already taken' }, + { status: 409 } + ) + } + } + + // Upsert โ€” uses authUser.id from server session, NOT from client body + const updatedUser = await prisma.user.upsert({ + where: { id: authUser.id }, + create: { + id: authUser.id, + email: authUser.email || `${authUser.id}@stackauth.local`, + name: name || null, + username: username || null, + bio: bio || null, + image: image || null, + notifyEmail: notifyEmail ?? true, + notifyStars: notifyStars ?? true, + notifyRemixes: notifyRemixes ?? true, + }, + update: { + ...(name !== undefined && { name }), + ...(username !== undefined && { username }), + ...(bio !== undefined && { bio }), + ...(socialLinks !== undefined && { socialLinks }), + ...(image !== undefined && { image }), + ...(notifyEmail !== undefined && { notifyEmail }), + ...(notifyStars !== undefined && { notifyStars }), + ...(notifyRemixes !== undefined && { notifyRemixes }), + }, + select: { + id: true, + name: true, + username: true, + image: true, + bio: true, + socialLinks: true, + notifyEmail: true, + notifyStars: true, + notifyRemixes: true, + }, + }) + + return NextResponse.json(updatedUser) + } catch (error) { + console.error('Update profile error:', error) + return NextResponse.json( + { error: 'Failed to update profile' }, + { status: 500 } + ) + } +} + +// POST - Create or sync user from Stack Auth +export async function POST(req: Request) { + try { + const body = await req.json() + const parsed = parseBody(syncProfileSchema, body) + if (!parsed.success) return parsed.response + + const { id, email, name, image } = parsed.data + + // Upsert user - create if doesn't exist, update if does + const user = await prisma.user.upsert({ + where: { id }, + create: { + id, + email, + name: name || null, + image: image || null, + username: email.split('@')[0], // Default username from email + }, + update: { + email, + name: name || null, + image: image || null, + }, + }) + + return NextResponse.json(user) + } catch (error) { + console.error('Sync user error:', error) + return NextResponse.json( + { error: 'Failed to sync user' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/prompts/[id]/versions/route.ts b/src/app/api/prompts/[id]/versions/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6229f3357d8aa833f288756dc8807f9540724c4 --- /dev/null +++ b/src/app/api/prompts/[id]/versions/route.ts @@ -0,0 +1,46 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +/** + * GET /api/prompts/[id]/versions + * Returns the version history for a prompt. + * + * Only owners can see private prompt versions. + * Public prompts show versions to everyone. + */ +export async function GET( + _request: NextRequest, + { params }: { params: Promise<{ id: string }> }, +) { + try { + const { id } = await params + + // Verify the prompt exists and is accessible + const prompt = await prisma.prompt.findUnique({ + where: { id }, + select: { id: true, visibility: true, creatorId: true }, + }) + + if (!prompt || prompt.visibility === 'private') { + return NextResponse.json({ error: 'Not found' }, { status: 404 }) + } + + const versions = await prisma.promptVersion.findMany({ + where: { promptId: id }, + orderBy: { version: 'desc' }, + select: { + id: true, + version: true, + title: true, + template: true, + changeNote: true, + createdAt: true, + }, + }) + + return NextResponse.json({ versions }) + } catch (error) { + console.error('GET /api/prompts/[id]/versions error:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/prompts/[slug]/fork-tree/route.ts b/src/app/api/prompts/[slug]/fork-tree/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..65caec6cb15e85592e95de1f9ecd243e66ceacb6 --- /dev/null +++ b/src/app/api/prompts/[slug]/fork-tree/route.ts @@ -0,0 +1,98 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ slug: string }> } +) { + const { slug } = await params + + try { + // Get the current prompt + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { + id: true, + parentId: true, + } + }) + + if (!prompt) { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + // Find the root of the tree (original prompt) + let rootId = prompt.id + let currentParentId = prompt.parentId + + while (currentParentId) { + const parent = await prisma.prompt.findUnique({ + where: { id: currentParentId }, + select: { id: true, parentId: true } + }) + if (parent) { + rootId = parent.id + currentParentId = parent.parentId + } else { + break + } + } + + // Get all prompts in this tree (recursive CTE would be ideal, but we'll do it manually) + // First get the root + const allPrompts = new Map() + + const fetchWithRemixes = async (id: string) => { + const p = await prisma.prompt.findUnique({ + where: { id }, + select: { + id: true, + slug: true, + title: true, + parentId: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + creator: { + select: { + name: true, + username: true, + } + }, + remixes: { + select: { id: true } + } + } + }) + + if (p && !allPrompts.has(p.id)) { + allPrompts.set(p.id, { + id: p.id, + slug: p.slug, + title: p.title, + parentId: p.parentId, + totalRuns: p.totalRuns, + starsCount: p.starsCount, + remixesCount: p.remixesCount, + creator: p.creator, + }) + + // Recursively fetch remixes + for (const remix of p.remixes) { + await fetchWithRemixes(remix.id) + } + } + } + + await fetchWithRemixes(rootId) + + return NextResponse.json({ + rootId, + currentSlug: slug, + prompts: Array.from(allPrompts.values()) + }) + } catch (error) { + console.error('Error fetching fork tree:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/prompts/[slug]/remixes/route.ts b/src/app/api/prompts/[slug]/remixes/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..771700f358e135cde319abe4b0d1b18e9bcbad1c --- /dev/null +++ b/src/app/api/prompts/[slug]/remixes/route.ts @@ -0,0 +1,68 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +export const dynamic = 'force-dynamic' + +interface RouteContext { + params: Promise<{ slug: string }> +} + +// GET - Fetch remixes of a prompt +export async function GET(req: Request, context: RouteContext) { + try { + const { slug } = await context.params + + // Find prompt by slug + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { id: true } + }) + + if (!prompt) { + return NextResponse.json( + { error: 'Prompt not found' }, + { status: 404 } + ) + } + + // Fetch all remixes of this prompt + const remixes = await prisma.prompt.findMany({ + where: { + parentId: prompt.id, + visibility: 'public', + }, + select: { + id: true, + slug: true, + title: true, + description: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + createdAt: true, + creator: { + select: { + id: true, + name: true, + username: true, + image: true, + }, + }, + }, + orderBy: [ + { totalRuns: 'desc' }, + { createdAt: 'desc' }, + ], + take: 20, // Limit to 20 remixes + }) + + return NextResponse.json({ remixes }) + + } catch (error) { + console.error('Get remixes error:', error) + return NextResponse.json( + { error: 'Failed to fetch remixes' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/prompts/[slug]/route.ts b/src/app/api/prompts/[slug]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..20d7e20bd63a430ec08a91e550021bd6ae5cf9b0 --- /dev/null +++ b/src/app/api/prompts/[slug]/route.ts @@ -0,0 +1,151 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +export const dynamic = 'force-dynamic' + +interface RouteContext { + params: Promise<{ slug: string }> +} + +// GET - Fetch single prompt by slug +export async function GET(req: Request, context: RouteContext) { + try { + const { slug } = await context.params + + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + include: { + creator: { + select: { + id: true, + name: true, + username: true, + image: true, + }, + }, + parent: { + select: { + id: true, + slug: true, + title: true, + }, + }, + _count: { + select: { + remixes: true, + stars: true, + }, + }, + }, + }) + + if (!prompt) { + return NextResponse.json( + { error: 'Prompt not found' }, + { status: 404 } + ) + } + + return NextResponse.json(prompt) + } catch (error) { + console.error('Get prompt error:', error) + return NextResponse.json( + { error: 'Failed to fetch prompt' }, + { status: 500 } + ) + } +} + +// PUT - Update prompt +export async function PUT(req: Request, context: RouteContext) { + try { + const { slug } = await context.params + const body = await req.json() + const { title, description, template, schema, category, tags, modelDefault, visibility, userId } = body + + // Find the prompt first + const existingPrompt = await prisma.prompt.findUnique({ + where: { slug }, + }) + + if (!existingPrompt) { + return NextResponse.json( + { error: 'Prompt not found' }, + { status: 404 } + ) + } + + // Check if user owns the prompt + if (existingPrompt.creatorId && existingPrompt.creatorId !== userId) { + return NextResponse.json( + { error: 'You can only edit your own prompts' }, + { status: 403 } + ) + } + + // Update the prompt + const updatedPrompt = await prisma.prompt.update({ + where: { slug }, + data: { + ...(title && { title }), + ...(description !== undefined && { description }), + ...(template && { template }), + ...(schema && { schema }), + ...(category !== undefined && { category }), + ...(tags && { tags }), + ...(modelDefault && { modelDefault }), + ...(visibility && { visibility }), + }, + }) + + return NextResponse.json(updatedPrompt) + } catch (error) { + console.error('Update prompt error:', error) + return NextResponse.json( + { error: 'Failed to update prompt' }, + { status: 500 } + ) + } +} + +// DELETE - Delete prompt +export async function DELETE(req: Request, context: RouteContext) { + try { + const { slug } = await context.params + const { searchParams } = new URL(req.url) + const userId = searchParams.get('userId') + + // Find the prompt first + const existingPrompt = await prisma.prompt.findUnique({ + where: { slug }, + }) + + if (!existingPrompt) { + return NextResponse.json( + { error: 'Prompt not found' }, + { status: 404 } + ) + } + + // Check if user owns the prompt + if (existingPrompt.creatorId && existingPrompt.creatorId !== userId) { + return NextResponse.json( + { error: 'You can only delete your own prompts' }, + { status: 403 } + ) + } + + // Delete the prompt (cascades to stars, runs, etc.) + await prisma.prompt.delete({ + where: { slug }, + }) + + return NextResponse.json({ success: true, message: 'Prompt deleted' }) + } catch (error) { + console.error('Delete prompt error:', error) + return NextResponse.json( + { error: 'Failed to delete prompt' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/prompts/[slug]/saved-runs/route.ts b/src/app/api/prompts/[slug]/saved-runs/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..00e5c8aa55a7db1cb84fa7749d20206ab435c3a1 --- /dev/null +++ b/src/app/api/prompts/[slug]/saved-runs/route.ts @@ -0,0 +1,87 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +interface RouteParams { + params: Promise<{ slug: string }> +} + +// GET /api/prompts/[slug]/saved-runs - Get saved runs for a prompt +export async function GET(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + const { searchParams } = new URL(request.url) + const userId = searchParams.get('userId') + + try { + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { id: true, visibility: true, creatorId: true } + }) + + if (!prompt) { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + const where: any = { promptId: prompt.id } + + // If private, only show to creator + if (prompt.visibility === 'private') { + if (!userId || userId !== prompt.creatorId) { + return NextResponse.json({ runs: [] }) + } + where.userId = userId + } + + const runs = await prisma.savedPromptRun.findMany({ + where, + orderBy: { createdAt: 'desc' }, + take: 50, + }) + + return NextResponse.json({ runs }) + } catch (error) { + console.error('Error fetching saved runs:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// POST /api/prompts/[slug]/saved-runs - Save a prompt run +export async function POST(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + + try { + const body = await request.json() + const { userId, name, variables, output, model } = body + + if (!output || !model) { + return NextResponse.json( + { error: 'output and model are required' }, + { status: 400 } + ) + } + + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { id: true } + }) + + if (!prompt) { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + const run = await prisma.savedPromptRun.create({ + data: { + promptId: prompt.id, + userId: userId || null, + name: name || null, + variables: variables || null, + output, + model, + } + }) + + return NextResponse.json(run, { status: 201 }) + } catch (error) { + console.error('Error saving prompt run:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/prompts/[slug]/versions/route.ts b/src/app/api/prompts/[slug]/versions/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e4c017880e5ed0153883f8fc1a638c514c360a9 --- /dev/null +++ b/src/app/api/prompts/[slug]/versions/route.ts @@ -0,0 +1,91 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' + +// GET /api/prompts/[slug]/versions โ€” get version history for a prompt +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ slug: string }> } +) { + try { + const { slug } = await params + + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { id: true, creatorId: true }, + }) + + if (!prompt) { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + const versions = await prisma.promptVersion.findMany({ + where: { promptId: prompt.id }, + orderBy: { version: 'desc' }, + take: 50, + }) + + return NextResponse.json({ versions }) + } catch (error) { + console.error('Error fetching versions:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// POST /api/prompts/[slug]/versions โ€” save a new version (auto-saved on edit) +export async function POST( + request: NextRequest, + { params }: { params: Promise<{ slug: string }> } +) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const { slug } = await params + + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { id: true, creatorId: true, title: true, template: true, schema: true }, + }) + + if (!prompt) { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + // Only the creator can save versions + if (prompt.creatorId !== authUser.id) { + return NextResponse.json({ error: 'Only the creator can save versions' }, { status: 403 }) + } + + const body = await request.json() + const { changeNote } = body + + // Get the latest version number + const latestVersion = await prisma.promptVersion.findFirst({ + where: { promptId: prompt.id }, + orderBy: { version: 'desc' }, + select: { version: true }, + }) + + const newVersion = (latestVersion?.version || 0) + 1 + + // Save current state as a version + const version = await prisma.promptVersion.create({ + data: { + promptId: prompt.id, + version: newVersion, + title: prompt.title, + template: prompt.template, + schema: prompt.schema || { variables: [] }, + changeNote: changeNote || null, + }, + }) + + return NextResponse.json(version, { status: 201 }) + } catch (error) { + console.error('Error creating version:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/prompts/my/route.ts b/src/app/api/prompts/my/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a952744c3d7bcd3c45f285925d63227eb08f5e5 --- /dev/null +++ b/src/app/api/prompts/my/route.ts @@ -0,0 +1,44 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' + +export const dynamic = 'force-dynamic' + +export async function GET() { + try { + // Server-side auth โ€” no more userId from query params + const authUser = await getAuthUser() + + if (!authUser) { + return NextResponse.json( + { error: 'Authentication required', prompts: [] }, + { status: 401 } + ) + } + + const prompts = await prisma.prompt.findMany({ + where: { + creatorId: authUser.id, + }, + include: { + _count: { + select: { + stars: true, + remixes: true, + runs: true, + }, + }, + }, + orderBy: { createdAt: 'desc' }, + }) + + return NextResponse.json({ prompts }) + + } catch (error) { + console.error('Get my prompts error:', error) + return NextResponse.json( + { error: 'Failed to fetch prompts', prompts: [] }, + { status: 500 } + ) + } +} diff --git a/src/app/api/prompts/route.ts b/src/app/api/prompts/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..1e374a36189578f45830ea5870c5c5b9cce72b60 --- /dev/null +++ b/src/app/api/prompts/route.ts @@ -0,0 +1,182 @@ +import { NextResponse } from 'next/server' +import type { Prisma } from '@prisma/client' +import prisma from '@/lib/prisma' +import { generateSlug } from '@/lib/utils' +import { getAuthUser } from '@/lib/auth' +import { createPromptSchema, parseBody } from '@/lib/validations' +import { checkRateLimit, getClientIdentifier } from '@/lib/rate-limit' + +// Force dynamic to prevent static build +export const dynamic = 'force-dynamic' + +export async function POST(req: Request) { + try { + // Server-side auth โ€” require authentication for prompt creation + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json( + { error: 'Authentication required to create prompts' }, + { status: 401 } + ) + } + + // Rate limit + const identifier = getClientIdentifier(req, authUser.id) + const rateLimit = await checkRateLimit(`prompts:${identifier}`, true) + if (!rateLimit.success) { + return NextResponse.json({ error: rateLimit.error }, { status: 429 }) + } + + const body = await req.json() + const parsed = parseBody(createPromptSchema, body) + if (!parsed.success) return parsed.response + + const { + title, + description, + template, + schema, + category, + tags, + modelDefault, + visibility, + } = parsed.data + + // Generate unique slug + const slug = generateSlug(title) + + const prompt = await prisma.prompt.create({ + data: { + slug, + title, + description: description || null, + template, + schema: (schema || { variables: [] }) as Prisma.InputJsonValue, + category: category || null, + tags: tags || [], + modelDefault: modelDefault || 'gpt-4o-mini', + visibility: visibility || 'public', + creatorId: authUser.id, + }, + }) + + // Create initial version entry for version history + await prisma.promptVersion.create({ + data: { + promptId: prompt.id, + version: 1, + title: prompt.title, + template: prompt.template, + schema: prompt.schema as Prisma.InputJsonValue, + changeNote: 'Initial version', + }, + }).catch((err: unknown) => console.error('Version tracking error:', err)) + + return NextResponse.json(prompt) + + } catch (error) { + console.error('Create prompt error:', error) + return NextResponse.json( + { error: 'Failed to create prompt' }, + { status: 500 } + ) + } +} + +export async function GET(req: Request) { + try { + const { searchParams } = new URL(req.url) + const category = searchParams.get('category') + const search = searchParams.get('search') + const sort = searchParams.get('sort') || 'popular' + const limit = Math.min(parseInt(searchParams.get('limit') || '20'), 100) // Cap at 100 + const offset = Math.max(parseInt(searchParams.get('offset') || '0'), 0) + const cursor = searchParams.get('cursor') // For cursor-based pagination + + // Build where clause + const where: Record = { + visibility: 'public', + } + + if (category) { + where.category = category + } + + if (search) { + where.OR = [ + { title: { contains: search, mode: 'insensitive' } }, + { description: { contains: search, mode: 'insensitive' } }, + ] + } + + // Build orderBy based on sort param + const orderBy: Record[] = [] + + switch (sort) { + case 'recent': + orderBy.push({ createdAt: 'desc' }) + break + case 'stars': + orderBy.push({ starsCount: 'desc' }) + break + case 'runs': + orderBy.push({ totalRuns: 'desc' }) + break + default: // popular + orderBy.push({ totalRuns: 'desc' }) + } + + // Add secondary sort by ID for stability + orderBy.push({ id: 'desc' }) + + // Support cursor-based pagination + const paginationArgs: Record = { + take: limit, + } + + if (cursor) { + paginationArgs.skip = 1 // Skip the cursor item itself + paginationArgs.cursor = { id: cursor } + } else { + paginationArgs.skip = offset + } + + const prompts = await prisma.prompt.findMany({ + where, + include: { + creator: { + select: { + id: true, + name: true, + username: true, + image: true, + }, + }, + _count: { + select: { + stars: true, + remixes: true, + }, + }, + }, + orderBy, + ...paginationArgs, + }) + + // Return cursor for next page + const nextCursor = prompts.length === limit ? prompts[prompts.length - 1].id : null + + return NextResponse.json({ + prompts, + nextCursor, + hasMore: !!nextCursor, + }) + + } catch (error) { + console.error('Get prompts error:', error) + return NextResponse.json( + { error: 'Failed to fetch prompts' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/prompts/starred/route.ts b/src/app/api/prompts/starred/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ad8b7be1fd3679c4fe236881fc4bf5e956600f9 --- /dev/null +++ b/src/app/api/prompts/starred/route.ts @@ -0,0 +1,54 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +export const dynamic = 'force-dynamic' + +export async function GET(req: Request) { + try { + const { searchParams } = new URL(req.url) + const userId = searchParams.get('userId') + + if (!userId) { + return NextResponse.json([]) + } + + // Get starred prompt IDs + const stars = await prisma.star.findMany({ + where: { userId }, + select: { promptId: true }, + }) + + const promptIds = stars.map((s: { promptId: string }) => s.promptId) + + if (promptIds.length === 0) { + return NextResponse.json([]) + } + + // Get prompt details + const prompts = await prisma.prompt.findMany({ + where: { + id: { in: promptIds }, + visibility: 'public', + }, + include: { + creator: { + select: { + name: true, + username: true, + image: true, + }, + }, + }, + orderBy: { starsCount: 'desc' }, + }) + + return NextResponse.json(prompts) + + } catch (error) { + console.error('Get starred prompts error:', error) + return NextResponse.json( + { error: 'Failed to fetch starred prompts' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/remix/route.ts b/src/app/api/remix/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..a7385823ef48c6d66ae301c9a23653a3941b8949 --- /dev/null +++ b/src/app/api/remix/route.ts @@ -0,0 +1,70 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { generateSlug } from '@/lib/utils' + +export const dynamic = 'force-dynamic' + +export async function POST(req: Request) { + try { + const { promptId, creatorId } = await req.json() + + if (!promptId) { + return NextResponse.json( + { error: 'promptId is required' }, + { status: 400 } + ) + } + + // Fetch the original prompt + const original = await prisma.prompt.findUnique({ + where: { id: promptId }, + }) + + if (!original) { + return NextResponse.json( + { error: 'Prompt not found' }, + { status: 404 } + ) + } + + // Generate new slug with "remix" suffix + const newSlug = generateSlug(`${original.title} remix`) + + // Create the remix + const remix = await prisma.prompt.create({ + data: { + slug: newSlug, + title: `${original.title} (Remix)`, + description: original.description, + template: original.template, + schema: original.schema ?? { variables: [] }, + category: original.category, + tags: original.tags, + modelDefault: original.modelDefault, + modelAllowed: original.modelAllowed, + visibility: 'public', + parentId: original.id, + creatorId: creatorId || null, + }, + }) + + // Increment remix count on original + await prisma.prompt.update({ + where: { id: original.id }, + data: { remixesCount: { increment: 1 } }, + }) + + return NextResponse.json({ + success: true, + slug: remix.slug, + id: remix.id, + }) + + } catch (error) { + console.error('Remix error:', error) + return NextResponse.json( + { error: 'Failed to create remix' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/run/route.ts b/src/app/api/run/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..245d91476f0155be5f1dee56a4fe3f7181e26ac2 --- /dev/null +++ b/src/app/api/run/route.ts @@ -0,0 +1,296 @@ +import { streamText } from 'ai' +import { openai } from '@ai-sdk/openai' +import { anthropic } from '@ai-sdk/anthropic' +import { google } from '@ai-sdk/google' +import { AI_MODELS, ModelId, DEFAULT_MODEL, isOllamaModel } from '@/types/prompt' +import { checkRateLimit, getClientIdentifier, getRateLimitHeaders } from '@/lib/rate-limit' +import { getCachedResponse } from '@/lib/cache' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' + +// Helper to stream from Ollama +async function streamFromOllama(prompt: string, model: string, ollamaUrl: string) { + const response = await fetch(`${ollamaUrl}/api/generate`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model, + prompt, + stream: true, + }), + }) + + if (!response.ok) { + if (response.status === 404) { + throw new Error(`Ollama model "${model}" not found. Please run: ollama pull ${model}`) + } + const errorText = await response.text().catch(() => '') + throw new Error(`Ollama error: ${response.status}${errorText ? ` - ${errorText}` : ''}`) + } + + // Transform Ollama's response format to plain text stream + const encoder = new TextEncoder() + const decoder = new TextDecoder() + + const transformStream = new TransformStream({ + async transform(chunk, controller) { + const text = decoder.decode(chunk) + const lines = text.split('\n').filter(line => line.trim()) + + for (const line of lines) { + try { + const json = JSON.parse(line) + if (json.response) { + controller.enqueue(encoder.encode(json.response)) + } + } catch { + // Skip malformed JSON + } + } + }, + }) + + return response.body?.pipeThrough(transformStream) +} + +async function verifyTurnstile(token: string): Promise { + const secretKey = process.env.TURNSTILE_SECRET_KEY + + if (!secretKey) { + // Fail closed in production, open in development + if (process.env.NODE_ENV === 'production') { + console.error('Turnstile secret key not configured in production') + return false + } + console.warn('Turnstile not configured, skipping verification in development') + return true + } + + try { + const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + secret: secretKey, + response: token, + }), + }) + + const data = await response.json() + return data.success === true + } catch (error) { + console.error('Turnstile verification error:', error) + return false // Fail closed on error + } +} + +export async function POST(req: Request) { + try { + // Parse body ONCE โ€” fixes the double req.json() bug + const body = await req.json() + + // Zod validation + const { runSchema } = await import('@/lib/validations') + const parsed = runSchema.safeParse(body) + if (!parsed.success) { + return new Response( + JSON.stringify({ error: 'Validation failed', details: parsed.error.issues }), + { status: 400, headers: { 'Content-Type': 'application/json' } } + ) + } + + const { prompt, promptId, model, variables, turnstileToken, ollamaUrl } = parsed.data + + // Get authenticated user server-side (replaces client-sent userId) + const authUser = await getAuthUser() + const userId = authUser?.id ?? null + + // 1. Rate Limiting + const identifier = getClientIdentifier(req, userId ?? undefined) + const rateLimit = await checkRateLimit(identifier, !!userId) + + if (!rateLimit.success) { + const headers = getRateLimitHeaders(rateLimit) + return new Response( + JSON.stringify({ error: rateLimit.error }), + { + status: 429, + headers: { + 'Content-Type': 'application/json', + ...Object.fromEntries(headers.entries()), + }, + } + ) + } + + // 2. Check Cache + const modelId = (model as ModelId) || DEFAULT_MODEL + + // 2.5 Validate model against prompt's allowed list + if (promptId && !isOllamaModel(modelId)) { + const promptRecord = await prisma.prompt.findUnique({ + where: { id: promptId }, + select: { modelAllowed: true }, + }) + if (promptRecord?.modelAllowed?.length && !promptRecord.modelAllowed.includes(modelId)) { + return new Response( + JSON.stringify({ error: `Model "${modelId}" is not allowed for this prompt. Allowed: ${promptRecord.modelAllowed.join(', ')}` }), + { status: 400, headers: { 'Content-Type': 'application/json' } } + ) + } + } + if (promptId && variables) { + const cached = await getCachedResponse(promptId, variables, modelId) + if (cached) { + const headers = getRateLimitHeaders(rateLimit) + headers.set('X-Cache', 'HIT') + + return new Response(cached, { + headers: { + 'Content-Type': 'text/plain', + ...Object.fromEntries(headers.entries()), + }, + }) + } + } + + // 3. Verify Turnstile (bot protection) โ€” require token for unauthenticated users + if (!userId) { + if (!turnstileToken) { + return new Response( + JSON.stringify({ error: 'Bot verification required' }), + { status: 403, headers: { 'Content-Type': 'application/json' } } + ) + } + const isValid = await verifyTurnstile(turnstileToken) + if (!isValid) { + return new Response( + JSON.stringify({ error: 'Bot verification failed' }), + { status: 403, headers: { 'Content-Type': 'application/json' } } + ) + } + } + + // 4. Check if this is an Ollama model + const isOllama = isOllamaModel(modelId) + + if (isOllama) { + // Route to Ollama โ€” use ollamaUrl from the SAME parsed body + const resolvedOllamaUrl = ollamaUrl || "http://localhost:11434" + + try { + const stream = await streamFromOllama(prompt, modelId, resolvedOllamaUrl) + + if (!stream) { + return new Response('Failed to get Ollama stream', { status: 500 }) + } + + // Track run in database (non-blocking) + if (promptId) { + trackRun(promptId, userId, modelId, identifier).catch( + (err: unknown) => console.error('Failed to track run:', err) + ) + } + + const headers = getRateLimitHeaders(rateLimit) + headers.set('X-Cache', 'MISS') + headers.set('X-Model-Type', 'ollama') + + return new Response(stream, { + headers: { + 'Content-Type': 'text/plain; charset=utf-8', + ...Object.fromEntries(headers.entries()), + }, + }) + } catch (error) { + console.error('Ollama error:', error) + return new Response( + `Ollama error: ${error instanceof Error ? error.message : 'Connection failed'}. Make sure Ollama is running.`, + { status: 500 } + ) + } + } + + // 5. Validate cloud model + const modelConfig = AI_MODELS[modelId as ModelId] + if (!modelConfig) { + return new Response('Invalid model', { status: 400 }) + } + + // 6. Select the appropriate AI provider + let aiModel + switch (modelConfig.provider) { + case 'openai': + aiModel = openai(modelId) + break + case 'anthropic': + aiModel = anthropic(modelId) + break + case 'google': + aiModel = google(modelId) + break + default: + aiModel = google(DEFAULT_MODEL) + } + + // 7. Stream the response + const result = await streamText({ + model: aiModel, + prompt, + }) + + // 8. Track run in database (non-blocking) + if (promptId) { + trackRun(promptId, userId, modelId, identifier).catch( + (err: unknown) => console.error('Failed to track run:', err) + ) + } + + // 9. Return streaming response with rate limit headers + const headers = getRateLimitHeaders(rateLimit) + headers.set('X-Cache', 'MISS') + headers.set('X-Model-Type', 'cloud') + + return result.toTextStreamResponse({ + headers: Object.fromEntries(headers.entries()), + }) + + } catch (error) { + console.error('AI Run Error:', error) + + if (error instanceof Response) { + return error // Re-throw auth errors + } + + if (error instanceof Error) { + if (error.message.includes('API key')) { + return new Response('API key not configured. Please add your API keys.', { status: 500 }) + } + return new Response(error.message, { status: 500 }) + } + + return new Response('An unexpected error occurred', { status: 500 }) + } +} + +/** + * Track a run in the database and increment the prompt's totalRuns counter. + * Uses a transaction to keep counts in sync. + */ +async function trackRun(promptId: string, userId: string | null, model: string, ipHash: string) { + await prisma.$transaction([ + prisma.run.create({ + data: { + promptId, + userId: userId || null, + model, + cached: false, + ipHash, + }, + }), + prisma.prompt.update({ + where: { id: promptId }, + data: { totalRuns: { increment: 1 } }, + }), + ]) +} diff --git a/src/app/api/search/route.ts b/src/app/api/search/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c0d3516c452668a98e429fff4fe288e12508b64 --- /dev/null +++ b/src/app/api/search/route.ts @@ -0,0 +1,189 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" +import { generateText } from "ai" +import { openai } from "@ai-sdk/openai" +import { getAuthUser } from "@/lib/auth" +import { checkRateLimit, getClientIdentifier } from "@/lib/rate-limit" +import { redisGet, redisSet } from "@/lib/redis" + +// GET - Search for prompts (rate limited, semantic search cached) +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const query = searchParams.get("q") + const category = searchParams.get("category") + const model = searchParams.get("model") + const semantic = searchParams.get("semantic") === "true" + const limit = Math.min(parseInt(searchParams.get("limit") || "20"), 100) + const offset = Math.max(parseInt(searchParams.get("offset") || "0"), 0) + + if (!query || query.trim().length < 2) { + return NextResponse.json( + { error: "Query must be at least 2 characters" }, + { status: 400 } + ) + } + + // Rate limit โ€” semantic search is expensive, stricter limit + const authUser = await getAuthUser() + const identifier = getClientIdentifier(request, authUser?.id ?? undefined) + const preset = semantic ? `search-semantic:${identifier}` : `search:${identifier}` + const maxReqs = semantic ? 10 : 60 + const rateLimit = await checkRateLimit(preset, !!authUser) + if (!rateLimit.success) { + return NextResponse.json({ error: rateLimit.error }, { status: 429 }) + } + + // Build base query + const whereClause: Record = { + visibility: "public", + } + + if (category && category !== "all") { + whereClause.category = category + } + + if (model) { + whereClause.modelAllowed = { has: model } + } + + // If semantic search is enabled, use AI to expand the query (with caching) + let searchTerms = [query.toLowerCase()] + + if (semantic) { + const cacheKey = `search:semantic:${query.toLowerCase()}` + const cached = await redisGet(cacheKey) + + if (cached) { + searchTerms = cached + } else { + try { + const { text } = await generateText({ + model: openai("gpt-4o-mini"), + prompt: `Given this search query for AI prompts: "${query}" + +Generate 5 related search terms that would help find relevant prompts. Include: +- Synonyms and related concepts +- Common use cases +- Related tasks + +Return ONLY a comma-separated list of terms, nothing else.`, + }) + + const expandedTerms = text.split(",").map(t => t.trim().toLowerCase()) + searchTerms = [...searchTerms, ...expandedTerms] + + // Cache for 1 hour + await redisSet(cacheKey, searchTerms, 3600) + } catch (error) { + console.error("Semantic expansion failed, falling back to basic search:", error) + } + } + } + + // Build OR clause for search โ€” exclude template field (too expensive for ILIKE) + const orClause = searchTerms.flatMap(term => [ + { title: { contains: term, mode: "insensitive" as const } }, + { description: { contains: term, mode: "insensitive" as const } }, + { tags: { has: term } }, + ]) + + // Search prompts with expanded terms + const [prompts, total] = await Promise.all([ + prisma.prompt.findMany({ + where: { + ...whereClause, + OR: orClause, + }, + select: { + id: true, + slug: true, + title: true, + description: true, + category: true, + tags: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + modelDefault: true, + badges: true, + framework: true, + creator: { + select: { + id: true, + name: true, + username: true, + image: true, + } + } + }, + orderBy: [ + { starsCount: "desc" }, + { totalRuns: "desc" }, + ], + take: limit, + skip: offset, + }), + prisma.prompt.count({ + where: { + ...whereClause, + OR: orClause, + }, + }), + ]) + + // Calculate relevance scores for ranking + const scoredPrompts = prompts.map(prompt => { + let score = 0 + const lowerQuery = query.toLowerCase() + + // Title match (highest weight) + if (prompt.title.toLowerCase().includes(lowerQuery)) { + score += 100 + } + + // Description match + if (prompt.description?.toLowerCase().includes(lowerQuery)) { + score += 50 + } + + // Tag match + if (prompt.tags.some(tag => tag.toLowerCase().includes(lowerQuery))) { + score += 30 + } + + // Engagement boost + score += Math.log(prompt.totalRuns + 1) * 5 + score += prompt.starsCount * 2 + score += prompt.remixesCount * 3 + + // Badge boost + if (prompt.badges && prompt.badges.length > 0) { + score += prompt.badges.length * 10 + } + + return { ...prompt, relevanceScore: score } + }) + + // Sort by relevance score + scoredPrompts.sort((a, b) => b.relevanceScore - a.relevanceScore) + + return NextResponse.json({ + prompts: scoredPrompts, + searchTerms: semantic ? searchTerms : [query], + total, + hasMore: offset + prompts.length < total, + }, { + headers: { + // Short cache for search results + 'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=300', + }, + }) + } catch (error) { + console.error("Search error:", error) + return NextResponse.json( + { error: "Search failed" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/star/route.ts b/src/app/api/star/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..abb8db32e1eeb80a30f330960a51c77119b2330a --- /dev/null +++ b/src/app/api/star/route.ts @@ -0,0 +1,130 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { getAuthUser } from '@/lib/auth' + +export const dynamic = 'force-dynamic' + +// Helper to ensure user exists in database +async function ensureUserExists(userId: string, email?: string, name?: string) { + const existingUser = await prisma.user.findUnique({ + where: { id: userId }, + }) + + if (!existingUser) { + await prisma.user.create({ + data: { + id: userId, + email: email || `${userId}@stackauth.local`, + name: name || null, + }, + }) + } +} + +// Toggle star on a prompt โ€” requires authentication +export async function POST(req: Request) { + try { + // Server-side auth โ€” no more trusting client userId + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json( + { error: 'Authentication required' }, + { status: 401 } + ) + } + + const { promptId } = await req.json() + + if (!promptId) { + return NextResponse.json( + { error: 'promptId is required' }, + { status: 400 } + ) + } + + // Ensure user exists in database + await ensureUserExists(authUser.id, authUser.email ?? undefined, authUser.displayName ?? undefined) + + // Check if already starred + const existingStar = await prisma.star.findUnique({ + where: { + userId_promptId: { + userId: authUser.id, + promptId, + }, + }, + }) + + if (existingStar) { + // Unstar โ€” use transaction to keep count in sync + await prisma.$transaction([ + prisma.star.delete({ + where: { + userId_promptId: { + userId: authUser.id, + promptId, + }, + }, + }), + prisma.prompt.update({ + where: { id: promptId }, + data: { starsCount: { decrement: 1 } }, + }), + ]) + + return NextResponse.json({ starred: false }) + } else { + // Star โ€” use transaction to keep count in sync + await prisma.$transaction([ + prisma.star.create({ + data: { + userId: authUser.id, + promptId, + }, + }), + prisma.prompt.update({ + where: { id: promptId }, + data: { starsCount: { increment: 1 } }, + }), + ]) + + return NextResponse.json({ starred: true }) + } + + } catch (error) { + console.error('Star error:', error) + return NextResponse.json( + { error: 'Failed to toggle star' }, + { status: 500 } + ) + } +} + +// Check if current user has starred a prompt +export async function GET(req: Request) { + try { + const { searchParams } = new URL(req.url) + const promptId = searchParams.get('promptId') + + const authUser = await getAuthUser() + + if (!promptId || !authUser) { + return NextResponse.json({ starred: false }) + } + + const star = await prisma.star.findUnique({ + where: { + userId_promptId: { + userId: authUser.id, + promptId, + }, + }, + }) + + return NextResponse.json({ starred: !!star }) + + } catch (error) { + console.error('Check star error:', error) + return NextResponse.json({ starred: false }) + } +} diff --git a/src/app/api/stripe/checkout/route.ts b/src/app/api/stripe/checkout/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..32fb4372648aa6b23565b1f916d4ab604a3328cc --- /dev/null +++ b/src/app/api/stripe/checkout/route.ts @@ -0,0 +1,86 @@ +import { NextRequest, NextResponse } from 'next/server' +import { stripe, STRIPE_PRICES } from '@/lib/stripe' +import { getAuthUser } from '@/lib/auth' +import prisma from '@/lib/prisma' + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +/** + * POST /api/stripe/checkout + * Creates a Stripe Checkout Session for a Pro subscription. + * + * Body: { plan: 'pro_monthly' | 'pro_yearly' } + */ +export async function POST(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const body = await request.json() + const { plan = 'pro_monthly', returnUrl } = body + + const priceId = STRIPE_PRICES[plan as keyof typeof STRIPE_PRICES] + if (!priceId) { + return NextResponse.json({ error: 'Invalid plan selected' }, { status: 400 }) + } + + // Check if user already has a Stripe customer ID + const user = await prisma.user.findUnique({ + where: { id: authUser.id }, + select: { stripeCustomerId: true, email: true, name: true, stripePlan: true }, + }) + + if (!user) { + return NextResponse.json({ error: 'User not found' }, { status: 404 }) + } + + // Already subscribed? + if (user.stripePlan === 'pro') { + return NextResponse.json( + { error: 'You are already on the Pro plan. Manage your subscription in settings.' }, + { status: 400 }, + ) + } + + // Create or retrieve Stripe customer + let customerId = user.stripeCustomerId + if (!customerId) { + const customer = await stripe.customers.create({ + email: user.email, + name: user.name || undefined, + metadata: { userId: authUser.id }, + }) + customerId = customer.id + + // Save customer ID to DB + await prisma.user.update({ + where: { id: authUser.id }, + data: { stripeCustomerId: customerId }, + }) + } + + // Create Checkout Session + const session = await stripe.checkout.sessions.create({ + customer: customerId, + payment_method_types: ['card'], + line_items: [{ price: priceId, quantity: 1 }], + mode: 'subscription', + success_url: `${BASE_URL}/settings?tab=billing&success=true`, + cancel_url: `${returnUrl || `${BASE_URL}/pricing`}?canceled=true`, + allow_promotion_codes: true, + billing_address_collection: 'auto', + subscription_data: { + metadata: { userId: authUser.id }, + trial_period_days: 7, // 7-day free trial + }, + metadata: { userId: authUser.id, plan }, + }) + + return NextResponse.json({ url: session.url, sessionId: session.id }) + } catch (error) { + console.error('Stripe checkout error:', error) + return NextResponse.json({ error: 'Failed to create checkout session' }, { status: 500 }) + } +} diff --git a/src/app/api/stripe/portal/route.ts b/src/app/api/stripe/portal/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..581ce8f2a246d8cbcc3a8f847aebf794cf3285b5 --- /dev/null +++ b/src/app/api/stripe/portal/route.ts @@ -0,0 +1,42 @@ +import { NextResponse } from 'next/server' +import { stripe } from '@/lib/stripe' +import { getAuthUser } from '@/lib/auth' +import prisma from '@/lib/prisma' + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +/** + * POST /api/stripe/portal + * Opens the Stripe Customer Portal for managing subscriptions. + * User must be authenticated and have a Stripe customer ID. + */ +export async function POST() { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) + } + + const user = await prisma.user.findUnique({ + where: { id: authUser.id }, + select: { stripeCustomerId: true }, + }) + + if (!user?.stripeCustomerId) { + return NextResponse.json( + { error: 'No billing account found. Please subscribe first.' }, + { status: 404 }, + ) + } + + const session = await stripe.billingPortal.sessions.create({ + customer: user.stripeCustomerId, + return_url: `${BASE_URL}/settings?tab=billing`, + }) + + return NextResponse.json({ url: session.url }) + } catch (error) { + console.error('Stripe portal error:', error) + return NextResponse.json({ error: 'Failed to open billing portal' }, { status: 500 }) + } +} diff --git a/src/app/api/stripe/webhook/route.ts b/src/app/api/stripe/webhook/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4ce3ac4bc070a848cb4daf4bb93ee0a17d8e355 --- /dev/null +++ b/src/app/api/stripe/webhook/route.ts @@ -0,0 +1,199 @@ +import { NextRequest, NextResponse } from 'next/server' +import Stripe from 'stripe' +import { stripe } from '@/lib/stripe' +import prisma from '@/lib/prisma' + +const WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET || '' + +/** + * POST /api/stripe/webhook + * Handles Stripe webhook events to keep subscription status in sync. + * + * Add this URL to your Stripe Dashboard webhook settings: + * https://your-domain.com/api/stripe/webhook + * + * Required events to enable: + * - checkout.session.completed + * - customer.subscription.updated + * - customer.subscription.deleted + * - invoice.payment_failed + */ +export async function POST(request: NextRequest) { + const body = await request.text() + const signature = request.headers.get('stripe-signature') + + if (!signature) { + return NextResponse.json({ error: 'Missing stripe-signature header' }, { status: 400 }) + } + + let event: Stripe.Event + try { + event = stripe.webhooks.constructEvent(body, signature, WEBHOOK_SECRET) + } catch (err) { + console.error('Webhook signature verification failed:', err) + return NextResponse.json({ error: 'Invalid webhook signature' }, { status: 400 }) + } + + try { + switch (event.type) { + case 'checkout.session.completed': { + const session = event.data.object as Stripe.Checkout.Session + await handleCheckoutCompleted(session) + break + } + + case 'customer.subscription.updated': { + const subscription = event.data.object as Stripe.Subscription + await handleSubscriptionUpdated(subscription) + break + } + + case 'customer.subscription.deleted': { + const subscription = event.data.object as Stripe.Subscription + await handleSubscriptionDeleted(subscription) + break + } + + case 'invoice.payment_failed': { + const invoice = event.data.object as Stripe.Invoice + await handlePaymentFailed(invoice) + break + } + + default: + // Unhandled event type โ€” ignore + break + } + + return NextResponse.json({ received: true }) + } catch (error) { + console.error(`Webhook handler error for ${event.type}:`, error) + return NextResponse.json({ error: 'Webhook handler failed' }, { status: 500 }) + } +} + +async function handleCheckoutCompleted(session: Stripe.Checkout.Session) { + if (session.mode !== 'subscription') return + + const userId = session.metadata?.userId + if (!userId) { + console.error('No userId in checkout session metadata') + return + } + + const subscription = await stripe.subscriptions.retrieve(session.subscription as string) + // Stripe 2026 SDK renamed period fields โ€” cast to access them + const sub = subscription as unknown as Record + const periodStart = sub.current_period_start as number + const periodEnd = sub.current_period_end as number + + // Upsert subscription record + await prisma.$transaction([ + prisma.subscription.upsert({ + where: { userId }, + create: { + userId, + stripeCustomerId: session.customer as string, + stripeSubscriptionId: subscription.id, + stripePriceId: subscription.items.data[0].price.id, + plan: 'pro', + status: subscription.status, + currentPeriodStart: new Date(periodStart * 1000), + currentPeriodEnd: new Date(periodEnd * 1000), + cancelAtPeriodEnd: subscription.cancel_at_period_end, + }, + update: { + stripeSubscriptionId: subscription.id, + stripePriceId: subscription.items.data[0].price.id, + status: subscription.status, + currentPeriodStart: new Date(periodStart * 1000), + currentPeriodEnd: new Date(periodEnd * 1000), + cancelAtPeriodEnd: subscription.cancel_at_period_end, + }, + }), + // Update user plan + prisma.user.update({ + where: { id: userId }, + data: { + stripePlan: 'pro', + stripeCustomerId: session.customer as string, + stripeSubscriptionId: subscription.id, + stripeSubscriptionStatus: subscription.status, + }, + }), + ]) + + console.log(`โœ… Pro subscription activated for user ${userId}`) +} + +async function handleSubscriptionUpdated(subscription: Stripe.Subscription) { + const userId = subscription.metadata?.userId + if (!userId) return + + const isActive = subscription.status === 'active' || subscription.status === 'trialing' + const sub = subscription as unknown as Record + const periodStart = sub.current_period_start as number + const periodEnd = sub.current_period_end as number + + await prisma.$transaction([ + prisma.subscription.updateMany({ + where: { stripeSubscriptionId: subscription.id }, + data: { + status: subscription.status, + currentPeriodStart: new Date(periodStart * 1000), + currentPeriodEnd: new Date(periodEnd * 1000), + cancelAtPeriodEnd: subscription.cancel_at_period_end, + canceledAt: subscription.canceled_at ? new Date(subscription.canceled_at * 1000) : null, + }, + }), + prisma.user.update({ + where: { id: userId }, + data: { + stripePlan: isActive ? 'pro' : 'free', + stripeSubscriptionStatus: subscription.status, + }, + }), + ]) +} + +async function handleSubscriptionDeleted(subscription: Stripe.Subscription) { + const userId = subscription.metadata?.userId + if (!userId) return + + // Downgrade to free + await prisma.$transaction([ + prisma.subscription.updateMany({ + where: { stripeSubscriptionId: subscription.id }, + data: { status: 'canceled', canceledAt: new Date() }, + }), + prisma.user.update({ + where: { id: userId }, + data: { + stripePlan: 'free', + stripeSubscriptionId: null, + stripeSubscriptionStatus: 'canceled', + }, + }), + ]) + + console.log(`Subscription canceled for user ${userId} โ€” downgraded to free`) +} + +async function handlePaymentFailed(invoice: Stripe.Invoice) { + const customerId = invoice.customer as string + if (!customerId) return + + const user = await prisma.user.findUnique({ + where: { stripeCustomerId: customerId }, + select: { id: true }, + }) + + if (!user) return + + await prisma.user.update({ + where: { id: user.id }, + data: { stripeSubscriptionStatus: 'past_due' }, + }) + + console.warn(`Payment failed for customer ${customerId}`) +} diff --git a/src/app/api/tags/route.ts b/src/app/api/tags/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0221f13458ca60b7a618e58779cb26a31b1c9ae --- /dev/null +++ b/src/app/api/tags/route.ts @@ -0,0 +1,39 @@ +import { NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +export const dynamic = 'force-dynamic' + +// GET /api/tags โ€” get popular tags with counts +export async function GET() { + try { + // Get all prompts with tags and aggregate + const prompts = await prisma.prompt.findMany({ + where: { visibility: 'public' }, + select: { tags: true }, + }) + + // Count tag occurrences + const tagCounts = new Map() + for (const prompt of prompts) { + if (prompt.tags && Array.isArray(prompt.tags)) { + for (const tag of prompt.tags as string[]) { + const normalizedTag = tag.toLowerCase().trim() + if (normalizedTag) { + tagCounts.set(normalizedTag, (tagCounts.get(normalizedTag) || 0) + 1) + } + } + } + } + + // Sort by count descending + const tags = Array.from(tagCounts.entries()) + .map(([name, count]) => ({ name, count })) + .sort((a, b) => b.count - a.count) + .slice(0, 50) // Top 50 tags + + return NextResponse.json({ tags }) + } catch (error) { + console.error('Error fetching tags:', error) + return NextResponse.json({ error: 'Internal server error', tags: [] }, { status: 500 }) + } +} diff --git a/src/app/api/thunderdome/route.ts b/src/app/api/thunderdome/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..f842a8e0aa0e5209622636a49d16ee61d13e479d --- /dev/null +++ b/src/app/api/thunderdome/route.ts @@ -0,0 +1,174 @@ +import { NextRequest, NextResponse } from "next/server" +import prisma from "@/lib/prisma" + +// Thunderdome vote model and tracking + +// GET - Get model leaderboard from Thunderdome battles +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const period = searchParams.get("period") || "all" // all, week, month + + // Calculate date filter + let dateFilter: Date | undefined + if (period === "week") { + dateFilter = new Date() + dateFilter.setDate(dateFilter.getDate() - 7) + } else if (period === "month") { + dateFilter = new Date() + dateFilter.setMonth(dateFilter.getMonth() - 1) + } + + // Get all saved comparisons (thunderdome battles) + const whereClause: Record = { type: "thunderdome" } + if (dateFilter) { + whereClause.createdAt = { gte: dateFilter } + } + + const battles = await prisma.savedComparison.findMany({ + where: whereClause, + select: { + id: true, + results: true, + winner: true, + createdAt: true, + }, + }) + + // Aggregate wins and votes by model + const modelStats: Record = {} + + battles.forEach(battle => { + const results = battle.results as Array<{ + model: string + votes: number + }> + + results.forEach(result => { + if (!modelStats[result.model]) { + modelStats[result.model] = { wins: 0, battles: 0, totalVotes: 0 } + } + modelStats[result.model].battles += 1 + modelStats[result.model].totalVotes += result.votes || 0 + + if (battle.winner === result.model) { + modelStats[result.model].wins += 1 + } + }) + }) + + // Calculate win rates and sort + const leaderboard = Object.entries(modelStats) + .map(([model, stats]) => ({ + model, + wins: stats.wins, + battles: stats.battles, + totalVotes: stats.totalVotes, + winRate: stats.battles > 0 ? (stats.wins / stats.battles) * 100 : 0, + })) + .sort((a, b) => { + // Sort by win rate, then by total battles + if (b.winRate !== a.winRate) return b.winRate - a.winRate + return b.battles - a.battles + }) + + // Get recent battles for display + const recentBattles = await prisma.savedComparison.findMany({ + where: { type: "thunderdome" }, + orderBy: { createdAt: "desc" }, + take: 10, + select: { + id: true, + name: true, + prompt: true, + results: true, + winner: true, + createdAt: true, + }, + }) + + return NextResponse.json({ + leaderboard, + recentBattles, + totalBattles: battles.length, + period, + }) + } catch (error) { + console.error("Error fetching thunderdome stats:", error) + return NextResponse.json( + { error: "Failed to fetch thunderdome stats" }, + { status: 500 } + ) + } +} + +// POST - Record a community vote on a battle +export async function POST(request: NextRequest) { + try { + const { battleId, modelVote, userId } = await request.json() + + if (!battleId || !modelVote) { + return NextResponse.json( + { error: "battleId and modelVote are required" }, + { status: 400 } + ) + } + + // Get the battle + const battle = await prisma.savedComparison.findUnique({ + where: { id: battleId }, + }) + + if (!battle) { + return NextResponse.json( + { error: "Battle not found" }, + { status: 404 } + ) + } + + // Update the vote count for the model + const results = battle.results as Array<{ + model: string + output: string + votes: number + }> + + const updatedResults = results.map(result => { + if (result.model === modelVote) { + return { ...result, votes: (result.votes || 0) + 1 } + } + return result + }) + + // Determine new winner + const maxVotes = Math.max(...updatedResults.map(r => r.votes || 0)) + const newWinner = maxVotes > 0 + ? updatedResults.find(r => r.votes === maxVotes)?.model || battle.winner + : battle.winner + + // Update the battle + await prisma.savedComparison.update({ + where: { id: battleId }, + data: { + results: updatedResults, + winner: newWinner, + }, + }) + + return NextResponse.json({ + success: true, + updatedResults, + winner: newWinner, + }) + } catch (error) { + console.error("Error recording vote:", error) + return NextResponse.json( + { error: "Failed to record vote" }, + { status: 500 } + ) + } +} diff --git a/src/app/api/tools/[slug]/execute/route.ts b/src/app/api/tools/[slug]/execute/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..871c1cfd730b39999a04a8833d69bedda12a7b9e --- /dev/null +++ b/src/app/api/tools/[slug]/execute/route.ts @@ -0,0 +1,160 @@ +import { NextResponse } from 'next/server' +import { getToolBySlug } from '@/lib/tools/index' +import { isOllamaModel, AI_MODELS, ModelId } from '@/types/prompt' + +export const dynamic = 'force-dynamic' + +interface RouteContext { + params: Promise<{ slug: string }> +} + +export async function POST(req: Request, context: RouteContext) { + try { + const { slug } = await context.params + const { inputs, model, ollamaUrl = "http://localhost:11434" } = await req.json() + + // Get tool definition + const tool = getToolBySlug(slug) + if (!tool) { + return NextResponse.json( + { error: 'Tool not found' }, + { status: 404 } + ) + } + + // Validate inputs + for (const field of tool.inputSchema) { + if (field.required && (!inputs[field.name] || inputs[field.name].trim() === '')) { + return NextResponse.json( + { error: `${field.label} is required` }, + { status: 400 } + ) + } + } + + // Replace placeholders in system prompt + let finalPrompt = tool.systemPrompt + for (const [key, value] of Object.entries(inputs)) { + finalPrompt = finalPrompt.replace(new RegExp(`{{${key}}}`, 'g'), value as string) + } + + // Determine which model to use + const modelToUse = model || tool.model || 'gemini-2.5-flash' + let aiResponse: string + + // Check if Ollama model + if (isOllamaModel(modelToUse)) { + // Ollama local model + const ollamaRes = await fetch(`${ollamaUrl}/api/generate`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model: modelToUse, + prompt: finalPrompt, + stream: false, + }), + }) + + if (!ollamaRes.ok) { + throw new Error(`Ollama error: ${ollamaRes.status}. Make sure Ollama is running.`) + } + + const data = await ollamaRes.json() + aiResponse = data.response + } else if (modelToUse.startsWith('gpt')) { + // OpenAI + const openaiRes = await fetch('https://api.openai.com/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`, + }, + body: JSON.stringify({ + model: modelToUse, + messages: [{ role: 'user', content: finalPrompt }], + temperature: 0.7, + }), + }) + + if (!openaiRes.ok) { + throw new Error('OpenAI API error') + } + + const data = await openaiRes.json() + aiResponse = data.choices[0].message.content + } else if (modelToUse.startsWith('gemini')) { + // Google Gemini + const geminiRes = await fetch( + `https://generativelanguage.googleapis.com/v1beta/models/${modelToUse}:generateContent?key=${process.env.GOOGLE_GENERATIVE_AI_API_KEY}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + contents: [{ parts: [{ text: finalPrompt }] }], + }), + } + ) + + if (!geminiRes.ok) { + throw new Error('Gemini API error') + } + + const data = await geminiRes.json() + aiResponse = data.candidates?.[0]?.content?.parts?.[0]?.text || '' + } else if (modelToUse.startsWith('claude')) { + // Anthropic Claude + const claudeRes = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': process.env.ANTHROPIC_API_KEY || '', + 'anthropic-version': '2024-10-22', + }, + body: JSON.stringify({ + model: modelToUse, + max_tokens: 4096, + messages: [{ role: 'user', content: finalPrompt }], + }), + }) + + if (!claudeRes.ok) { + throw new Error('Claude API error') + } + + const data = await claudeRes.json() + aiResponse = data.content?.[0]?.text || '' + } else { + // Default fallback to Gemini + const geminiRes = await fetch( + `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${process.env.GOOGLE_GENERATIVE_AI_API_KEY}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + contents: [{ parts: [{ text: finalPrompt }] }], + }), + } + ) + + if (!geminiRes.ok) { + throw new Error('Gemini API error') + } + + const data = await geminiRes.json() + aiResponse = data.candidates?.[0]?.content?.parts?.[0]?.text || '' + } + + return NextResponse.json({ + output: aiResponse, + toolName: tool.name, + modelUsed: modelToUse, + }) + + } catch (error) { + console.error('Tool execution error:', error) + return NextResponse.json( + { error: error instanceof Error ? error.message : 'Failed to execute tool' }, + { status: 500 } + ) + } +} diff --git a/src/app/api/tools/[slug]/saved-runs/route.ts b/src/app/api/tools/[slug]/saved-runs/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..11a2b062f506d77727e9e1783882ba97e2a89af0 --- /dev/null +++ b/src/app/api/tools/[slug]/saved-runs/route.ts @@ -0,0 +1,66 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +interface RouteParams { + params: Promise<{ slug: string }> +} + +// GET /api/tools/[slug]/saved-runs - Get saved runs for a tool +export async function GET(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + const { searchParams } = new URL(request.url) + const userId = searchParams.get('userId') + + try { + const where: any = { toolSlug: slug } + + // Only show user's own runs for tools + if (userId) { + where.userId = userId + } + + const runs = await prisma.savedToolRun.findMany({ + where, + orderBy: { createdAt: 'desc' }, + take: 50, + }) + + return NextResponse.json({ runs }) + } catch (error) { + console.error('Error fetching tool runs:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// POST /api/tools/[slug]/saved-runs - Save a tool run +export async function POST(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + + try { + const body = await request.json() + const { userId, name, inputs, output, model } = body + + if (!output || !model) { + return NextResponse.json( + { error: 'output and model are required' }, + { status: 400 } + ) + } + + const run = await prisma.savedToolRun.create({ + data: { + toolSlug: slug, + userId: userId || null, + name: name || null, + inputs: inputs || null, + output, + model, + } + }) + + return NextResponse.json(run, { status: 201 }) + } catch (error) { + console.error('Error saving tool run:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/v1/prompts/[slug]/route.ts b/src/app/api/v1/prompts/[slug]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..12d48ec8965188c191af781cb8aea2667c8e2d7b --- /dev/null +++ b/src/app/api/v1/prompts/[slug]/route.ts @@ -0,0 +1,55 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +/** + * GET /api/v1/prompts/[slug] + * Retrieve a single public prompt by slug. + */ +export async function GET( + _request: NextRequest, + { params }: { params: Promise<{ slug: string }> }, +) { + try { + const { slug } = await params + + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { + id: true, + slug: true, + title: true, + description: true, + template: true, + schema: true, + category: true, + tags: true, + framework: true, + badges: true, + visibility: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + modelDefault: true, + modelAllowed: true, + maxTokens: true, + createdAt: true, + updatedAt: true, + creator: { + select: { username: true, name: true, image: true }, + }, + parent: { + select: { slug: true, title: true }, + }, + }, + }) + + if (!prompt || prompt.visibility !== 'public') { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + return NextResponse.json({ data: prompt }) + } catch (error) { + console.error('GET /api/v1/prompts/[slug] error:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/v1/prompts/[slug]/run/route.ts b/src/app/api/v1/prompts/[slug]/run/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..b99ea5bb542a83383ac28cd9936a66694b769417 --- /dev/null +++ b/src/app/api/v1/prompts/[slug]/run/route.ts @@ -0,0 +1,132 @@ +import { NextRequest, NextResponse } from 'next/server' +import { streamText } from 'ai' +import { openai } from '@ai-sdk/openai' +import { anthropic } from '@ai-sdk/anthropic' +import { google } from '@ai-sdk/google' +import prisma from '@/lib/prisma' +import { checkRateLimit, getClientIdentifier, getRateLimitHeaders } from '@/lib/rate-limit' +import { AI_MODELS, ModelId, DEFAULT_MODEL } from '@/types/prompt' +import { getCachedResponse } from '@/lib/cache' + +/** + * POST /api/v1/prompts/[slug]/run + * + * Execute a prompt via the public REST API. + * + * Body: + * variables - key/value object matching the prompt's schema + * model - optional model override (must be in prompt's modelAllowed) + * stream - true for streaming response (default: false for API) + * + * Rate limit: same as web (10/hr guest, 50/hr authenticated) + * + * Returns: + * { output: string, model: string, cached: boolean, tokens?: number } + * OR streaming text if stream=true + */ +export async function POST( + request: NextRequest, + { params }: { params: Promise<{ slug: string }> }, +) { + try { + const { slug } = await params + const body = await request.json() + const { variables = {}, model, stream = false } = body + + // Fetch the prompt + const prompt = await prisma.prompt.findUnique({ + where: { slug }, + select: { + id: true, + template: true, + schema: true, + modelDefault: true, + modelAllowed: true, + maxTokens: true, + visibility: true, + }, + }) + + if (!prompt || prompt.visibility !== 'public') { + return NextResponse.json({ error: 'Prompt not found' }, { status: 404 }) + } + + // Rate limit check + const identifier = getClientIdentifier(request) + const rateLimit = await checkRateLimit(identifier, false) + if (!rateLimit.success) { + const headers = getRateLimitHeaders(rateLimit) + return NextResponse.json( + { error: rateLimit.error }, + { status: 429, headers: Object.fromEntries(headers.entries()) }, + ) + } + + // Resolve model + const selectedModel = (model || prompt.modelDefault) as ModelId + if (prompt.modelAllowed?.length && !prompt.modelAllowed.includes(selectedModel)) { + return NextResponse.json( + { error: `Model "${selectedModel}" not allowed. Allowed: ${prompt.modelAllowed.join(', ')}` }, + { status: 400 }, + ) + } + + // Fill template variables + let filledPrompt = prompt.template + for (const [key, value] of Object.entries(variables)) { + filledPrompt = filledPrompt.replaceAll(`{{${key}}}`, String(value)) + } + + // Check cache + const cached = await getCachedResponse(prompt.id, variables, selectedModel) + if (cached) { + const headers = getRateLimitHeaders(rateLimit) + headers.set('X-Cache', 'HIT') + if (stream) { + return new Response(cached, { + headers: { 'Content-Type': 'text/plain', ...Object.fromEntries(headers.entries()) }, + }) + } + return NextResponse.json( + { output: cached, model: selectedModel, cached: true }, + { headers: Object.fromEntries(headers.entries()) }, + ) + } + + // Select AI provider + const modelConfig = AI_MODELS[selectedModel] + if (!modelConfig) { + return NextResponse.json({ error: 'Invalid model' }, { status: 400 }) + } + + let aiModel + switch (modelConfig.provider) { + case 'openai': aiModel = openai(selectedModel); break + case 'anthropic': aiModel = anthropic(selectedModel); break + case 'google': aiModel = google(selectedModel); break + default: aiModel = google(DEFAULT_MODEL) + } + + const rateLimitHeaders = Object.fromEntries(getRateLimitHeaders(rateLimit).entries()) + + if (stream) { + // Streaming response + const result = await streamText({ model: aiModel, prompt: filledPrompt }) + return result.toTextStreamResponse({ + headers: { ...rateLimitHeaders, 'X-Cache': 'MISS' }, + }) + } + + // Non-streaming response (default for API) + const result = await streamText({ model: aiModel, prompt: filledPrompt }) + const text = await result.text + + return NextResponse.json( + { output: text, model: selectedModel, cached: false }, + { headers: rateLimitHeaders }, + ) + } catch (error) { + console.error('POST /api/v1/prompts/[slug]/run error:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/v1/prompts/route.ts b/src/app/api/v1/prompts/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..51114174d678eaeec6ec0cb53c6b9456d0b4df30 --- /dev/null +++ b/src/app/api/v1/prompts/route.ts @@ -0,0 +1,96 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +/** + * GET /api/v1/prompts + * + * List public prompts with pagination, search, and filtering. + * No authentication required. + * + * Query params: + * q - search term + * category - filter by category + * tags - comma-separated tags + * sort - runs|stars|newest (default: newest) + * page - page number (default: 1) + * limit - results per page (default: 20, max: 100) + */ +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const q = searchParams.get('q') || '' + const category = searchParams.get('category') || '' + const tags = searchParams.get('tags')?.split(',').filter(Boolean) || [] + const sort = searchParams.get('sort') || 'newest' + const page = Math.max(1, parseInt(searchParams.get('page') || '1')) + const limit = Math.min(100, Math.max(1, parseInt(searchParams.get('limit') || '20'))) + const skip = (page - 1) * limit + + // Build WHERE clause + const where: Record = { visibility: 'public' } + if (q) { + where.OR = [ + { title: { contains: q, mode: 'insensitive' } }, + { description: { contains: q, mode: 'insensitive' } }, + { tags: { hasSome: [q] } }, + ] + } + if (category) where.category = { equals: category, mode: 'insensitive' } + if (tags.length > 0) where.tags = { hasSome: tags } + + // Build ORDER BY + const orderBy = + sort === 'runs' ? { totalRuns: 'desc' as const } : + sort === 'stars' ? { starsCount: 'desc' as const } : + { createdAt: 'desc' as const } + + const [prompts, total] = await Promise.all([ + prisma.prompt.findMany({ + where, + orderBy, + skip, + take: limit, + select: { + id: true, + slug: true, + title: true, + description: true, + category: true, + tags: true, + framework: true, + badges: true, + totalRuns: true, + starsCount: true, + remixesCount: true, + modelDefault: true, + modelAllowed: true, + createdAt: true, + updatedAt: true, + creator: { + select: { username: true, name: true, image: true }, + }, + }, + }), + prisma.prompt.count({ where }), + ]) + + return NextResponse.json({ + data: prompts, + pagination: { + page, + limit, + total, + totalPages: Math.ceil(total / limit), + hasNext: page < Math.ceil(total / limit), + hasPrev: page > 1, + }, + }, { + headers: { + 'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=300', + }, + }) + } catch (error) { + console.error('GET /api/v1/prompts error:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/v1/route.ts b/src/app/api/v1/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..d97b7fe3fa4db535bbdbac9e5b9623d56d4619c5 --- /dev/null +++ b/src/app/api/v1/route.ts @@ -0,0 +1,54 @@ +import { NextResponse } from 'next/server' + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +/** + * GET /api/v1 + * API overview โ€” returns available endpoints, rate limits, and usage info. + */ +export async function GET() { + return NextResponse.json({ + name: 'OpenPrompt Public API', + version: '1.0.0', + baseUrl: `${BASE_URL}/api/v1`, + documentation: `${BASE_URL}/docs/api`, + rateLimits: { + guest: '10 requests / hour per IP', + authenticated: '50 requests / hour per user', + pro: '500 requests / hour per user', + }, + endpoints: [ + { + method: 'GET', + path: '/api/v1/prompts', + description: 'List public prompts', + params: ['q', 'category', 'tags', 'sort', 'page', 'limit'], + }, + { + method: 'GET', + path: '/api/v1/prompts/:slug', + description: 'Get a single prompt by slug', + }, + { + method: 'POST', + path: '/api/v1/prompts/:slug/run', + description: 'Execute a prompt with variables', + body: { variables: 'object', model: 'string (optional)', stream: 'boolean (optional)' }, + }, + { + method: 'GET', + path: '/api/v1/tools', + description: 'List all AI tools', + params: ['category', 'q', 'limit'], + }, + ], + authentication: { + note: 'Authentication not required for public endpoints. Rate limits apply per IP.', + future: 'API key authentication coming soon โ€” sign up at ' + BASE_URL, + }, + }, { + headers: { + 'Cache-Control': 'public, s-maxage=3600', + }, + }) +} diff --git a/src/app/api/v1/tools/route.ts b/src/app/api/v1/tools/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7ace142d4c5d79459bfb5cd2670f64bdb7b0e24 --- /dev/null +++ b/src/app/api/v1/tools/route.ts @@ -0,0 +1,58 @@ +import { NextRequest, NextResponse } from 'next/server' +import { getAllToolsComplete } from '@/lib/tools/index' + +/** + * GET /api/v1/tools + * List all available AI tools with their metadata. + * No authentication required. + * + * Query params: + * category - filter by category + * q - search term + * limit - max results (default: 50, max: 200) + */ +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url) + const category = searchParams.get('category') || '' + const q = searchParams.get('q')?.toLowerCase() || '' + const limit = Math.min(200, Math.max(1, parseInt(searchParams.get('limit') || '50'))) + + let tools = getAllToolsComplete() + + if (category) { + tools = tools.filter((t) => t.category.toLowerCase() === category.toLowerCase()) + } + + if (q) { + tools = tools.filter( + (t) => + t.name.toLowerCase().includes(q) || + t.description.toLowerCase().includes(q) || + t.category.toLowerCase().includes(q), + ) + } + + const limited = tools.slice(0, limit) + + return NextResponse.json({ + data: limited.map((t) => ({ + slug: t.slug, + name: t.name, + description: t.description, + category: t.category, + icon: t.icon, + isPremium: t.isPremium ?? false, + })), + total: limited.length, + totalAll: tools.length, + }, { + headers: { + 'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400', + }, + }) + } catch (error) { + console.error('GET /api/v1/tools error:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/votes/route.ts b/src/app/api/votes/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c8ead92a2027a93105bc69cf19b50c89be80fd2 --- /dev/null +++ b/src/app/api/votes/route.ts @@ -0,0 +1,155 @@ +import { NextRequest, NextResponse } from "next/server"; +import { prisma } from "@/lib/prisma"; +import { getAuthUser } from "@/lib/auth"; +import { voteSchema, parseBody } from "@/lib/validations"; +import { checkRateLimit, getClientIdentifier, getRateLimitHeaders } from "@/lib/rate-limit"; + +// POST /api/votes โ€” requires authentication +export async function POST(request: NextRequest) { + try { + // Auth check โ€” no more trusting client-supplied userId + const authUser = await getAuthUser(); + if (!authUser) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ); + } + + // Rate limit + const identifier = getClientIdentifier(request, authUser.id); + const rateLimit = await checkRateLimit(`votes:${identifier}`, true); + if (!rateLimit.success) { + return NextResponse.json( + { error: rateLimit.error }, + { status: 429, headers: Object.fromEntries(getRateLimitHeaders(rateLimit).entries()) } + ); + } + + const body = await request.json(); + const parsed = parseBody(voteSchema, body); + if (!parsed.success) return parsed.response; + + const { targetType, targetId, value } = parsed.data; + const userId = authUser.id; + + // Clamp value to -1 or 1 (prevents inflation attacks) + const safeValue = value >= 0 ? 1 : -1; + + // Handle different target types + if (targetType === "imagePrompt") { + const existingVote = await prisma.imagePromptVote.findUnique({ + where: { + imagePromptId_userId: { imagePromptId: targetId, userId }, + }, + }); + + if (existingVote) { + // Toggle vote off โ€” use transaction for consistency + await prisma.$transaction([ + prisma.imagePromptVote.delete({ where: { id: existingVote.id } }), + prisma.imagePrompt.update({ + where: { id: targetId }, + data: { votesCount: { decrement: existingVote.value } }, + }), + ]); + return NextResponse.json({ voted: false, change: -existingVote.value }); + } else { + await prisma.$transaction([ + prisma.imagePromptVote.create({ + data: { imagePromptId: targetId, userId, value: safeValue }, + }), + prisma.imagePrompt.update({ + where: { id: targetId }, + data: { votesCount: { increment: safeValue } }, + }), + ]); + return NextResponse.json({ voted: true, change: safeValue }); + } + } + + if (targetType === "character") { + const existingVote = await prisma.characterVote.findUnique({ + where: { + characterId_userId: { characterId: targetId, userId }, + }, + }); + + if (existingVote) { + await prisma.$transaction([ + prisma.characterVote.delete({ where: { id: existingVote.id } }), + prisma.character.update({ + where: { id: targetId }, + data: { votesCount: { decrement: existingVote.value } }, + }), + ]); + return NextResponse.json({ voted: false, change: -existingVote.value }); + } else { + await prisma.$transaction([ + prisma.characterVote.create({ + data: { characterId: targetId, userId, value: safeValue }, + }), + prisma.character.update({ + where: { id: targetId }, + data: { votesCount: { increment: safeValue } }, + }), + ]); + return NextResponse.json({ voted: true, change: safeValue }); + } + } + + return NextResponse.json({ error: "Invalid targetType" }, { status: 400 }); + } catch (error) { + console.error("Error processing vote:", error); + return NextResponse.json( + { error: "Failed to process vote" }, + { status: 500 } + ); + } +} + +// GET /api/votes - Check if current user voted (uses auth, not query param) +export async function GET(request: NextRequest) { + try { + const authUser = await getAuthUser(); + if (!authUser) { + return NextResponse.json({ hasVoted: false }); + } + + const { searchParams } = new URL(request.url); + const targetType = searchParams.get("targetType"); + const targetId = searchParams.get("targetId"); + + if (!targetType || !targetId) { + return NextResponse.json( + { error: "targetType and targetId are required" }, + { status: 400 } + ); + } + + const userId = authUser.id; + let hasVoted = false; + + if (targetType === "imagePrompt") { + const vote = await prisma.imagePromptVote.findUnique({ + where: { imagePromptId_userId: { imagePromptId: targetId, userId } }, + }); + hasVoted = !!vote; + } + + if (targetType === "character") { + const vote = await prisma.characterVote.findUnique({ + where: { characterId_userId: { characterId: targetId, userId } }, + }); + hasVoted = !!vote; + } + + return NextResponse.json({ hasVoted }); + } catch (error) { + console.error("Error checking vote:", error); + return NextResponse.json( + { error: "Failed to check vote" }, + { status: 500 } + ); + } +} diff --git a/src/app/api/workflows/[slug]/route.ts b/src/app/api/workflows/[slug]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..4237f8d84c0bca6da0bfdddc2f37070ace166164 --- /dev/null +++ b/src/app/api/workflows/[slug]/route.ts @@ -0,0 +1,87 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +interface RouteParams { + params: Promise<{ slug: string }> +} + +// GET /api/workflows/[slug] - Get single workflow +export async function GET(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + + try { + const workflow = await prisma.workflow.findUnique({ + where: { slug } + }) + + if (!workflow) { + return NextResponse.json({ error: 'Workflow not found' }, { status: 404 }) + } + + return NextResponse.json(workflow) + } catch (error) { + console.error('Error fetching workflow:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// PUT /api/workflows/[slug] - Update workflow +export async function PUT(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + + try { + const body = await request.json() + const { name, description, steps, variables, visibility } = body + + const workflow = await prisma.workflow.update({ + where: { slug }, + data: { + name, + description, + steps, + variables, + visibility, + } + }) + + return NextResponse.json(workflow) + } catch (error) { + console.error('Error updating workflow:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// DELETE /api/workflows/[slug] - Delete workflow +export async function DELETE(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + + try { + await prisma.workflow.delete({ + where: { slug } + }) + + return NextResponse.json({ success: true }) + } catch (error) { + console.error('Error deleting workflow:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// POST /api/workflows/[slug]/run - Increment run count +export async function POST(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + + try { + const workflow = await prisma.workflow.update({ + where: { slug }, + data: { + totalRuns: { increment: 1 } + } + }) + + return NextResponse.json({ runs: workflow.totalRuns }) + } catch (error) { + console.error('Error incrementing runs:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/workflows/[slug]/runs/route.ts b/src/app/api/workflows/[slug]/runs/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ce7231b3d1b01fc8f9eb0195a8d975ba779ab33 --- /dev/null +++ b/src/app/api/workflows/[slug]/runs/route.ts @@ -0,0 +1,91 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' + +interface RouteParams { + params: Promise<{ slug: string }> +} + +// GET /api/workflows/[slug]/runs - Get saved runs for a workflow +export async function GET(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + const { searchParams } = new URL(request.url) + const userId = searchParams.get('userId') + + try { + // First get the workflow to check visibility + const workflow = await prisma.workflow.findUnique({ + where: { slug }, + select: { id: true, visibility: true, creatorId: true } + }) + + if (!workflow) { + return NextResponse.json({ error: 'Workflow not found' }, { status: 404 }) + } + + // Build where clause based on visibility + const where: any = { workflowId: workflow.id } + + // If workflow is private, only show runs to the creator + if (workflow.visibility === 'private') { + if (!userId || userId !== workflow.creatorId) { + return NextResponse.json({ runs: [] }) + } + where.userId = userId + } + + const runs = await prisma.workflowRun.findMany({ + where, + orderBy: { createdAt: 'desc' }, + take: 50, + }) + + return NextResponse.json({ runs }) + } catch (error) { + console.error('Error fetching workflow runs:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// POST /api/workflows/[slug]/runs - Save a workflow run +export async function POST(request: NextRequest, { params }: RouteParams) { + const { slug } = await params + + try { + const body = await request.json() + const { userId, name, variables, outputs, model } = body + + if (!outputs || !model) { + return NextResponse.json( + { error: 'outputs and model are required' }, + { status: 400 } + ) + } + + // Get the workflow + const workflow = await prisma.workflow.findUnique({ + where: { slug }, + select: { id: true } + }) + + if (!workflow) { + return NextResponse.json({ error: 'Workflow not found' }, { status: 404 }) + } + + // Create the run record + const run = await prisma.workflowRun.create({ + data: { + workflowId: workflow.id, + userId: userId || null, + name: name || null, + variables: variables || null, + outputs, + model, + } + }) + + return NextResponse.json(run, { status: 201 }) + } catch (error) { + console.error('Error saving workflow run:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/api/workflows/route.ts b/src/app/api/workflows/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..ce69fc4c7905c203f66b3d98590c5b6dab0b0a3d --- /dev/null +++ b/src/app/api/workflows/route.ts @@ -0,0 +1,86 @@ +import { NextRequest, NextResponse } from 'next/server' +import prisma from '@/lib/prisma' +import { nanoid } from 'nanoid' +import { getAuthUser } from '@/lib/auth' + +// GET /api/workflows - List workflows (public access for public workflows) +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url) + const visibility = searchParams.get('visibility') || 'public' + const limit = Math.min(parseInt(searchParams.get('limit') || '20'), 100) + const offset = Math.max(parseInt(searchParams.get('offset') || '0'), 0) + + try { + const authUser = await getAuthUser() + const where: Record = {} + + // If authenticated, allow viewing own workflows (public + private) + const creatorId = searchParams.get('creatorId') + if (creatorId && authUser && creatorId === authUser.id) { + where.creatorId = authUser.id + } else if (visibility === 'public') { + where.visibility = 'public' + } else { + where.visibility = 'public' + } + + const workflows = await prisma.workflow.findMany({ + where, + orderBy: { createdAt: 'desc' }, + take: limit, + skip: offset, + }) + + const total = await prisma.workflow.count({ where }) + + return NextResponse.json({ + workflows, + total, + hasMore: offset + workflows.length < total + }) + } catch (error) { + console.error('Error fetching workflows:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} + +// POST /api/workflows - Create workflow โ€” requires authentication +export async function POST(request: NextRequest) { + try { + const authUser = await getAuthUser() + if (!authUser) { + return NextResponse.json( + { error: 'Authentication required' }, + { status: 401 } + ) + } + + const body = await request.json() + const { name, description, steps, variables, visibility } = body + + if (!name || !steps) { + return NextResponse.json({ error: 'Name and steps are required' }, { status: 400 }) + } + + // Generate unique slug + const baseSlug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 50) + const slug = `${baseSlug}-${nanoid(6)}` + + const workflow = await prisma.workflow.create({ + data: { + slug, + name, + description: description || null, + steps, + variables: variables || null, + visibility: visibility || 'private', + creatorId: authUser.id, + } + }) + + return NextResponse.json(workflow, { status: 201 }) + } catch (error) { + console.error('Error creating workflow:', error) + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) + } +} diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..622e9d96bccbdf941e609fae3bf5340645b017e1 --- /dev/null +++ b/src/app/blog/page.tsx @@ -0,0 +1,155 @@ +import { Metadata } from "next" +import { Newspaper, Calendar, ArrowRight, User } from "lucide-react" +import Link from "next/link" +import { getCurrentMonthYear } from "@/lib/date-utils" +import { generateSEO } from "@/lib/seo" + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const metadata: Metadata = generateSEO({ + title: "Blog | OpenPrompt", + description: "Latest news, tutorials, and insights about AI prompts, prompt engineering, and the OpenPrompt platform.", + url: `${BASE_URL}/blog`, + type: "website", + keywords: ["AI blog", "prompt engineering blog", "AI news", "prompt tips"], +}) as Metadata + +const currentDate = getCurrentMonthYear() + +const posts = [ + { + title: "Introducing OpenPrompt: The GitHub for AI Prompts", + excerpt: "Today we're launching OpenPrompt, a platform to create, share, and run AI prompts as micro-apps. Here's our vision for the future of prompt engineering.", + author: "OpenPrompt Team", + date: currentDate, + category: "Announcement", + href: "#", + featured: true, + }, + { + title: "The Future of Prompt Engineering", + excerpt: "As AI models become more capable, the art of prompting becomes more important. Learn about emerging trends and best practices.", + author: "OpenPrompt Team", + date: currentDate, + category: "Insights", + href: "#", + }, + { + title: "177+ AI Tools in One Platform", + excerpt: "Explore our comprehensive suite of AI-powered tools for marketing, business, content creation, and more.", + author: "OpenPrompt Team", + date: currentDate, + category: "Product", + href: "#", + }, + { + title: "Understanding Prompt Frameworks", + excerpt: "A deep dive into the 10 prompt frameworks available on OpenPrompt and when to use each one.", + author: "OpenPrompt Team", + date: currentDate, + category: "Tutorial", + href: "#", + }, +] + +export default function BlogPage() { + return ( +
+
+ {/* Header */} +
+
+ + Blog +
+

+ Latest Updates +

+

+ News, insights, and tutorials from the OpenPrompt team. +

+
+ + {/* Featured Post */} + {posts.filter(p => p.featured).map((post) => ( + + + {post.category} + +

+ {post.title} +

+

+ {post.excerpt} +

+
+ + + {post.author} + + + + {post.date} + +
+ + ))} + + {/* Posts Grid */} +
+ {posts.filter(p => !p.featured).map((post) => ( + + + {post.category} + +

+ {post.title} +

+

+ {post.excerpt} +

+
+ + {post.date} +
+ + ))} +
+ + {/* Newsletter CTA */} +
+

Stay Updated

+

+ Follow us on social media for the latest updates. +

+ +
+
+
+ ) +} diff --git a/src/app/careers/page.tsx b/src/app/careers/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..42c9ff03b83ae163efb2d539cd4addcf0955d725 --- /dev/null +++ b/src/app/careers/page.tsx @@ -0,0 +1,151 @@ +import { Metadata } from "next" +import { Briefcase, MapPin, Clock, ArrowRight, Heart, Zap, Users } from "lucide-react" +import Link from "next/link" +import { generateSEO } from "@/lib/seo" + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const metadata: Metadata = generateSEO({ + title: "Careers | OpenPrompt", + description: "Join the OpenPrompt team and help build the future of AI prompts. Remote-first, cutting-edge AI, and impact millions.", + url: `${BASE_URL}/careers`, + keywords: ["OpenPrompt careers", "AI jobs", "remote AI jobs"], +}) as Metadata + +const perks = [ + { + icon: Zap, + title: "Work on Cutting-Edge AI", + description: "Build products at the intersection of AI and developer tools.", + }, + { + icon: Users, + title: "Remote-First Culture", + description: "Work from anywhere in the world with flexible hours.", + }, + { + icon: Heart, + title: "Impact Millions", + description: "Your work will help millions of people use AI more effectively.", + }, +] + +const openings = [ + { + title: "Senior Full-Stack Engineer", + department: "Engineering", + location: "Remote", + type: "Full-time", + href: "#", + }, + { + title: "AI/ML Engineer", + department: "Engineering", + location: "Remote", + type: "Full-time", + href: "#", + }, + { + title: "Product Designer", + department: "Design", + location: "Remote", + type: "Full-time", + href: "#", + }, + { + title: "Developer Advocate", + department: "Marketing", + location: "Remote", + type: "Full-time", + href: "#", + }, +] + +export default function CareersPage() { + return ( +
+
+ {/* Header */} +
+
+ + Careers +
+

+ Join Our Team +

+

+ Help us build the future of AI prompts. We're looking for + passionate people to join our mission. +

+
+ + {/* Perks */} +
+ {perks.map((perk) => ( +
+ +

{perk.title}

+

+ {perk.description} +

+
+ ))} +
+ + {/* Open Positions */} +
+

Open Positions

+ +
+ {openings.map((job) => ( + +
+

+ {job.title} +

+
+ {job.department} + + + {job.location} + + + + {job.type} + +
+
+ + + ))} +
+
+ + {/* No Match CTA */} +
+

+ Don't See a Match? +

+

+ We're always looking for talented people. Send us your resume + and we'll keep you in mind for future opportunities. +

+ + Get in Touch + +
+
+
+ ) +} diff --git a/src/app/categories/page.tsx b/src/app/categories/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..58b221986295b1c7122024ac7fe246ab9fb78de2 --- /dev/null +++ b/src/app/categories/page.tsx @@ -0,0 +1,251 @@ +import { Metadata } from 'next' +import Link from 'next/link' +import prisma from '@/lib/prisma' +import { Card, CardContent } from '@/components/ui/card' +import { Badge } from '@/components/ui/badge' +import { generateSEO } from '@/lib/seo' +import { + FileText, + Code, + Megaphone, + Briefcase, + GraduationCap, + Palette, + Search, + MessageSquare, + Sparkles, + BookOpen, + TrendingUp, + Play, + Star, + ArrowRight, + Layers +} from 'lucide-react' +import { getCategories } from '@/lib/search' + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const dynamic = 'force-dynamic' + +export const metadata: Metadata = generateSEO({ + title: 'Browse Prompt Categories | OpenPrompt', + description: 'Explore all prompt categories โ€” Content, Development, Marketing, Business, Education, Creative, and Research. Find the best AI prompts by category.', + url: `${BASE_URL}/categories`, + keywords: ['prompt categories', 'AI prompt types', 'content prompts', 'coding prompts', 'marketing prompts'], +}) as Metadata + +// Category icons and colors +const CATEGORY_CONFIG: Record + color: string + gradient: string + description: string +}> = { + Content: { + icon: FileText, + color: "text-blue-400", + gradient: "from-blue-600/20 to-blue-900/20", + description: "Blog posts, articles, social media captions, and copy" + }, + Development: { + icon: Code, + color: "text-green-400", + gradient: "from-green-600/20 to-green-900/20", + description: "Code generation, debugging, documentation, and architecture" + }, + Marketing: { + icon: Megaphone, + color: "text-orange-400", + gradient: "from-orange-600/20 to-orange-900/20", + description: "Ads, campaigns, brand messaging, and growth strategies" + }, + Business: { + icon: Briefcase, + color: "text-purple-400", + gradient: "from-purple-600/20 to-purple-900/20", + description: "Reports, analysis, planning, and professional communication" + }, + Education: { + icon: GraduationCap, + color: "text-yellow-400", + gradient: "from-yellow-600/20 to-yellow-900/20", + description: "Learning materials, explanations, and study guides" + }, + Creative: { + icon: Palette, + color: "text-pink-400", + gradient: "from-pink-600/20 to-pink-900/20", + description: "Stories, scripts, poetry, and creative writing" + }, + Research: { + icon: Search, + color: "text-cyan-400", + gradient: "from-cyan-600/20 to-cyan-900/20", + description: "Analysis, summaries, literature reviews, and insights" + }, + Chat: { + icon: MessageSquare, + color: "text-violet-400", + gradient: "from-violet-600/20 to-violet-900/20", + description: "Conversational prompts, roleplay, and dialogues" + }, + Other: { + icon: Sparkles, + color: "text-gray-400", + gradient: "from-gray-600/20 to-gray-900/20", + description: "Miscellaneous and uncategorized prompts" + }, +} + +function formatNumber(num: number): string { + if (num >= 1000000) return (num / 1000000).toFixed(1) + "M" + if (num >= 1000) return (num / 1000).toFixed(1) + "K" + return num.toString() +} + +export default async function CategoriesPage() { + const categories = getCategories() + + // Get stats for each category + const categoryStats = await Promise.all( + categories.map(async (category) => { + const stats = await prisma.prompt.aggregate({ + where: { + category, + visibility: 'public', + }, + _count: { id: true }, + _sum: { + totalRuns: true, + starsCount: true, + }, + }) + + return { + name: category, + count: stats._count.id, + runs: stats._sum.totalRuns || 0, + stars: stats._sum.starsCount || 0, + } + }) + ) + + // Sort by prompt count + categoryStats.sort((a, b) => b.count - a.count) + + // Calculate totals + const totalPrompts = categoryStats.reduce((sum, c) => sum + c.count, 0) + const totalRuns = categoryStats.reduce((sum, c) => sum + c.runs, 0) + const totalStars = categoryStats.reduce((sum, c) => sum + c.stars, 0) + + return ( +
+ {/* Header */} +
+
+
+ +
+

+ Browse Categories +

+

+ Discover prompts organized by purpose. From content creation to code development, find the perfect prompt for your needs. +

+ + {/* Stats Summary */} +
+
+
+ + {formatNumber(totalPrompts)} +
+

Total Prompts

+
+
+
+ + {formatNumber(totalRuns)} +
+

Total Runs

+
+
+
+ + {formatNumber(totalStars)} +
+

Total Stars

+
+
+
+
+ + {/* Categories Grid */} +
+
+
+ {categoryStats.map((cat, index) => { + const config = CATEGORY_CONFIG[cat.name] || CATEGORY_CONFIG.Other + const Icon = config.icon + + return ( + + + + {/* Icon and Badge Row */} +
+
+ +
+ + {cat.count} prompts + +
+ + {/* Title */} +

+ {cat.name} +

+ + {/* Description */} +

+ {config.description} +

+ + {/* Stats Row */} +
+
+ + + {formatNumber(cat.runs)} + + + + {formatNumber(cat.stars)} + +
+ +
+
+
+ + ) + })} +
+ + {/* Trending Section */} + {categoryStats.length > 0 && categoryStats[0].count > 0 && ( +
+
+ + + {categoryStats[0].name} is the most popular category with {categoryStats[0].count} prompts + +
+
+ )} +
+
+
+ ) +} diff --git a/src/app/category/[name]/page.tsx b/src/app/category/[name]/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..78bb16a4a9952344749ca10ef231a1d715e27a3e --- /dev/null +++ b/src/app/category/[name]/page.tsx @@ -0,0 +1,101 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' +import prisma from '@/lib/prisma' +import { ExploreClient } from '@/components/explore/explore-client' +import { Badge } from '@/components/ui/badge' +import { getCategories } from '@/lib/search' +import { generateSEO, generateBreadcrumbSchema } from '@/lib/seo' + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const dynamic = 'force-dynamic' + +interface CategoryPageProps { + params: Promise<{ name: string }> +} + +export async function generateMetadata({ params }: CategoryPageProps): Promise { + const { name } = await params + const category = decodeURIComponent(name) + + return generateSEO({ + title: `${category} AI Prompts`, + description: `Discover the best ${category.toLowerCase()} AI prompts created by the community. Run, remix, and share ${category.toLowerCase()} prompts on OpenPrompt.`, + url: `${BASE_URL}/category/${encodeURIComponent(category)}`, + keywords: [`${category.toLowerCase()} prompts`, `${category.toLowerCase()} AI`, `best ${category.toLowerCase()} prompts`, 'AI prompt templates'], + }) as Metadata +} + +export default async function CategoryPage({ params }: CategoryPageProps) { + const { name } = await params + const category = decodeURIComponent(name) + + // Validate category + const validCategories = getCategories() + if (!validCategories.includes(category)) { + notFound() + } + + // Fetch prompts for this category + const prompts = await prisma.prompt.findMany({ + where: { + category, + visibility: 'public', + }, + include: { + creator: { + select: { + name: true, + username: true, + image: true, + }, + }, + }, + orderBy: [ + { totalRuns: 'desc' }, + { starsCount: 'desc' }, + ], + take: 12, + }) + + // Get category stats + const stats = await prisma.prompt.aggregate({ + where: { + category, + visibility: 'public', + }, + _count: { id: true }, + _sum: { + totalRuns: true, + starsCount: true, + }, + }) + + return ( +
+ {/* Category Header */} +
+ Category +

+ {category} Prompts +

+

+ Explore {stats._count.id} prompts in the {category} category +

+ + {/* Category Stats */} +
+ + {stats._sum.totalRuns?.toLocaleString() || 0} total runs + + + {stats._sum.starsCount?.toLocaleString() || 0} total stars + +
+
+ + {/* Prompts using ExploreClient */} + +
+ ) +} diff --git a/src/app/characters/[slug]/loading.tsx b/src/app/characters/[slug]/loading.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2d535016100c0889ff0b43fe4d63afa77f6a87cf --- /dev/null +++ b/src/app/characters/[slug]/loading.tsx @@ -0,0 +1,12 @@ +import { Loader2 } from "lucide-react"; + +export default function Loading() { + return ( +
+
+ +

Loading character...

+
+
+ ); +} diff --git a/src/app/characters/[slug]/page.tsx b/src/app/characters/[slug]/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ad34701e21f699e2882ff6e242b109b09ddbed62 --- /dev/null +++ b/src/app/characters/[slug]/page.tsx @@ -0,0 +1,429 @@ +"use client"; + +import { useState, useEffect, useRef } from "react"; +import { useParams } from "next/navigation"; +import { motion, AnimatePresence } from "framer-motion"; +import { + Bot, + Send, + Loader2, + ArrowLeft, + Heart, + Bookmark, + Share2, + RotateCcw, + Settings, + Trash2 +} from "lucide-react"; +import Link from "next/link"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Badge } from "@/components/ui/badge"; +import { Card, CardContent } from "@/components/ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; + +interface Character { + id: string; + slug: string; + name: string; + description: string; + personality: string; + background?: string; + systemPrompt: string; + avatar?: string; + style?: string; + category: string; + tags: string[]; + responseStyle?: string; + temperature: number; + totalChats: number; + votesCount: number; + savesCount: number; + creator?: { + id: string; + name: string; + username: string; + }; +} + +interface Message { + id: string; + role: "user" | "assistant"; + content: string; + timestamp: Date; +} + +export default function CharacterChatPage() { + const params = useParams(); + const slug = params.slug as string; + + const [character, setCharacter] = useState(null); + const [loading, setLoading] = useState(true); + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(""); + const [sending, setSending] = useState(false); + const [liked, setLiked] = useState(false); + const [saved, setSaved] = useState(false); + + const messagesEndRef = useRef(null); + const inputRef = useRef(null); + + // Fetch character data + useEffect(() => { + const fetchCharacter = async () => { + try { + const res = await fetch(`/api/characters?search=${slug}&limit=1`); + if (res.ok) { + const data = await res.json(); + if (data.characters && data.characters.length > 0) { + setCharacter(data.characters[0]); + } else { + setCharacter(null); + } + } else { + setCharacter(null); + } + } catch (error) { + console.error("Error fetching character:", error); + setCharacter(null); + } finally { + setLoading(false); + } + }; + + // Load memory from localStorage + const savedMessages = localStorage.getItem(`character-chat-${slug}`); + if (savedMessages) { + try { + setMessages(JSON.parse(savedMessages)); + } catch { + // Ignore parse errors + } + } + + fetchCharacter(); + }, [slug]); + + // Save messages to localStorage + useEffect(() => { + if (messages.length > 0) { + localStorage.setItem(`character-chat-${slug}`, JSON.stringify(messages)); + } + }, [messages, slug]); + + // Scroll to bottom when new messages arrive + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + + const sendMessage = async () => { + if (!input.trim() || sending || !character) return; + + const userMessage: Message = { + id: Date.now().toString(), + role: "user", + content: input.trim(), + timestamp: new Date(), + }; + + setMessages(prev => [...prev, userMessage]); + setInput(""); + setSending(true); + + try { + // Build conversation context + const conversationHistory = messages.slice(-10).map(m => ({ + role: m.role, + content: m.content, + })); + + const res = await fetch("/api/run", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + prompt: `${character.systemPrompt}\n\nPersonality: ${character.personality}\n\nUser: ${userMessage.content}`, + model: "gpt-4o-mini", + }), + }); + + if (res.ok) { + // The API returns a streaming text response, not JSON + const text = await res.text(); + const assistantMessage: Message = { + id: (Date.now() + 1).toString(), + role: "assistant", + content: text || "I'm here to help! How can I assist you?", + timestamp: new Date(), + }; + setMessages(prev => [...prev, assistantMessage]); + + // Update memory API + try { + await fetch("/api/characters/memory", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + characterId: character.id, + newMessage: userMessage.content, + characterResponse: assistantMessage.content, + }), + }); + } catch { + // Memory update is optional + } + } else { + // Fallback response + const assistantMessage: Message = { + id: (Date.now() + 1).toString(), + role: "assistant", + content: `Hello! I'm ${character.name}. ${character.description} How can I help you today?`, + timestamp: new Date(), + }; + setMessages(prev => [...prev, assistantMessage]); + } + } catch (error) { + console.error("Error sending message:", error); + // Fallback response + const assistantMessage: Message = { + id: (Date.now() + 1).toString(), + role: "assistant", + content: `I'm ${character.name}. There was a connection issue, but I'm here to help!`, + timestamp: new Date(), + }; + setMessages(prev => [...prev, assistantMessage]); + } finally { + setSending(false); + inputRef.current?.focus(); + } + }; + + const clearChat = () => { + setMessages([]); + localStorage.removeItem(`character-chat-${slug}`); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + sendMessage(); + } + }; + + if (loading) { + return ( +
+ +
+ ); + } + + if (!character) { + return ( +
+
+ +

Character not found

+ + + +
+
+ ); + } + + return ( +
+ {/* Header */} +
+
+
+ + + + + + + + + +
+

{character.name}

+
+ + Online +
+
+
+ + +
+ + + + + Like + + + + + + + Save + + + + + + + Clear Chat + +
+
+
+
+ + {/* Chat Area */} +
+
+ {/* Welcome message if no messages */} + {messages.length === 0 && ( + + + + + + + +

{character.name}

+

+ {character.description} +

+
+ {character.tags.map(tag => ( + {tag} + ))} +
+

+ Start a conversation below... +

+
+ )} + + {/* Messages */} +
+ + {messages.map((message) => ( + +
+ {message.role === "assistant" && ( + + + + + + + )} + + +

{message.content}

+
+
+
+
+ ))} +
+ + {/* Typing indicator */} + {sending && ( + + + + + + + + + +
+ + + +
+
+
+
+ )} +
+
+
+ + {/* Input Area */} +
+
+ setInput(e.target.value)} + onKeyDown={handleKeyDown} + disabled={sending} + className="flex-1" + /> + +
+
+
+
+ ); +} diff --git a/src/app/characters/layout.tsx b/src/app/characters/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..62ec182ecdfb14480b7972e7e8bbf0b973d0cddc --- /dev/null +++ b/src/app/characters/layout.tsx @@ -0,0 +1,15 @@ +import { Metadata } from "next" +import { generateSEO } from "@/lib/seo" + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const metadata: Metadata = generateSEO({ + title: "AI Characters | OpenPrompt", + description: "Browse AI character prompts โ€” persona-based prompts for roleplay, creative writing, tutoring, and more. Run them instantly on OpenPrompt.", + url: `${BASE_URL}/characters`, + keywords: ["AI characters", "character prompts", "AI persona", "roleplay prompts", "creative writing AI"], +}) as Metadata + +export default function CharactersLayout({ children }: { children: React.ReactNode }) { + return children +} diff --git a/src/app/characters/loading.tsx b/src/app/characters/loading.tsx new file mode 100644 index 0000000000000000000000000000000000000000..492b1040c0efaac87c82d1e6876a1ed729fe7510 --- /dev/null +++ b/src/app/characters/loading.tsx @@ -0,0 +1,46 @@ +import { Skeleton } from "@/components/ui/skeleton"; + +export default function CharactersLoading() { + return ( +
+
+
+ + + +
+
+ +
+
+
+ {[...Array(8)].map((_, i) => ( + + ))} +
+
+
+ +
+
+
+ {[...Array(8)].map((_, i) => ( +
+
+ +
+ +
+ + +
+ + +
+ ))} +
+
+
+
+ ); +} diff --git a/src/app/characters/page.tsx b/src/app/characters/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..41efff215dae3a4fe4e59293b7765b7b97f22acb --- /dev/null +++ b/src/app/characters/page.tsx @@ -0,0 +1,285 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { motion } from "framer-motion"; +import Link from "next/link"; +import { + Bot, + User, + Sparkles, + Search, + Filter, + MessageCircle, + Heart, + Bookmark, + Play, + Users, + Wand2, + Brain, + GraduationCap, + Briefcase, + Gamepad2, + HeartHandshake +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Badge } from "@/components/ui/badge"; +import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +// Character categories +const CATEGORIES = [ + { id: "all", name: "All", icon: Sparkles }, + { id: "assistant", name: "Assistants", icon: Bot }, + { id: "roleplay", name: "Roleplay", icon: Gamepad2 }, + { id: "education", name: "Education", icon: GraduationCap }, + { id: "productivity", name: "Productivity", icon: Briefcase }, + { id: "creative", name: "Creative", icon: Wand2 }, + { id: "companion", name: "Companions", icon: HeartHandshake }, + { id: "expert", name: "Experts", icon: Brain }, +]; + +function getStyleColor(style?: string) { + const colors: Record = { + realistic: "bg-blue-900/50 text-blue-300 border-blue-700", + anime: "bg-pink-900/50 text-pink-300 border-pink-700", + cartoon: "bg-green-900/50 text-green-300 border-green-700", + fantasy: "bg-purple-900/50 text-purple-300 border-purple-700", + }; + return colors[style || ""] || "bg-gray-900/50 text-gray-300 border-gray-700"; +} + +export default function CharactersPage() { + const [selectedCategory, setSelectedCategory] = useState("all"); + const [searchQuery, setSearchQuery] = useState(""); + const [sortBy, setSortBy] = useState("popular"); + const [characters, setCharacters] = useState([]); + const [loading, setLoading] = useState(true); + + // Fetch characters from database + useEffect(() => { + const fetchCharacters = async () => { + try { + const params = new URLSearchParams(); + if (selectedCategory !== "all") params.set("category", selectedCategory); + if (searchQuery) params.set("search", searchQuery); + params.set("sortBy", sortBy); + + const res = await fetch(`/api/characters?${params}`); + if (res.ok) { + const data = await res.json(); + setCharacters(data.characters || []); + } else { + setCharacters([]); + } + } catch (error) { + console.error("Error fetching characters:", error); + setCharacters([]); + } finally { + setLoading(false); + } + }; + fetchCharacters(); + }, [selectedCategory, sortBy, searchQuery]); + + const filteredCharacters = characters.filter((char) => { + const matchesCategory = selectedCategory === "all" || char.category === selectedCategory; + const matchesSearch = + searchQuery === "" || + char.name.toLowerCase().includes(searchQuery.toLowerCase()) || + char.description.toLowerCase().includes(searchQuery.toLowerCase()) || + char.tags.some((tag: string) => tag.toLowerCase().includes(searchQuery.toLowerCase())); + return matchesCategory && matchesSearch; + }); + + return ( +
+ {/* Header */} +
+
+ + + + AI Characters + +

+ Meet Your AI{" "} + + Characters + +

+

+ Chat with unique AI personas designed for specific tasks. From coding mentors + to creative collaborators, find the perfect character for your needs. +

+
+
+
+ + {/* Category Tabs */} +
+
+ + + {CATEGORIES.map((cat) => ( + + + {cat.name} + + ))} + + +
+
+ + {/* Filters */} +
+
+
+
+ + setSearchQuery(e.target.value)} + /> +
+ +
+
+
+ + {/* Characters Grid */} +
+
+
+ {filteredCharacters.map((character, index) => ( + + + {/* Character Header */} + +
+ + + + + + +
+
+

{character.name}

+
+ + {character.style} + + + {CATEGORIES.find(c => c.id === character.category)?.name} + +
+ + + +

+ {character.description} +

+
+ {character.tags.slice(0, 3).map((tag: string) => ( + + {tag} + + ))} +
+
+ + +
+ + + {(character.totalChats / 1000).toFixed(1)}K + + + + {(character.votesCount / 1000).toFixed(1)}K + + + + {character.savesCount} + +
+ + + +
+ + + ))} +
+ + {filteredCharacters.length === 0 && ( +
+ +

No characters found

+

+ Try adjusting your filters or search query +

+
+ )} +
+
+ + {/* CTA Section */} +
+
+ + + +

Create Your Own Character

+

+ Design a unique AI persona with custom personality, expertise, and conversation style +

+ +
+
+
+
+
+ ); +} diff --git a/src/app/collections/[id]/page.tsx b/src/app/collections/[id]/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..478b349117d2f29ffea59a07698fc81cb572b963 --- /dev/null +++ b/src/app/collections/[id]/page.tsx @@ -0,0 +1,173 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' +import Link from 'next/link' +import prisma from '@/lib/prisma' +import { PromptCard } from '@/components/explore/prompt-card' +import { Card, CardContent } from '@/components/ui/card' +import { Button } from '@/components/ui/button' +import { BookOpen, Lock } from 'lucide-react' +import { generateSEO } from '@/lib/seo' + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +interface CollectionPromptItem { + prompt: { + id: string + slug: string + title: string + description: string | null + category: string | null + totalRuns: number + starsCount: number + remixesCount: number + badges: string[] + creator: { + name: string | null + username: string | null + image: string | null + } | null + } +} + +export const dynamic = 'force-dynamic' + +interface CollectionPageProps { + params: Promise<{ id: string }> +} + +export async function generateMetadata({ params }: CollectionPageProps): Promise { + const { id } = await params + + const collection = await prisma.collection.findUnique({ + where: { id }, + select: { name: true, description: true }, + }) + + if (!collection) { + return { title: 'Collection Not Found' } + } + + return generateSEO({ + title: `${collection.name} | Prompt Collection`, + description: collection.description || `Browse the ${collection.name} prompt collection on OpenPrompt`, + url: `${BASE_URL}/collections/${id}`, + }) as Metadata +} + +export default async function CollectionPage({ params }: CollectionPageProps) { + const { id } = await params + + const collection = await prisma.collection.findUnique({ + where: { id }, + include: { + user: { + select: { + name: true, + username: true, + image: true, + }, + }, + prompts: { + include: { + prompt: { + include: { + creator: { + select: { + name: true, + username: true, + image: true, + }, + }, + }, + }, + }, + }, + }, + }) + + if (!collection) { + notFound() + } + + // Check if collection is public or belongs to user + // For now, just show if public + if (!collection.isPublic) { + return ( +
+ + + +

Private Collection

+

+ This collection is private and cannot be viewed. +

+
+
+
+ ) + } + + return ( +
+ {/* Collection Header */} +
+
+ + Collection by + {collection.user.username ? ( + + {collection.user.name || collection.user.username} + + ) : ( + {collection.user.name || 'Anonymous'} + )} +
+ +

+ {collection.name} +

+ + {collection.description && ( +

+ {collection.description} +

+ )} + +
+ {collection.prompts.length} prompts + {collection.viewCount} views +
+
+ + {/* Prompts */} + {collection.prompts.length > 0 ? ( +
+ {collection.prompts.map((item: CollectionPromptItem) => ( + + ))} +
+ ) : ( + + + +

No prompts in this collection yet

+
+
+ )} +
+ ) +} diff --git a/src/app/collections/layout.tsx b/src/app/collections/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..290a84e328efd24fe4b0c365dd5c88d453abfa31 --- /dev/null +++ b/src/app/collections/layout.tsx @@ -0,0 +1,33 @@ +import { Suspense } from "react" +import { Metadata } from "next" +import { Loader2 } from "lucide-react" +import { generateSEO } from "@/lib/seo" + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const metadata: Metadata = generateSEO({ + title: "Prompt Collections | OpenPrompt", + description: "Browse curated collections of AI prompts. Find organized sets of prompts for marketing, coding, writing, and more.", + url: `${BASE_URL}/collections`, + keywords: ["prompt collections", "curated prompts", "AI prompt sets", "prompt bundles"], +}) as Metadata + +function CollectionsLoading() { + return ( +
+ +
+ ) +} + +export default function CollectionsLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + }> + {children} + + ) +} diff --git a/src/app/collections/page.tsx b/src/app/collections/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a1bd53319c274f1c8f6136027244cef2ce1dcf22 --- /dev/null +++ b/src/app/collections/page.tsx @@ -0,0 +1,137 @@ +"use client" + +import { useUser } from "@stackframe/stack" +import { useEffect, useState } from "react" +import Link from "next/link" +import { Card, CardContent } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { Loader2, BookOpen, Plus, Lock, Globe } from "lucide-react" + +interface Collection { + id: string + name: string + description: string | null + isPublic: boolean + viewCount: number + prompts: any[] + createdAt: string +} + +export default function MyCollectionsPage() { + const user = useUser() + const [collections, setCollections] = useState([]) + const [isLoading, setIsLoading] = useState(true) + + useEffect(() => { + if (!user) return + + async function fetchCollections() { + if (!user) return // Guard for TypeScript + try { + const res = await fetch(`/api/collections?userId=${user.id}`) + if (res.ok) { + const data = await res.json() + setCollections(data) + } + } catch (error) { + console.error("Failed to fetch collections:", error) + } finally { + setIsLoading(false) + } + } + + fetchCollections() + }, [user]) + + if (!user) { + return ( +
+ + + +

Sign in to view collections

+

+ Organize your favorite prompts into collections +

+ +
+
+
+ ) + } + + return ( +
+ {/* Header */} +
+
+

+ My Collections +

+

+ Organize and share your favorite prompts +

+
+ +
+ + {/* Content */} + {isLoading ? ( +
+ +
+ ) : collections.length > 0 ? ( +
+ {collections.map((collection) => ( + + + +
+

+ {collection.name} +

+ {collection.isPublic ? ( + + ) : ( + + )} +
+ + {collection.description && ( +

+ {collection.description} +

+ )} + +
+ {collection.prompts?.length || 0} prompts + {collection.viewCount} views +
+
+
+ + ))} +
+ ) : ( + + + +

No collections yet

+

+ Create your first collection to organize prompts +

+ +
+
+ )} +
+ ) +} diff --git a/src/app/contact/layout.tsx b/src/app/contact/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..238b5ebdbf16cd842efab268a6db850a4e390645 --- /dev/null +++ b/src/app/contact/layout.tsx @@ -0,0 +1,15 @@ +import { Metadata } from "next" +import { generateSEO } from "@/lib/seo" + +const BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://open-prompt.netlify.app' + +export const metadata: Metadata = generateSEO({ + title: "Contact Us | OpenPrompt", + description: "Get in touch with the OpenPrompt team. We'd love to hear your feedback, questions, or partnership inquiries.", + url: `${BASE_URL}/contact`, + keywords: ["contact OpenPrompt", "feedback", "support"], +}) as Metadata + +export default function ContactLayout({ children }: { children: React.ReactNode }) { + return children +} diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..be5adfa76a48569e35452afba2452826a8045941 --- /dev/null +++ b/src/app/contact/page.tsx @@ -0,0 +1,187 @@ +"use client" + +import { useState } from "react" +import { Mail, MessageSquare, Send, Github, Twitter } from "lucide-react" +import { Button } from "@/components/ui/button" + +export default function ContactPage() { + const [formState, setFormState] = useState({ + name: "", + email: "", + subject: "", + message: "", + }) + const [isSubmitting, setIsSubmitting] = useState(false) + const [submitted, setSubmitted] = useState(false) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setIsSubmitting(true) + + // Simulate form submission + await new Promise((resolve) => setTimeout(resolve, 1000)) + + setIsSubmitting(false) + setSubmitted(true) + } + + return ( +
+
+ {/* Header */} +
+
+ + Contact +
+

+ Get in Touch +

+

+ Have a question or feedback? We'd love to hear from you. +

+
+ +
+ {/* Contact Info */} +
+ + + + +
+

Response Time

+

+ We typically respond within 24-48 hours. +

+
+
+ + {/* Contact Form */} +
+ {submitted ? ( +
+
+ +
+

Message Sent!

+

+ Thanks for reaching out. We'll get back to you soon. +

+
+ ) : ( +
+
+
+ + setFormState({ ...formState, name: e.target.value })} + className="w-full px-4 py-2 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary" + placeholder="Your name" + /> +
+
+ + setFormState({ ...formState, email: e.target.value })} + className="w-full px-4 py-2 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary" + placeholder="you@example.com" + /> +
+
+ +
+ + setFormState({ ...formState, subject: e.target.value })} + className="w-full px-4 py-2 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary" + placeholder="How can we help?" + /> +
+ +
+ +