← back to Goodquestion
initial scaffold (gitify-all 2026-05-06)
9df33381b9e644c09e5deb5ac2182f8ffacadb24 · 2026-05-06 10:25:20 -0700 · Steve Abrams
Files touched
A .eslintrc.jsonA .gitignoreA AI_PROVIDER_FALLBACK.mdA DEPLOYMENT.mdA MCP_SERVER_GUIDE.mdA README.mdA cloudflaredA components.jsonA ecosystem.config.jsA monitor-health.shA next.config.jsA package-lock.jsonA package.jsonA postcss.config.jsA src/app/api/analyze/route.tsA src/app/api/mcp/fetch/[documentId]/route.tsA src/app/api/mcp/search/route.tsA src/app/api/opportunities/route.tsA src/app/api/sections/route.tsA src/app/globals.cssA src/app/layout.tsxA src/app/page.tsxA src/components/LoadingTicker.tsxA src/components/action-plan/ActionPlan.tsxA src/components/financial/StartupCapitalBreakdown.tsxA src/components/historical/HistoricalContext.tsxA src/components/historical/HistoricalTimeline.tsxA src/components/historical/TrajectoryCharts.tsxA src/components/market/CompetitorMap.tsxA src/components/market/IncomeProjections.tsxA src/components/market/MarketSizeChart.tsxA src/components/mindmap/MindMap.tsxA src/components/search/SearchForm.tsxA src/components/swot/SWOTChart.tsxA src/components/swot/ScoreCard.tsxA src/components/ui/badge.tsxA src/components/ui/card.tsxA src/lib/ai-provider-multi.tsA src/lib/ai-provider.tsA src/lib/ai-workflows.tsA src/lib/mcp-client.tsA src/lib/mock-data.tsA src/lib/utils.tsA src/types/swot.tsA tailwind.config.tsA tsconfig.json
Diff
commit 9df33381b9e644c09e5deb5ac2182f8ffacadb24
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed May 6 10:25:20 2026 -0700
initial scaffold (gitify-all 2026-05-06)
---
.eslintrc.json | 3 +
.gitignore | 45 +
AI_PROVIDER_FALLBACK.md | 292 +
DEPLOYMENT.md | 632 ++
MCP_SERVER_GUIDE.md | 680 ++
README.md | 375 +
cloudflared | Bin 0 -> 41192406 bytes
components.json | 17 +
ecosystem.config.js | 29 +
monitor-health.sh | 78 +
next.config.js | 17 +
package-lock.json | 7931 ++++++++++++++++++++
package.json | 39 +
postcss.config.js | 6 +
src/app/api/analyze/route.ts | 67 +
src/app/api/mcp/fetch/[documentId]/route.ts | 39 +
src/app/api/mcp/search/route.ts | 53 +
src/app/api/opportunities/route.ts | 147 +
src/app/api/sections/route.ts | 84 +
src/app/globals.css | 59 +
src/app/layout.tsx | 19 +
src/app/page.tsx | 490 ++
src/components/LoadingTicker.tsx | 104 +
src/components/action-plan/ActionPlan.tsx | 166 +
.../financial/StartupCapitalBreakdown.tsx | 262 +
src/components/historical/HistoricalContext.tsx | 55 +
src/components/historical/HistoricalTimeline.tsx | 91 +
src/components/historical/TrajectoryCharts.tsx | 143 +
src/components/market/CompetitorMap.tsx | 111 +
src/components/market/IncomeProjections.tsx | 127 +
src/components/market/MarketSizeChart.tsx | 220 +
src/components/mindmap/MindMap.tsx | 230 +
src/components/search/SearchForm.tsx | 347 +
src/components/swot/SWOTChart.tsx | 209 +
src/components/swot/ScoreCard.tsx | 108 +
src/components/ui/badge.tsx | 39 +
src/components/ui/card.tsx | 78 +
src/lib/ai-provider-multi.ts | 320 +
src/lib/ai-provider.ts | 249 +
src/lib/ai-workflows.ts | 508 ++
src/lib/mcp-client.ts | 145 +
src/lib/mock-data.ts | 1149 +++
src/lib/utils.ts | 6 +
src/types/swot.ts | 193 +
tailwind.config.ts | 80 +
tsconfig.json | 27 +
46 files changed, 16069 insertions(+)
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..bffb357
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e8cbe02
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,45 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+.env
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
+node_modules/
+.env.local
+.env.*.local
+.env.*
+tmp/
+*.log
+dist/
+build/
+*.bak
diff --git a/AI_PROVIDER_FALLBACK.md b/AI_PROVIDER_FALLBACK.md
new file mode 100644
index 0000000..f88df12
--- /dev/null
+++ b/AI_PROVIDER_FALLBACK.md
@@ -0,0 +1,292 @@
+# AI Provider Fallback System
+
+## Overview
+
+The SWOT Analysis Platform now includes an intelligent AI provider fallback system that automatically switches between Anthropic's Claude and Google's Gemini based on token usage, rate limits, and API availability.
+
+## Architecture
+
+### Components
+
+1. **AI Provider Manager** (`src/lib/ai-provider.ts`)
+ - Unified interface for multiple AI providers
+ - Automatic provider selection based on usage metrics
+ - Token usage tracking with rolling window
+ - Error handling and fallback logic
+
+2. **Updated Workflows** (`src/lib/ai-workflows.ts`)
+ - SWOT Analysis workflow
+ - Historical Context workflow
+ - Startup Costs workflow
+ - All now use the unified AI provider
+
+## Features
+
+### Automatic Provider Selection
+
+The system automatically selects the best provider based on:
+
+1. **Rate Limit Detection**
+ - Tracks API errors (429, low credit balance)
+ - Implements 1-minute cooldown after rate limit errors
+ - Automatically falls back to Gemini during cooldown
+
+2. **Token Usage Monitoring**
+ - Tracks output tokens in a rolling 1-minute window
+ - Anthropic limit: 4,000 output tokens per minute
+ - Switches to Gemini when usage exceeds 80% of limit (3,200 tokens)
+
+3. **Error-Based Fallback**
+ - Catches rate limit errors (HTTP 429)
+ - Catches low credit balance errors (HTTP 400)
+ - Automatically retries with Gemini on failure
+
+### Provider Priority
+
+1. **Primary**: Anthropic Claude Sonnet 4.5
+ - Superior quality for complex business analysis
+ - Used when available and within rate limits
+
+2. **Fallback**: Google Gemini 1.5 Pro
+ - High quality alternative
+ - Generous rate limits
+ - Activated automatically when needed
+
+## Configuration
+
+### Environment Variables
+
+Add to `.env.local`:
+
+```bash
+# Anthropic API Configuration
+ANTHROPIC_API_KEY=sk-ant-api03-...
+
+# Google Gemini API Configuration
+GOOGLE_API_KEY=your-gemini-api-key-here
+```
+
+### Get API Keys
+
+- **Anthropic Claude**: https://console.anthropic.com/settings/keys
+- **Google Gemini**: https://aistudio.google.com/app/apikey
+
+## Usage
+
+The fallback system works automatically. No code changes needed in your application:
+
+```typescript
+// Old approach (removed)
+const message = await anthropic.messages.create({...})
+
+// New approach (automatic fallback)
+const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 5000,
+ temperature: 1.0,
+})
+
+console.log(`Generated using ${response.provider}`) // 'anthropic' or 'gemini'
+```
+
+## Monitoring
+
+### Console Logs
+
+The system logs provider selection and usage:
+
+```
+[AI Provider] anthropic used 1234 tokens. Total in last minute: 2500
+[SWOT] Generated using anthropic (1234 tokens)
+[Historical] Generated using gemini (890 tokens)
+[Startup Costs] Generated using anthropic (1567 tokens)
+```
+
+### Rate Limit Detection
+
+```
+[AI Provider] Anthropic is rate limited, using Gemini
+[AI Provider] Approaching Anthropic token limit, using Gemini
+[AI Provider] Anthropic failed (rate_limit_error), falling back to Gemini
+```
+
+### Statistics API
+
+Access provider statistics programmatically:
+
+```typescript
+import { aiProvider } from '@/lib/ai-provider'
+
+const stats = aiProvider.getStats()
+// {
+// anthropic: {
+// provider: 'anthropic',
+// requestCount: 15,
+// totalTokens: 12500,
+// lastError: 'rate_limit_error',
+// lastErrorTime: Date
+// },
+// gemini: {
+// provider: 'gemini',
+// requestCount: 3,
+// totalTokens: 2800
+// }
+// }
+
+// Reset statistics
+aiProvider.resetStats()
+```
+
+## Token Limits
+
+### Anthropic Claude
+
+- **Output Tokens**: 4,000 per minute
+- **Input Tokens**: Separate limit (higher)
+- **Fallback Threshold**: 3,200 tokens/min (80%)
+
+### Google Gemini
+
+- **Requests**: 15 per minute (free tier)
+- **Tokens**: Much higher limits
+- **Input/Output**: Combined into single limit
+
+## Behavior Under Load
+
+### Scenario 1: Normal Operation
+- All requests use Anthropic Claude
+- High quality responses
+- ~1,200-1,500 output tokens per analysis
+
+### Scenario 2: High Traffic
+- First 2-3 requests use Anthropic (~4,000 tokens total)
+- System detects approaching limit (3,200 threshold)
+- Remaining requests use Gemini
+- After 1 minute, Anthropic becomes available again
+
+### Scenario 3: Rate Limited
+- Anthropic returns 429 error
+- Request automatically retries with Gemini
+- 1-minute cooldown period activated
+- All subsequent requests use Gemini
+- After cooldown, Anthropic becomes available
+
+### Scenario 4: Low Credits
+- Anthropic returns "credit balance too low" error
+- Request automatically retries with Gemini
+- System remembers error for 1 minute
+- Falls back to Gemini for all requests during cooldown
+
+## Error Handling
+
+The system handles errors gracefully:
+
+1. **Anthropic Fails → Gemini Fallback**
+ - Rate limit (429)
+ - Low credits (400)
+ - Connection timeout
+
+2. **Both Fail → Error Returned**
+ - If forced to use Gemini and it fails
+ - Original error is thrown to caller
+
+3. **Partial Results**
+ - Route uses `Promise.allSettled()`
+ - Returns partial data even if some workflows fail
+ - Includes warnings array in response
+
+## Testing
+
+### Test Fallback Manually
+
+Force Gemini usage:
+
+```typescript
+const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 5000,
+ forceProvider: 'gemini'
+})
+```
+
+### Test Rate Limit Behavior
+
+1. Make multiple rapid requests to exhaust Anthropic quota
+2. Watch logs for automatic Gemini fallback
+3. Wait 60 seconds
+4. Observe Anthropic becoming available again
+
+### Verify Token Tracking
+
+```typescript
+import { aiProvider } from '@/lib/ai-provider'
+
+// Make some requests
+await generateAnalysis(...)
+
+// Check stats
+const stats = aiProvider.getStats()
+console.log('Anthropic requests:', stats.anthropic.requestCount)
+console.log('Anthropic tokens:', stats.anthropic.totalTokens)
+```
+
+## Benefits
+
+1. **High Availability**: System continues working even when one provider fails
+2. **Cost Optimization**: Uses free/cheaper Gemini when rate limits approached
+3. **Quality First**: Prioritizes Claude for best results when available
+4. **Transparent**: Automatic switching requires no code changes
+5. **Observable**: Detailed logging for debugging and monitoring
+6. **Resilient**: Graceful degradation with partial results
+
+## Future Enhancements
+
+Potential improvements:
+
+1. **MCP Integration**: Store usage metrics in MCP for persistent monitoring
+2. **Multiple Fallbacks**: Add OpenAI GPT-4 as tertiary option
+3. **Load Balancing**: Distribute requests across providers proactively
+4. **Quality Comparison**: A/B test provider outputs for quality metrics
+5. **Cost Tracking**: Monitor and optimize based on API costs
+6. **User Preference**: Allow users to select preferred provider
+7. **Regional Routing**: Use different providers based on user location
+
+## Troubleshooting
+
+### Issue: Always using Gemini
+
+**Cause**: Anthropic API key not configured or invalid
+
+**Solution**:
+- Check `.env.local` has valid `ANTHROPIC_API_KEY`
+- Restart server after adding key
+- Check console for authentication errors
+
+### Issue: Gemini requests failing
+
+**Cause**: Google API key not configured or quota exceeded
+
+**Solution**:
+- Add `GOOGLE_API_KEY` to `.env.local`
+- Get free key from https://aistudio.google.com/app/apikey
+- Check Google Cloud Console for quota limits
+
+### Issue: Both providers failing
+
+**Cause**: Network issues or both APIs down
+
+**Solution**:
+- Check internet connectivity
+- Verify API status pages
+- Check for firewall/proxy issues
+- Review server logs for specific errors
+
+## Summary
+
+The AI Provider Fallback System provides enterprise-grade reliability through:
+
+- Automatic provider selection based on real-time metrics
+- Intelligent fallback on rate limits or errors
+- Token usage tracking with rolling windows
+- Graceful degradation with partial results
+- Transparent operation requiring no application changes
+
+This ensures the SWOT Analysis Platform remains available and responsive even under heavy load or API constraints.
diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md
new file mode 100644
index 0000000..a12cc93
--- /dev/null
+++ b/DEPLOYMENT.md
@@ -0,0 +1,632 @@
+# Deployment Guide
+
+Complete guide for deploying the SWOT Analysis Platform to production.
+
+## Deployment Options
+
+### Option 1: Vercel (Recommended)
+
+Vercel provides the best integration with Next.js and supports automatic deployments from GitHub.
+
+#### Setup Steps
+
+1. **Create Vercel Account**
+ - Go to [vercel.com](https://vercel.com)
+ - Sign up with GitHub
+
+2. **Install Vercel CLI** (optional but recommended)
+ ```bash
+ npm i -g vercel
+ ```
+
+3. **Connect GitHub Repository**
+ - Push your code to GitHub
+ - In Vercel dashboard, click "New Project"
+ - Import your repository
+
+4. **Configure Environment Variables**
+ In Project Settings → Environment Variables, add:
+ ```
+ ANTHROPIC_API_KEY=sk-ant-api03-xxx
+ MCP_SERVER_URL=https://your-mcp-server.com
+ MCP_API_KEY=your_mcp_key
+ NEXT_PUBLIC_APP_URL=https://your-domain.vercel.app
+ ```
+
+5. **Deploy**
+ ```bash
+ # First deployment
+ vercel
+
+ # Production deployment
+ vercel --prod
+ ```
+
+6. **Set Up Custom Domain**
+ - In Project Settings → Domains
+ - Add your custom domain
+ - Follow DNS configuration instructions
+
+#### Continuous Deployment
+
+Vercel automatically deploys:
+- **Production**: Every push to `main` branch
+- **Preview**: Every pull request gets a unique preview URL
+
+To customize:
+```json
+// vercel.json
+{
+ "git": {
+ "deploymentEnabled": {
+ "main": true,
+ "feature/*": true
+ }
+ },
+ "github": {
+ "silent": false
+ }
+}
+```
+
+---
+
+### Option 2: Self-Hosted (Docker)
+
+For full control over hosting environment.
+
+#### 1. Create Dockerfile
+
+Already included in the project root:
+
+```dockerfile
+FROM node:18-alpine AS base
+
+# Install dependencies only when needed
+FROM base AS deps
+WORKDIR /app
+COPY package.json package-lock.json ./
+RUN npm ci
+
+# Rebuild the source code only when needed
+FROM base AS builder
+WORKDIR /app
+COPY --from=deps /app/node_modules ./node_modules
+COPY . .
+
+ENV NEXT_TELEMETRY_DISABLED 1
+RUN npm run build
+
+# Production image, copy all the files and run next
+FROM base AS runner
+WORKDIR /app
+
+ENV NODE_ENV production
+ENV NEXT_TELEMETRY_DISABLED 1
+
+RUN addgroup --system --gid 1001 nodejs
+RUN adduser --system --uid 1001 nextjs
+
+COPY --from=builder /app/public ./public
+COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
+COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
+
+USER nextjs
+
+EXPOSE 3000
+
+ENV PORT 3000
+ENV HOSTNAME "0.0.0.0"
+
+CMD ["node", "server.js"]
+```
+
+#### 2. Build and Run
+
+```bash
+# Build image
+docker build -t swot-platform .
+
+# Run container
+docker run -d \
+ -p 3000:3000 \
+ --name swot-app \
+ --env-file .env \
+ swot-platform
+
+# Check logs
+docker logs -f swot-app
+```
+
+#### 3. Docker Compose (with MCP Server)
+
+```yaml
+# docker-compose.yml
+version: '3.8'
+
+services:
+ web:
+ build: .
+ ports:
+ - "3000:3000"
+ environment:
+ - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
+ - MCP_SERVER_URL=http://mcp-server:8000
+ - MCP_API_KEY=${MCP_API_KEY}
+ depends_on:
+ - mcp-server
+
+ mcp-server:
+ build: ./mcp-server
+ ports:
+ - "8000:8000"
+ volumes:
+ - ./data:/app/data
+ environment:
+ - MCP_API_KEY=${MCP_API_KEY}
+```
+
+Deploy:
+```bash
+docker-compose up -d
+```
+
+---
+
+### Option 3: AWS (EC2 + RDS)
+
+For enterprise-grade deployment with database.
+
+#### Prerequisites
+- AWS account
+- AWS CLI configured
+- Domain name
+
+#### Steps
+
+1. **Create EC2 Instance**
+ ```bash
+ aws ec2 run-instances \
+ --image-id ami-0c55b159cbfafe1f0 \
+ --instance-type t3.medium \
+ --key-name your-key-pair \
+ --security-group-ids sg-xxxxx
+ ```
+
+2. **SSH into Instance**
+ ```bash
+ ssh -i your-key.pem ec2-user@your-instance-ip
+ ```
+
+3. **Install Dependencies**
+ ```bash
+ # Install Node.js
+ curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
+ sudo yum install -y nodejs
+
+ # Install PM2
+ sudo npm install -g pm2
+
+ # Install Docker (optional)
+ sudo yum install -y docker
+ sudo service docker start
+ ```
+
+4. **Deploy Application**
+ ```bash
+ # Clone repository
+ git clone https://github.com/your-repo/swot-platform.git
+ cd swot-platform
+
+ # Install dependencies
+ npm ci
+
+ # Build
+ npm run build
+
+ # Start with PM2
+ pm2 start npm --name "swot-app" -- start
+ pm2 save
+ pm2 startup
+ ```
+
+5. **Configure Nginx Reverse Proxy**
+ ```nginx
+ # /etc/nginx/conf.d/swot.conf
+ server {
+ listen 80;
+ server_name your-domain.com;
+
+ location / {
+ proxy_pass http://localhost:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ }
+ }
+ ```
+
+6. **Set Up SSL with Let's Encrypt**
+ ```bash
+ sudo certbot --nginx -d your-domain.com
+ ```
+
+---
+
+## MCP Server Deployment
+
+The MCP server needs to be deployed separately for production use.
+
+### Option A: Replit (Quick & Easy)
+
+1. **Create New Repl**
+ - Go to [replit.com](https://replit.com)
+ - Create new Python repl
+
+2. **Add Code**
+ ```python
+ # main.py
+ from fastmcp import FastMCP
+ import chromadb
+ import os
+
+ mcp = FastMCP("SWOT Data Server")
+ client = chromadb.Client()
+
+ # Initialize collections
+ collection = client.create_collection("business_data")
+
+ @mcp.tool()
+ def search(query: str, limit: int = 10):
+ results = collection.query(
+ query_texts=[query],
+ n_results=limit
+ )
+ return results
+
+ @mcp.tool()
+ def fetch(document_id: str):
+ doc = collection.get(ids=[document_id])
+ return doc
+
+ if __name__ == "__main__":
+ port = int(os.getenv("PORT", 8000))
+ mcp.run(host="0.0.0.0", port=port)
+ ```
+
+3. **Add Dependencies**
+ ```txt
+ # requirements.txt
+ fastmcp
+ chromadb
+ uvicorn
+ ```
+
+4. **Run and Get URL**
+ - Click "Run"
+ - Copy the public URL (e.g., `https://your-repl.repl.co`)
+ - Use this as `MCP_SERVER_URL`
+
+### Option B: Railway
+
+1. **Install Railway CLI**
+ ```bash
+ npm i -g @railway/cli
+ ```
+
+2. **Deploy MCP Server**
+ ```bash
+ cd mcp-server
+ railway login
+ railway init
+ railway up
+ ```
+
+3. **Get Public URL**
+ ```bash
+ railway domain
+ ```
+
+### Option C: AWS Lambda (Serverless)
+
+For production-grade, auto-scaling deployment:
+
+```python
+# lambda_handler.py
+import json
+from fastmcp import FastMCP
+
+mcp = FastMCP("SWOT MCP")
+
+def lambda_handler(event, context):
+ # Parse API Gateway event
+ path = event['path']
+ method = event['httpMethod']
+ body = json.loads(event.get('body', '{}'))
+
+ # Route to MCP handlers
+ if path == '/search' and method == 'POST':
+ results = mcp.search(body['query'], body.get('limit', 10))
+ return {
+ 'statusCode': 200,
+ 'body': json.dumps(results)
+ }
+
+ return {
+ 'statusCode': 404,
+ 'body': json.dumps({'error': 'Not found'})
+ }
+```
+
+Deploy with SAM or Serverless Framework.
+
+---
+
+## Database Setup (Optional)
+
+For storing analysis results and user data:
+
+### PostgreSQL on AWS RDS
+
+```bash
+# Create RDS instance
+aws rds create-db-instance \
+ --db-instance-identifier swot-db \
+ --db-instance-class db.t3.micro \
+ --engine postgres \
+ --master-username admin \
+ --master-user-password yourpassword \
+ --allocated-storage 20
+```
+
+### Prisma Schema
+
+```prisma
+// prisma/schema.prisma
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+generator client {
+ provider = "prisma-client-js"
+}
+
+model Analysis {
+ id String @id @default(cuid())
+ businessName String
+ businessType String
+ location String
+ swotData Json
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+```
+
+---
+
+## Environment Configuration
+
+### Production Environment Variables
+
+```env
+# API Keys
+ANTHROPIC_API_KEY=sk-ant-api03-xxx
+MCP_API_KEY=prod_xxx
+
+# URLs
+MCP_SERVER_URL=https://mcp.your-domain.com
+NEXT_PUBLIC_APP_URL=https://your-domain.com
+
+# Database (if using)
+DATABASE_URL=postgresql://user:pass@host:5432/dbname
+
+# Analytics (optional)
+NEXT_PUBLIC_VERCEL_ANALYTICS_ID=xxx
+```
+
+### Security Best Practices
+
+1. **Never commit `.env` files**
+ - Use `.env.example` for documentation
+ - Set real values in deployment platform
+
+2. **Rotate API keys regularly**
+ - Set calendar reminder for quarterly rotation
+
+3. **Use secrets management**
+ ```bash
+ # AWS Secrets Manager
+ aws secretsmanager create-secret \
+ --name swot/anthropic-key \
+ --secret-string "sk-ant-xxx"
+ ```
+
+4. **Enable CORS properly**
+ ```typescript
+ // next.config.js
+ module.exports = {
+ async headers() {
+ return [
+ {
+ source: '/api/:path*',
+ headers: [
+ { key: 'Access-Control-Allow-Origin', value: 'https://your-domain.com' },
+ ],
+ },
+ ]
+ },
+ }
+ ```
+
+---
+
+## Monitoring & Analytics
+
+### Vercel Analytics
+
+Add to `app/layout.tsx`:
+```typescript
+import { Analytics } from '@vercel/analytics/react'
+
+export default function RootLayout({ children }) {
+ return (
+ <html>
+ <body>
+ {children}
+ <Analytics />
+ </body>
+ </html>
+ )
+}
+```
+
+### Error Tracking (Sentry)
+
+```bash
+npm install @sentry/nextjs
+```
+
+```javascript
+// sentry.client.config.js
+import * as Sentry from '@sentry/nextjs'
+
+Sentry.init({
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
+ tracesSampleRate: 1.0,
+})
+```
+
+---
+
+## CI/CD Pipeline
+
+### GitHub Actions
+
+```yaml
+# .github/workflows/deploy.yml
+name: Deploy to Production
+
+on:
+ push:
+ branches: [main]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Run tests
+ run: npm test
+
+ - name: Build
+ run: npm run build
+ env:
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
+
+ - name: Deploy to Vercel
+ uses: amondnet/vercel-action@v20
+ with:
+ vercel-token: ${{ secrets.VERCEL_TOKEN }}
+ vercel-org-id: ${{ secrets.ORG_ID }}
+ vercel-project-id: ${{ secrets.PROJECT_ID }}
+ vercel-args: '--prod'
+```
+
+---
+
+## Post-Deployment Checklist
+
+- [ ] Verify all environment variables are set
+- [ ] Test API endpoints (`/api/analyze`, `/api/mcp/search`)
+- [ ] Check SSL certificate is active
+- [ ] Verify MCP server connectivity
+- [ ] Test with real business analysis
+- [ ] Set up monitoring alerts
+- [ ] Configure backup strategy
+- [ ] Document custom domain DNS settings
+- [ ] Enable CDN for static assets
+- [ ] Set up log aggregation
+
+---
+
+## Troubleshooting
+
+### Build Failures
+
+```bash
+# Clear cache and rebuild
+rm -rf .next node_modules
+npm install
+npm run build
+```
+
+### MCP Connection Issues
+
+```bash
+# Test MCP endpoint
+curl -X POST https://your-mcp-server.com/search \
+ -H "Content-Type: application/json" \
+ -d '{"query": "test", "limit": 1}'
+```
+
+### Memory Issues on Build
+
+```json
+// package.json
+{
+ "scripts": {
+ "build": "NODE_OPTIONS='--max-old-space-size=4096' next build"
+ }
+}
+```
+
+---
+
+## Scaling Considerations
+
+As your application grows:
+
+1. **Add Redis for caching**
+ ```typescript
+ import Redis from 'ioredis'
+ const redis = new Redis(process.env.REDIS_URL)
+
+ // Cache analysis results
+ await redis.setex(`analysis:${id}`, 3600, JSON.stringify(data))
+ ```
+
+2. **Implement rate limiting**
+ ```typescript
+ import { Ratelimit } from '@upstash/ratelimit'
+ const ratelimit = new Ratelimit({
+ redis,
+ limiter: Ratelimit.slidingWindow(10, '1 h'),
+ })
+ ```
+
+3. **Use CDN for assets**
+ - Vercel automatically provides this
+ - For self-hosted, use CloudFront or Cloudflare
+
+4. **Queue long-running analyses**
+ ```typescript
+ import { Queue } from 'bullmq'
+ const analysisQueue = new Queue('analysis')
+ await analysisQueue.add('swot-analysis', { businessName, businessType, location })
+ ```
+
+---
+
+For additional support, consult the main README.md or open an issue on GitHub.
diff --git a/MCP_SERVER_GUIDE.md b/MCP_SERVER_GUIDE.md
new file mode 100644
index 0000000..5b22b2f
--- /dev/null
+++ b/MCP_SERVER_GUIDE.md
@@ -0,0 +1,680 @@
+# MCP Server Implementation Guide
+
+Complete guide for building and deploying your Model Context Protocol (MCP) server for the SWOT Analysis Platform.
+
+## What is MCP?
+
+The Model Context Protocol (MCP) is a standardized way to connect AI models with external data sources. For this platform, the MCP server:
+
+1. **Stores** local business data in a vector database
+2. **Searches** through documents using semantic similarity
+3. **Retrieves** full document content on demand
+4. **Provides** context to Claude for analysis
+
+## Architecture Overview
+
+```
+┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
+│ Next.js App │────────>│ MCP Server │────────>│ Vector Store │
+│ (Frontend) │ HTTP │ (FastMCP) │ Query │ (ChromaDB) │
+└─────────────────┘ └──────────────────┘ └─────────────────┘
+ │
+ │ Ingest
+ ▼
+ ┌──────────────────┐
+ │ Data Sources │
+ │ - PDFs │
+ │ - Directories │
+ │ - Web Scraping │
+ └──────────────────┘
+```
+
+## Quick Start
+
+### Option 1: Basic Python Server
+
+```python
+# mcp_server.py
+from fastmcp import FastMCP
+import chromadb
+from chromadb.config import Settings
+import os
+
+# Initialize FastMCP server
+mcp = FastMCP("SWOT Business Data")
+
+# Initialize ChromaDB (vector database)
+client = chromadb.Client(Settings(
+ chroma_db_impl="duckdb+parquet",
+ persist_directory="./chroma_data"
+))
+
+# Create or get collection
+collection = client.get_or_create_collection(
+ name="business_data",
+ metadata={"description": "Local business and economic data"}
+)
+
+@mcp.tool()
+def search(
+ query: str,
+ filters: dict = None,
+ limit: int = 10
+) -> list:
+ """
+ Search the vector database for relevant documents
+
+ Args:
+ query: Search query string
+ filters: Optional metadata filters
+ limit: Maximum number of results
+
+ Returns:
+ List of search results with relevance scores
+ """
+ # Build where clause from filters
+ where = None
+ if filters:
+ where = {}
+ if 'documentType' in filters:
+ where['document_type'] = {'$in': filters['documentType']}
+ if 'location' in filters:
+ where['location'] = filters['location']
+
+ # Perform semantic search
+ results = collection.query(
+ query_texts=[query],
+ n_results=limit,
+ where=where
+ )
+
+ # Format results
+ formatted_results = []
+ for i in range(len(results['ids'][0])):
+ formatted_results.append({
+ 'id': results['ids'][0][i],
+ 'title': results['metadatas'][0][i].get('title', 'Untitled'),
+ 'snippet': results['documents'][0][i][:200] + '...',
+ 'relevance': 1 - results['distances'][0][i], # Convert distance to similarity
+ 'source': results['metadatas'][0][i].get('source', 'Unknown'),
+ 'datePublished': results['metadatas'][0][i].get('date_published')
+ })
+
+ return formatted_results
+
+@mcp.tool()
+def fetch(document_id: str) -> dict:
+ """
+ Fetch the full content of a document by ID
+
+ Args:
+ document_id: Unique document identifier
+
+ Returns:
+ Complete document with metadata
+ """
+ result = collection.get(
+ ids=[document_id],
+ include=['documents', 'metadatas']
+ )
+
+ if not result['ids']:
+ raise ValueError(f"Document {document_id} not found")
+
+ return {
+ 'id': result['ids'][0],
+ 'content': result['documents'][0],
+ 'metadata': result['metadatas'][0]
+ }
+
+# Health check endpoint
+@mcp.tool()
+def health() -> dict:
+ """Check server health and database stats"""
+ count = collection.count()
+ return {
+ 'status': 'healthy',
+ 'document_count': count,
+ 'version': '1.0.0'
+ }
+
+if __name__ == "__main__":
+ port = int(os.getenv("PORT", 8000))
+ mcp.run(host="0.0.0.0", port=port)
+```
+
+### Installation
+
+```bash
+# Create virtual environment
+python -m venv venv
+source venv/bin/activate # On Windows: venv\Scripts\activate
+
+# Install dependencies
+pip install fastmcp chromadb uvicorn python-dotenv
+
+# Run server
+python mcp_server.py
+```
+
+Server runs on `http://localhost:8000`
+
+---
+
+## Data Ingestion
+
+### Step 1: Prepare Data Sources
+
+Create a data ingestion script:
+
+```python
+# ingest_data.py
+import chromadb
+import os
+import glob
+from pathlib import Path
+import PyPDF2
+import json
+
+client = chromadb.Client(Settings(
+ persist_directory="./chroma_data"
+))
+collection = client.get_or_create_collection("business_data")
+
+def ingest_pdfs(directory: str, document_type: str):
+ """Ingest PDF files into vector database"""
+ pdf_files = glob.glob(f"{directory}/**/*.pdf", recursive=True)
+
+ for pdf_path in pdf_files:
+ try:
+ # Extract text from PDF
+ with open(pdf_path, 'rb') as file:
+ reader = PyPDF2.PdfReader(file)
+ text = ""
+ for page in reader.pages:
+ text += page.extract_text()
+
+ # Generate unique ID
+ doc_id = f"{document_type}_{Path(pdf_path).stem}"
+
+ # Add to collection
+ collection.add(
+ ids=[doc_id],
+ documents=[text],
+ metadatas=[{
+ 'title': Path(pdf_path).stem,
+ 'source': pdf_path,
+ 'document_type': document_type,
+ 'file_type': 'pdf'
+ }]
+ )
+ print(f"✓ Ingested: {pdf_path}")
+
+ except Exception as e:
+ print(f"✗ Error processing {pdf_path}: {e}")
+
+def ingest_json(file_path: str, document_type: str):
+ """Ingest structured JSON data"""
+ with open(file_path, 'r') as f:
+ data = json.load(f)
+
+ for item in data:
+ doc_id = f"{document_type}_{item['id']}"
+
+ # Convert item to text representation
+ text = f"{item.get('title', '')}\n{item.get('description', '')}\n{item.get('content', '')}"
+
+ collection.add(
+ ids=[doc_id],
+ documents=[text],
+ metadatas=[{
+ 'title': item.get('title', 'Untitled'),
+ 'source': file_path,
+ 'document_type': document_type,
+ **{k: v for k, v in item.items() if k not in ['id', 'title', 'description', 'content']}
+ }]
+ )
+
+# Example usage
+if __name__ == "__main__":
+ # Ingest different data types
+ ingest_pdfs('./data/historical', 'historical-document')
+ ingest_pdfs('./data/zoning', 'zoning-map')
+ ingest_pdfs('./data/economic', 'economic-report')
+ ingest_json('./data/competitors.json', 'business-directory')
+
+ print(f"\nTotal documents: {collection.count()}")
+```
+
+### Step 2: Data Sources to Collect
+
+#### Business Directories
+```python
+# scrape_businesses.py
+import requests
+from bs4 import BeautifulSoup
+import json
+
+def scrape_yelp_businesses(location: str, category: str):
+ """Example: Scrape business data from Yelp"""
+ # Note: Use Yelp API in production
+ url = f"https://api.yelp.com/v3/businesses/search"
+ headers = {"Authorization": f"Bearer {YELP_API_KEY}"}
+ params = {
+ "location": location,
+ "categories": category,
+ "limit": 50
+ }
+
+ response = requests.get(url, headers=headers, params=params)
+ businesses = response.json()['businesses']
+
+ # Save to JSON
+ with open(f'data/competitors_{location}.json', 'w') as f:
+ json.dump(businesses, f)
+
+ return businesses
+```
+
+#### Historical Documents
+- Local library archives (digitized)
+- Chamber of Commerce reports
+- Historical society publications
+- City planning documents
+
+#### Economic Data
+- Census Bureau data
+- Bureau of Labor Statistics
+- Local economic development reports
+- Real estate market reports
+
+### Step 3: Automated Web Scraping
+
+```python
+# scrape_economic_data.py
+import requests
+from datetime import datetime
+
+def fetch_census_data(location: str):
+ """Fetch demographic data from Census API"""
+ url = "https://api.census.gov/data/2021/acs/acs5"
+ params = {
+ "get": "B01001_001E,B19013_001E,B25077_001E", # Population, Income, Home Value
+ "for": f"place:{location}",
+ "key": CENSUS_API_KEY
+ }
+
+ response = requests.get(url, params=params)
+ data = response.json()
+
+ # Save to vector database
+ collection.add(
+ ids=[f"census_{location}_{datetime.now().year}"],
+ documents=[json.dumps(data)],
+ metadatas=[{
+ 'title': f"Census Data - {location}",
+ 'document_type': 'census-data',
+ 'location': location,
+ 'date_published': str(datetime.now().date())
+ }]
+ )
+```
+
+---
+
+## Advanced Features
+
+### Semantic Search Optimization
+
+```python
+# Enhanced search with re-ranking
+from sentence_transformers import CrossEncoder
+
+reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
+
+@mcp.tool()
+def search_with_reranking(query: str, limit: int = 10):
+ """Search with neural re-ranking for better relevance"""
+ # Initial retrieval (get more results)
+ initial_results = collection.query(
+ query_texts=[query],
+ n_results=limit * 3
+ )
+
+ # Re-rank using cross-encoder
+ pairs = [[query, doc] for doc in initial_results['documents'][0]]
+ scores = reranker.predict(pairs)
+
+ # Sort by score and take top results
+ ranked_indices = scores.argsort()[::-1][:limit]
+
+ return [initial_results['documents'][0][i] for i in ranked_indices]
+```
+
+### Hybrid Search (Keyword + Semantic)
+
+```python
+from chromadb.utils import embedding_functions
+
+# Use custom embedding function
+embed_fn = embedding_functions.SentenceTransformerEmbeddingFunction(
+ model_name="all-MiniLM-L6-v2"
+)
+
+collection = client.create_collection(
+ name="business_data_hybrid",
+ embedding_function=embed_fn,
+ metadata={"hnsw:space": "cosine"}
+)
+
+@mcp.tool()
+def hybrid_search(query: str, filters: dict = None):
+ """Combine semantic and keyword search"""
+ # Semantic search
+ semantic_results = collection.query(
+ query_texts=[query],
+ n_results=10
+ )
+
+ # Keyword search (simple text matching)
+ keyword_results = collection.get(
+ where_document={"$contains": query}
+ )
+
+ # Merge and deduplicate
+ all_ids = set(semantic_results['ids'][0] + keyword_results['ids'])
+
+ return list(all_ids)
+```
+
+### Caching Layer
+
+```python
+import redis
+import json
+
+redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)
+
+@mcp.tool()
+def cached_search(query: str, limit: int = 10):
+ """Search with Redis caching"""
+ cache_key = f"search:{query}:{limit}"
+
+ # Check cache
+ cached = redis_client.get(cache_key)
+ if cached:
+ return json.loads(cached)
+
+ # Perform search
+ results = search(query, limit=limit)
+
+ # Cache for 1 hour
+ redis_client.setex(cache_key, 3600, json.dumps(results))
+
+ return results
+```
+
+---
+
+## Security & Authentication
+
+### API Key Authentication
+
+```python
+from fastapi import HTTPException, Security
+from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
+
+security = HTTPBearer()
+
+VALID_API_KEYS = {
+ os.getenv("MCP_API_KEY"): "admin",
+ os.getenv("MCP_READ_KEY"): "read-only"
+}
+
+def verify_api_key(credentials: HTTPAuthorizationCredentials = Security(security)):
+ """Verify API key from Authorization header"""
+ api_key = credentials.credentials
+
+ if api_key not in VALID_API_KEYS:
+ raise HTTPException(status_code=403, detail="Invalid API key")
+
+ return VALID_API_KEYS[api_key]
+
+# Add to tool decorator
+@mcp.tool(dependencies=[verify_api_key])
+def search(query: str):
+ # ... search implementation
+```
+
+### Rate Limiting
+
+```python
+from slowapi import Limiter, _rate_limit_exceeded_handler
+from slowapi.util import get_remote_address
+
+limiter = Limiter(key_func=get_remote_address)
+
+@mcp.tool()
+@limiter.limit("10/minute")
+def search(query: str):
+ # ... search implementation
+```
+
+---
+
+## Deployment
+
+### Docker Deployment
+
+```dockerfile
+# Dockerfile
+FROM python:3.11-slim
+
+WORKDIR /app
+
+# Install dependencies
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+# Copy application
+COPY mcp_server.py .
+COPY ingest_data.py .
+COPY data/ ./data/
+
+# Create data directory
+RUN mkdir -p /app/chroma_data
+
+# Ingest data on build
+RUN python ingest_data.py
+
+# Expose port
+EXPOSE 8000
+
+# Run server
+CMD ["python", "mcp_server.py"]
+```
+
+Build and run:
+```bash
+docker build -t mcp-server .
+docker run -p 8000:8000 -e MCP_API_KEY=your_key mcp-server
+```
+
+### Kubernetes Deployment
+
+```yaml
+# deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mcp-server
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: mcp-server
+ template:
+ metadata:
+ labels:
+ app: mcp-server
+ spec:
+ containers:
+ - name: mcp-server
+ image: your-registry/mcp-server:latest
+ ports:
+ - containerPort: 8000
+ env:
+ - name: MCP_API_KEY
+ valueFrom:
+ secretKeyRef:
+ name: mcp-secrets
+ key: api-key
+ volumeMounts:
+ - name: chroma-data
+ mountPath: /app/chroma_data
+ volumes:
+ - name: chroma-data
+ persistentVolumeClaim:
+ claimName: chroma-pvc
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: mcp-service
+spec:
+ selector:
+ app: mcp-server
+ ports:
+ - port: 80
+ targetPort: 8000
+ type: LoadBalancer
+```
+
+---
+
+## Monitoring & Maintenance
+
+### Health Checks
+
+```python
+@mcp.tool()
+def health_check():
+ """Comprehensive health check"""
+ try:
+ # Check database
+ count = collection.count()
+
+ # Check disk space
+ import shutil
+ disk = shutil.disk_usage('/app/chroma_data')
+
+ return {
+ 'status': 'healthy',
+ 'documents': count,
+ 'disk_free_gb': disk.free / (1024**3),
+ 'uptime_seconds': time.time() - start_time
+ }
+ except Exception as e:
+ return {
+ 'status': 'unhealthy',
+ 'error': str(e)
+ }
+```
+
+### Logging
+
+```python
+import logging
+
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+ handlers=[
+ logging.FileHandler('mcp_server.log'),
+ logging.StreamHandler()
+ ]
+)
+
+logger = logging.getLogger(__name__)
+
+@mcp.tool()
+def search(query: str):
+ logger.info(f"Search query: {query}")
+ results = collection.query(query_texts=[query])
+ logger.info(f"Found {len(results['ids'][0])} results")
+ return results
+```
+
+---
+
+## Testing
+
+```python
+# test_mcp_server.py
+import pytest
+from mcp_server import search, fetch
+
+def test_search():
+ results = search("coffee shops Portland", limit=5)
+ assert len(results) <= 5
+ assert all('id' in r for r in results)
+
+def test_fetch():
+ # Assuming we know a document ID
+ doc = fetch("historical-document_portland_1990")
+ assert 'content' in doc
+ assert 'metadata' in doc
+
+def test_search_with_filters():
+ results = search(
+ "economic growth",
+ filters={'documentType': ['economic-report']},
+ limit=10
+ )
+ assert all(r['metadata']['document_type'] == 'economic-report' for r in results)
+```
+
+Run tests:
+```bash
+pytest test_mcp_server.py -v
+```
+
+---
+
+## Troubleshooting
+
+### Common Issues
+
+**Issue**: `chromadb.errors.ChromaError: Collection already exists`
+```python
+# Solution: Use get_or_create_collection
+collection = client.get_or_create_collection("business_data")
+```
+
+**Issue**: Slow search performance
+```python
+# Solution: Reduce embedding dimensions or use faster model
+embed_fn = embedding_functions.SentenceTransformerEmbeddingFunction(
+ model_name="all-MiniLM-L6-v2" # Faster, smaller model
+)
+```
+
+**Issue**: Memory errors with large documents
+```python
+# Solution: Chunk documents
+def chunk_text(text: str, chunk_size: int = 500):
+ words = text.split()
+ return [' '.join(words[i:i+chunk_size]) for i in range(0, len(words), chunk_size)]
+```
+
+---
+
+## Next Steps
+
+1. **Populate your database**: Run ingestion scripts with real data
+2. **Test endpoints**: Use curl or Postman to verify functionality
+3. **Deploy**: Choose deployment option (Replit, Railway, AWS)
+4. **Monitor**: Set up logging and health checks
+5. **Scale**: Add caching and load balancing as needed
+
+For integration with the Next.js frontend, see the main README.md.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c9f27c3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,375 @@
+# SWOT Analysis Platform
+
+AI-Powered Local Business Viability Analysis using Claude and Model Context Protocol (MCP)
+
+## Overview
+
+This Next.js application provides comprehensive SWOT (Strengths, Weaknesses, Opportunities, Threats) analysis for local business ventures. It leverages AI workflows through Claude API and integrates with an MCP server for deep data synthesis from historical documents, business directories, and market reports.
+
+## Features
+
+### Core Analysis Components
+
+- **Go/No-Go Scorecard**: Visual recommendation with overall viability score (0-100)
+- **Detailed SWOT Analysis**: Color-coded cards showing strengths, weaknesses, opportunities, and threats
+- **Historical Context**: Timeline visualization of key economic events and area trajectory charts
+- **Market Deep Dive**:
+ - Competitor mapping with distance and rating analysis
+ - Market size breakdown (TAM/SAM/SOM)
+ - 5-year income projections with optimistic/realistic/pessimistic scenarios
+- **System Architecture Mind Map**: Interactive visualization of the platform's technical components
+- **Action Plan**: Prioritized next steps with cost and time estimates
+
+## Tech Stack
+
+- **Framework**: Next.js 15.5.4 with React 19
+- **Styling**: Tailwind CSS 3.4 + shadcn/ui 2.1
+- **AI Integration**: Anthropic Claude Sonnet 4.5
+- **Data Protocol**: Model Context Protocol (MCP)
+- **Charts**: Recharts 2.12
+- **Type Safety**: TypeScript 5.6
+- **Deployment**: Vercel (recommended)
+
+## Project Structure
+
+```
+goodquestion/
+├── src/
+│ ├── app/
+│ │ ├── api/
+│ │ │ ├── analyze/ # Main SWOT analysis endpoint
+│ │ │ └── mcp/ # MCP search and fetch endpoints
+│ │ ├── layout.tsx
+│ │ ├── page.tsx # Main dashboard
+│ │ └── globals.css
+│ ├── components/
+│ │ ├── action-plan/ # Action plan components
+│ │ ├── historical/ # Historical timeline & trajectory charts
+│ │ ├── market/ # Market analysis visualizations
+│ │ ├── mindmap/ # System architecture mind map
+│ │ ├── swot/ # SWOT scorecard and charts
+│ │ └── ui/ # Reusable UI components (shadcn)
+│ ├── lib/
+│ │ ├── ai-workflows.ts # Claude AI integration workflows
+│ │ ├── mcp-client.ts # MCP server client
+│ │ ├── mock-data.ts # Sample data for development
+│ │ └── utils.ts # Utility functions
+│ └── types/
+│ └── swot.ts # TypeScript type definitions
+├── package.json
+├── tsconfig.json
+├── tailwind.config.ts
+└── next.config.js
+```
+
+## Installation
+
+### Prerequisites
+
+- Node.js 18+ and npm/pnpm/yarn
+- Anthropic API key
+- MCP server setup (optional for development)
+
+### Steps
+
+1. **Clone the repository**
+ ```bash
+ cd /root/WebsitesMisc/goodquestion
+ ```
+
+2. **Install dependencies**
+ ```bash
+ npm install
+ ```
+
+3. **Set up environment variables**
+ ```bash
+ cp .env.example .env
+ ```
+
+ Edit `.env` and add your API keys:
+ ```env
+ ANTHROPIC_API_KEY=your_anthropic_api_key_here
+ MCP_SERVER_URL=http://localhost:8000
+ MCP_API_KEY=your_mcp_api_key_here
+ ```
+
+4. **Run development server**
+ ```bash
+ npm run dev
+ ```
+
+5. **Open in browser**
+ Navigate to [http://localhost:3000](http://localhost:3000)
+
+## MCP Server Setup
+
+The MCP (Model Context Protocol) server provides access to local business data through vector search.
+
+### Quick Setup with Python and FastMCP
+
+```python
+# mcp_server.py
+from fastmcp import FastMCP
+import chromadb
+
+mcp = FastMCP("Local Business SWOT Data")
+
+# Initialize vector database
+client = chromadb.Client()
+collection = client.create_collection("business_data")
+
+@mcp.tool()
+def search(query: str, limit: int = 10):
+ """Search for relevant business documents"""
+ results = collection.query(
+ query_texts=[query],
+ n_results=limit
+ )
+ return results
+
+@mcp.tool()
+def fetch(document_id: str):
+ """Fetch full document by ID"""
+ doc = collection.get(ids=[document_id])
+ return doc
+
+if __name__ == "__main__":
+ mcp.run()
+```
+
+Run the server:
+```bash
+pip install fastmcp chromadb
+python mcp_server.py
+```
+
+### Data Sources to Ingest
+
+- Local business directories (Yelp, Google Business, Chamber of Commerce)
+- Historical economic documents (PDFs, reports)
+- Census and demographic data
+- Zoning maps and regulatory documents
+- Market trend reports
+
+## AI Workflows
+
+### SWOT Analysis Generation
+
+The platform uses specialized AI workflows to generate comprehensive analysis:
+
+```typescript
+// Example usage
+import { swotWorkflow } from '@/lib/ai-workflows'
+
+const analysis = await swotWorkflow.generateAnalysis(
+ 'Artisan Coffee Roastery',
+ 'Specialty Coffee Shop',
+ 'Downtown Portland, OR'
+)
+```
+
+### Workflow Steps
+
+1. **Data Collection**: Query MCP server for competitors, historical data, market trends
+2. **Document Retrieval**: Fetch full content of top relevant documents
+3. **AI Analysis**: Claude processes data and generates structured SWOT output
+4. **Response Parsing**: Convert AI response to typed TypeScript objects
+
+## API Routes
+
+### POST /api/analyze
+
+Generate complete SWOT analysis for a business idea.
+
+**Request:**
+```json
+{
+ "businessName": "Artisan Coffee Roastery",
+ "businessType": "Specialty Coffee Shop",
+ "location": "Downtown Portland, OR"
+}
+```
+
+**Response:**
+```json
+{
+ "success": true,
+ "data": {
+ "swotAnalysis": { /* Full SWOT data */ },
+ "historicalContext": { /* Historical analysis */ }
+ }
+}
+```
+
+### POST /api/mcp/search
+
+Search the MCP vector database.
+
+**Request:**
+```json
+{
+ "query": "coffee shops Portland",
+ "filters": {
+ "documentType": ["business-directory"],
+ "location": "Portland, OR"
+ },
+ "limit": 10
+}
+```
+
+### GET /api/mcp/fetch/[documentId]
+
+Retrieve a specific document by ID.
+
+## Deployment
+
+### Vercel (Recommended)
+
+1. **Install Vercel CLI**
+ ```bash
+ npm i -g vercel
+ ```
+
+2. **Deploy**
+ ```bash
+ vercel
+ ```
+
+3. **Set environment variables**
+ In the Vercel dashboard, add:
+ - `ANTHROPIC_API_KEY`
+ - `MCP_SERVER_URL`
+ - `MCP_API_KEY`
+
+4. **Enable continuous deployment**
+ Connect your GitHub repository for automatic deployments on push
+
+### Alternative: Docker
+
+```dockerfile
+FROM node:18-alpine
+WORKDIR /app
+COPY package*.json ./
+RUN npm ci
+COPY . .
+RUN npm run build
+EXPOSE 3000
+CMD ["npm", "start"]
+```
+
+Build and run:
+```bash
+docker build -t swot-platform .
+docker run -p 3000:3000 --env-file .env swot-platform
+```
+
+## Development Workflow
+
+### Using Codex for Parallel Development
+
+As outlined in the scaffolding document, you can use AI-powered development tools to build multiple UI variations:
+
+```bash
+# Generate 3 parallel versions
+codex build --parallel 3 --from-prd product-requirements.md
+```
+
+This creates three distinct implementations that you can compare and merge.
+
+### Testing with Mock Data
+
+The application includes comprehensive mock data in `src/lib/mock-data.ts` for development without an MCP server. Replace this with real API calls in production.
+
+## Customization
+
+### Adding New Visualizations
+
+1. Create component in appropriate directory (`src/components/`)
+2. Define required props using types from `src/types/swot.ts`
+3. Import and add to `src/app/page.tsx`
+
+### Extending AI Workflows
+
+Add new specialized agents in `src/lib/ai-workflows.ts`:
+
+```typescript
+export class CompetitorAnalysisWorkflow {
+ async analyzeCompetitors(businessType: string, location: string) {
+ // Custom analysis logic
+ }
+}
+```
+
+## Next Steps
+
+Based on the action plan scaffolding:
+
+1. **Buy Domain Name**: Secure `.com` and `.coffee` domains via Vercel Domains
+2. **Set Up Production MCP Server**: Deploy to Replit or AWS Lambda
+3. **Marketing Setup**: Configure Google Ads and local SEO
+4. **Keyword Research**: Analyze advertising costs for target market
+5. **A/B Testing**: Deploy multiple UI versions and track conversion
+
+## Troubleshooting
+
+### MCP Connection Issues
+
+```bash
+# Check if MCP server is running
+curl http://localhost:8000/health
+
+# Verify environment variables
+echo $MCP_SERVER_URL
+```
+
+### Build Errors
+
+```bash
+# Clear Next.js cache
+rm -rf .next
+
+# Reinstall dependencies
+rm -rf node_modules package-lock.json
+npm install
+```
+
+### TypeScript Errors
+
+```bash
+# Regenerate types
+npm run build
+```
+
+## Contributing
+
+This is a scaffolding project. To extend:
+
+1. Fork the repository
+2. Create feature branch: `git checkout -b feature/new-visualization`
+3. Commit changes: `git commit -am 'Add market sentiment analysis'`
+4. Push to branch: `git push origin feature/new-visualization`
+5. Submit pull request
+
+## License
+
+MIT License - See LICENSE file for details
+
+## Resources
+
+- [Next.js Documentation](https://nextjs.org/docs)
+- [Anthropic Claude API](https://docs.anthropic.com/)
+- [Model Context Protocol](https://modelcontextprotocol.io/)
+- [shadcn/ui Components](https://ui.shadcn.com/)
+- [Recharts Documentation](https://recharts.org/)
+
+## Support
+
+For issues, questions, or contributions:
+- Open an issue on GitHub
+- Review the architecture mind map in the application
+- Consult the MCP server documentation
+
+---
+
+Built with Claude Code and deployed on Vercel.
diff --git a/cloudflared b/cloudflared
new file mode 100755
index 0000000..9dffe91
Binary files /dev/null and b/cloudflared differ
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..7559f63
--- /dev/null
+++ b/components.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "default",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "src/app/globals.css",
+ "baseColor": "slate",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils"
+ }
+}
diff --git a/ecosystem.config.js b/ecosystem.config.js
new file mode 100644
index 0000000..6ad6445
--- /dev/null
+++ b/ecosystem.config.js
@@ -0,0 +1,29 @@
+module.exports = {
+ apps: [{
+ name: 'goodquestion',
+ script: 'npm',
+ args: 'start',
+ cwd: '/root/Projects/goodquestion-ai',
+ exec_mode: 'fork',
+ instances: 1,
+ autorestart: true,
+ watch: false,
+ max_memory_restart: '2G',
+ env: {
+ NODE_ENV: 'production',
+ PORT: 3003,
+ HOSTNAME: '0.0.0.0'
+ },
+ error_file: './logs/pm2-error.log',
+ out_file: './logs/pm2-out.log',
+ log_file: './logs/pm2-combined.log',
+ time: true,
+ restart_delay: 5000,
+ max_restarts: 999999,
+ min_uptime: '30s',
+ kill_timeout: 30000,
+ exp_backoff_restart_delay: 100,
+ listen_timeout: 120000,
+ shutdown_with_message: false
+ }]
+};
diff --git a/monitor-health.sh b/monitor-health.sh
new file mode 100755
index 0000000..a8aa5cb
--- /dev/null
+++ b/monitor-health.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+# Health check monitoring script for goodquestion
+# Monitors port 3003 and restarts PM2 if server is down or unresponsive
+
+LOG_FILE="/root/WebsitesMisc/goodquestion/logs/health-monitor.log"
+MAX_HANG_TIME=600 # 10 minutes in seconds
+PORT=3003
+APP_NAME="goodquestion"
+
+log_message() {
+ echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
+}
+
+check_port() {
+ lsof -i :$PORT -sTCP:LISTEN >/dev/null 2>&1
+ return $?
+}
+
+check_pm2_running() {
+ pm2 describe $APP_NAME >/dev/null 2>&1
+ return $?
+}
+
+restart_server() {
+ log_message "CRITICAL: Restarting server on port $PORT"
+ pm2 restart $APP_NAME
+ sleep 10
+ if check_port; then
+ log_message "SUCCESS: Server restarted and listening on port $PORT"
+ else
+ log_message "ERROR: Server restart failed, trying full restart"
+ pm2 delete $APP_NAME 2>/dev/null
+ cd /root/WebsitesMisc/goodquestion
+ pm2 start ecosystem.config.js
+ sleep 10
+ if check_port; then
+ log_message "SUCCESS: Full restart successful"
+ else
+ log_message "CRITICAL: Full restart failed!"
+ fi
+ fi
+}
+
+# Main monitoring loop
+while true; do
+ if ! check_pm2_running; then
+ log_message "WARNING: PM2 app not running, starting it"
+ cd /root/WebsitesMisc/goodquestion
+ pm2 start ecosystem.config.js
+ sleep 10
+ fi
+
+ if ! check_port; then
+ log_message "WARNING: Port $PORT not listening, restarting"
+ restart_server
+ else
+ # Check for hanging/unresponsive server
+ if timeout 5 curl -s http://localhost:$PORT >/dev/null 2>&1; then
+ # Server is responsive
+ LAST_RESPONSE_TIME=$(date +%s)
+ else
+ CURRENT_TIME=$(date +%s)
+ if [ -z "$LAST_RESPONSE_TIME" ]; then
+ LAST_RESPONSE_TIME=$CURRENT_TIME
+ fi
+ HANG_DURATION=$((CURRENT_TIME - LAST_RESPONSE_TIME))
+
+ if [ $HANG_DURATION -gt $MAX_HANG_TIME ]; then
+ log_message "WARNING: Server hung for $HANG_DURATION seconds, restarting"
+ restart_server
+ LAST_RESPONSE_TIME=$(date +%s)
+ fi
+ fi
+ fi
+
+ sleep 30
+done
diff --git a/next.config.js b/next.config.js
new file mode 100644
index 0000000..bbf7755
--- /dev/null
+++ b/next.config.js
@@ -0,0 +1,17 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ reactStrictMode: true,
+ typescript: {
+ ignoreBuildErrors: true,
+ },
+ eslint: {
+ ignoreDuringBuilds: true,
+ },
+ experimental: {
+ serverActions: {
+ bodySizeLimit: '2mb',
+ },
+ },
+}
+
+module.exports = nextConfig
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..181f2ec
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,7931 @@
+{
+ "name": "swot-analysis-platform",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "swot-analysis-platform",
+ "version": "0.1.0",
+ "dependencies": {
+ "@anthropic-ai/sdk": "^0.32.0",
+ "@google/generative-ai": "^0.24.1",
+ "@huggingface/inference": "^4.11.1",
+ "ai": "^3.4.0",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.0",
+ "json5": "^2.2.3",
+ "lucide-react": "^0.344.0",
+ "next": "15.0.3",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "recharts": "^2.12.7",
+ "tailwind-merge": "^2.2.1",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@types/node": "^22.9.0",
+ "@types/react": "^18.3.12",
+ "@types/react-dom": "^18.3.1",
+ "autoprefixer": "^10.4.18",
+ "eslint": "^8.57.0",
+ "eslint-config-next": "15.0.3",
+ "postcss": "^8.4.35",
+ "tailwindcss": "^3.4.1",
+ "tailwindcss-animate": "^1.0.7",
+ "typescript": "^5.6.2"
+ }
+ },
+ "node_modules/@ai-sdk/provider": {
+ "version": "0.0.26",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-0.0.26.tgz",
+ "integrity": "sha512-dQkfBDs2lTYpKM8389oopPdQgIU007GQyCbuPPrV+K6MtSII3HBfE0stUIMXUb44L+LK1t6GXPP7wjSzjO6uKg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "json-schema": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@ai-sdk/provider-utils": {
+ "version": "1.0.22",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-1.0.22.tgz",
+ "integrity": "sha512-YHK2rpj++wnLVc9vPGzGFP3Pjeld2MwhKinetA0zKXOoHAT/Jit5O8kZsxcSlJPu9wvcGT1UGZEjZrtO7PfFOQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider": "0.0.26",
+ "eventsource-parser": "^1.1.2",
+ "nanoid": "^3.3.7",
+ "secure-json-parse": "^2.7.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/react": {
+ "version": "0.0.70",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-0.0.70.tgz",
+ "integrity": "sha512-GnwbtjW4/4z7MleLiW+TOZC2M29eCg1tOUpuEiYFMmFNZK8mkrqM0PFZMo6UsYeUYMWqEOOcPOU9OQVJMJh7IQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider-utils": "1.0.22",
+ "@ai-sdk/ui-utils": "0.0.50",
+ "swr": "^2.2.5",
+ "throttleit": "2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19 || ^19.0.0-rc",
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/solid": {
+ "version": "0.0.54",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/solid/-/solid-0.0.54.tgz",
+ "integrity": "sha512-96KWTVK+opdFeRubqrgaJXoNiDP89gNxFRWUp0PJOotZW816AbhUf4EnDjBjXTLjXL1n0h8tGSE9sZsRkj9wQQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider-utils": "1.0.22",
+ "@ai-sdk/ui-utils": "0.0.50"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "solid-js": "^1.7.7"
+ },
+ "peerDependenciesMeta": {
+ "solid-js": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/svelte": {
+ "version": "0.0.57",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/svelte/-/svelte-0.0.57.tgz",
+ "integrity": "sha512-SyF9ItIR9ALP9yDNAD+2/5Vl1IT6kchgyDH8xkmhysfJI6WrvJbtO1wdQ0nylvPLcsPoYu+cAlz1krU4lFHcYw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider-utils": "1.0.22",
+ "@ai-sdk/ui-utils": "0.0.50",
+ "sswr": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "svelte": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/ui-utils": {
+ "version": "0.0.50",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-0.0.50.tgz",
+ "integrity": "sha512-Z5QYJVW+5XpSaJ4jYCCAVG7zIAuKOOdikhgpksneNmKvx61ACFaf98pmOd+xnjahl0pIlc/QIe6O4yVaJ1sEaw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider": "0.0.26",
+ "@ai-sdk/provider-utils": "1.0.22",
+ "json-schema": "^0.4.0",
+ "secure-json-parse": "^2.7.0",
+ "zod-to-json-schema": "^3.23.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/vue": {
+ "version": "0.0.59",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/vue/-/vue-0.0.59.tgz",
+ "integrity": "sha512-+ofYlnqdc8c4F6tM0IKF0+7NagZRAiqBJpGDJ+6EYhDW8FHLUP/JFBgu32SjxSxC6IKFZxEnl68ZoP/Z38EMlw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider-utils": "1.0.22",
+ "@ai-sdk/ui-utils": "0.0.50",
+ "swrv": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "vue": "^3.3.4"
+ },
+ "peerDependenciesMeta": {
+ "vue": {
+ "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/@anthropic-ai/sdk": {
+ "version": "0.32.1",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.32.1.tgz",
+ "integrity": "sha512-U9JwTrDvdQ9iWuABVsMLj8nJVwAyQz6QXvgLsVhryhCEPkLsbcP/MXxm+jYcAwLoV8ESbaTTjnD4kuAFa+Hyjg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "^18.11.18",
+ "@types/node-fetch": "^2.6.4",
+ "abort-controller": "^3.0.0",
+ "agentkeepalive": "^4.2.1",
+ "form-data-encoder": "1.7.2",
+ "formdata-node": "^4.3.2",
+ "node-fetch": "^2.6.7"
+ }
+ },
+ "node_modules/@anthropic-ai/sdk/node_modules/@types/node": {
+ "version": "18.19.130",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
+ "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@anthropic-ai/sdk/node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "license": "MIT"
+ },
+ "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==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
+ "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/types": "^7.28.4"
+ },
+ "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/types": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
+ "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
+ "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.1.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
+ "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
+ "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/@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/regexpp": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@google/generative-ai": {
+ "version": "0.24.1",
+ "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz",
+ "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@huggingface/inference": {
+ "version": "4.11.1",
+ "resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-4.11.1.tgz",
+ "integrity": "sha512-otClcigc7KUQfvG5wav7oVTBEVLsdKelEMuuQGXwBdPqrsJ7WZknAGCXJcXJoO2zLw9v518jgylkQnFwEBpGvw==",
+ "license": "MIT",
+ "dependencies": {
+ "@huggingface/jinja": "^0.5.1",
+ "@huggingface/tasks": "^0.19.50"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@huggingface/jinja": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.5.1.tgz",
+ "integrity": "sha512-yUZLld4lrM9iFxHCwFQ7D1HW2MWMwSbeB7WzWqFYDWK+rEb+WldkLdAJxUPOmgICMHZLzZGVcVjFh3w/YGubng==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@huggingface/tasks": {
+ "version": "0.19.50",
+ "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.19.50.tgz",
+ "integrity": "sha512-kHrfiDsJttkuwpdp7PgFiFHaK9rj+COJTIZ+221gk9vdF4B5QySW7hQT4aOGkwwZP+4qbXGhjMNGg/bxOq+LwA==",
+ "license": "MIT"
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.3",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.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/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+ "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+ "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.0.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+ "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+ "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.0.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+ "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+ "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.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+ "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+ "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.0.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+ "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+ "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.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+ "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "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.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+ "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+ "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.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+ "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+ "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.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+ "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+ "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.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+ "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+ "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.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+ "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+ "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.0.5"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+ "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+ "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.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+ "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+ "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.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+ "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+ "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.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+ "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+ "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.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+ "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+ "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.0.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+ "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.2.0"
+ },
+ "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.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+ "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+ "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.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+ "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+ "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==",
+ "dev": true,
+ "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/@isaacs/cliui/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "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==",
+ "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==",
+ "license": "MIT",
+ "peer": true,
+ "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==",
+ "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==",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "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/@next/env": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.0.3.tgz",
+ "integrity": "sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==",
+ "license": "MIT"
+ },
+ "node_modules/@next/eslint-plugin-next": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.0.3.tgz",
+ "integrity": "sha512-3Ln/nHq2V+v8uIaxCR6YfYo7ceRgZNXfTd3yW1ukTaFbO+/I8jNakrjYWODvG9BuR2v5kgVtH/C8r0i11quOgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-glob": "3.3.1"
+ }
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.3.tgz",
+ "integrity": "sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.3.tgz",
+ "integrity": "sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.3.tgz",
+ "integrity": "sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.3.tgz",
+ "integrity": "sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.3.tgz",
+ "integrity": "sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.3.tgz",
+ "integrity": "sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.3.tgz",
+ "integrity": "sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.3.tgz",
+ "integrity": "sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==",
+ "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/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "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/@rushstack/eslint-patch": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.13.0.tgz",
+ "integrity": "sha512-2ih5qGw5SZJ+2fLZxP6Lr6Na2NTIgPRL/7Kmyuw0uIyBQnuhQ8fi8fzUTd38eIQmqp+GYLC00cI6WgtqHxBwmw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@sveltejs/acorn-typescript": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.6.tgz",
+ "integrity": "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==",
+ "license": "MIT",
+ "peer": true,
+ "peerDependencies": {
+ "acorn": "^8.9.0"
+ }
+ },
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz",
+ "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "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/diff-match-patch": {
+ "version": "1.0.36",
+ "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz",
+ "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==",
+ "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",
+ "peer": true
+ },
+ "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/node": {
+ "version": "22.18.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.10.tgz",
+ "integrity": "sha512-anNG/V/Efn/YZY4pRzbACnKxNKoBng2VTFydVu8RRs5hQjikP8CQfaeAV59VFSCzKNp90mXiVXW2QzV56rwMrg==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/node-fetch": {
+ "version": "2.6.13",
+ "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz",
+ "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "form-data": "^4.0.4"
+ }
+ },
+ "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.26",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
+ "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/prop-types": "*",
+ "csstype": "^3.0.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/@typescript-eslint/eslint-plugin": {
+ "version": "8.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
+ "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "8.46.0",
+ "@typescript-eslint/type-utils": "8.46.0",
+ "@typescript-eslint/utils": "8.46.0",
+ "@typescript-eslint/visitor-keys": "8.46.0",
+ "graphemer": "^1.4.0",
+ "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.46.0",
+ "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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz",
+ "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.46.0",
+ "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/typescript-estree": "8.46.0",
+ "@typescript-eslint/visitor-keys": "8.46.0",
+ "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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz",
+ "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.46.0",
+ "@typescript-eslint/types": "^8.46.0",
+ "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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz",
+ "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/visitor-keys": "8.46.0"
+ },
+ "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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz",
+ "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==",
+ "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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz",
+ "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/typescript-estree": "8.46.0",
+ "@typescript-eslint/utils": "8.46.0",
+ "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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz",
+ "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==",
+ "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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz",
+ "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.46.0",
+ "@typescript-eslint/tsconfig-utils": "8.46.0",
+ "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/visitor-keys": "8.46.0",
+ "debug": "^4.3.4",
+ "fast-glob": "^3.3.2",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^2.1.0"
+ },
+ "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/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/@typescript-eslint/typescript-estree/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/@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.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz",
+ "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.7.0",
+ "@typescript-eslint/scope-manager": "8.46.0",
+ "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/typescript-estree": "8.46.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/visitor-keys": {
+ "version": "8.46.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz",
+ "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.46.0",
+ "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/@typescript-eslint/visitor-keys/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/@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==",
+ "dev": true,
+ "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/@vue/compiler-core": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz",
+ "integrity": "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/parser": "^7.28.4",
+ "@vue/shared": "3.5.22",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz",
+ "integrity": "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/compiler-core": "3.5.22",
+ "@vue/shared": "3.5.22"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.22.tgz",
+ "integrity": "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/parser": "^7.28.4",
+ "@vue/compiler-core": "3.5.22",
+ "@vue/compiler-dom": "3.5.22",
+ "@vue/compiler-ssr": "3.5.22",
+ "@vue/shared": "3.5.22",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.19",
+ "postcss": "^8.5.6",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.22.tgz",
+ "integrity": "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.22",
+ "@vue/shared": "3.5.22"
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz",
+ "integrity": "sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/shared": "3.5.22"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.22.tgz",
+ "integrity": "sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/reactivity": "3.5.22",
+ "@vue/shared": "3.5.22"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.22.tgz",
+ "integrity": "sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/reactivity": "3.5.22",
+ "@vue/runtime-core": "3.5.22",
+ "@vue/shared": "3.5.22",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.22.tgz",
+ "integrity": "sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.22",
+ "@vue/shared": "3.5.22"
+ },
+ "peerDependencies": {
+ "vue": "3.5.22"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz",
+ "integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "license": "MIT",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "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/agentkeepalive": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
+ "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "humanize-ms": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/ai": {
+ "version": "3.4.33",
+ "resolved": "https://registry.npmjs.org/ai/-/ai-3.4.33.tgz",
+ "integrity": "sha512-plBlrVZKwPoRTmM8+D1sJac9Bq8eaa2jiZlHLZIWekKWI1yMWYZvCCEezY9ASPwRhULYDJB2VhKOBUUeg3S5JQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ai-sdk/provider": "0.0.26",
+ "@ai-sdk/provider-utils": "1.0.22",
+ "@ai-sdk/react": "0.0.70",
+ "@ai-sdk/solid": "0.0.54",
+ "@ai-sdk/svelte": "0.0.57",
+ "@ai-sdk/ui-utils": "0.0.50",
+ "@ai-sdk/vue": "0.0.59",
+ "@opentelemetry/api": "1.9.0",
+ "eventsource-parser": "1.1.2",
+ "json-schema": "^0.4.0",
+ "jsondiffpatch": "0.6.0",
+ "secure-json-parse": "^2.7.0",
+ "zod-to-json-schema": "^3.23.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "openai": "^4.42.0",
+ "react": "^18 || ^19 || ^19.0.0-rc",
+ "sswr": "^2.1.0",
+ "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0",
+ "zod": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "openai": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "sswr": {
+ "optional": true
+ },
+ "svelte": {
+ "optional": true
+ },
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "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": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "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/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-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "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/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/autoprefixer": {
+ "version": "10.4.21",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
+ "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
+ "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.24.4",
+ "caniuse-lite": "^1.0.30001702",
+ "fraction.js": "^4.3.7",
+ "normalize-range": "^0.1.2",
+ "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/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/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==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.8.16",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz",
+ "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==",
+ "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/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/browserslist": {
+ "version": "4.26.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz",
+ "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==",
+ "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.8.9",
+ "caniuse-lite": "^1.0.30001746",
+ "electron-to-chromium": "^1.5.227",
+ "node-releases": "^2.0.21",
+ "update-browserslist-db": "^1.1.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/busboy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+ "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "dependencies": {
+ "streamsearch": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
+ "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==",
+ "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-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.30001750",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001750.tgz",
+ "integrity": "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==",
+ "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/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/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/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/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/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "license": "MIT",
+ "optional": true,
+ "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==",
+ "devOptional": true,
+ "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==",
+ "devOptional": true,
+ "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",
+ "optional": true,
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "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/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/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "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.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "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/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/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/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/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/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "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/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "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/diff-match-patch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
+ "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==",
+ "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/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
+ "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==",
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.234",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.234.tgz",
+ "integrity": "sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.24.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
+ "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==",
+ "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==",
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-iterator-helpers": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz",
+ "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==",
+ "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-set-tostringtag": "^2.0.3",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.6",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "iterator.prototype": "^1.1.4",
+ "safe-array-concat": "^1.1.3"
+ },
+ "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==",
+ "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==",
+ "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/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": "8.57.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-next": {
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.0.3.tgz",
+ "integrity": "sha512-IGP2DdQQrgjcr4mwFPve4DrCqo7CVVez1WoYY47XwKSrYO4hC0Dlb+iJA60i0YfICOzgNADIb8r28BpQ5Zs0wg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@next/eslint-plugin-next": "15.0.3",
+ "@rushstack/eslint-patch": "^1.10.3",
+ "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+ "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+ "eslint-import-resolver-node": "^0.3.6",
+ "eslint-import-resolver-typescript": "^3.5.2",
+ "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-jsx-a11y": "^6.10.0",
+ "eslint-plugin-react": "^7.35.0",
+ "eslint-plugin-react-hooks": "^5.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
+ "typescript": ">=3.3.1"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "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/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/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": "5.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
+ "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "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/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/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": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "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/esm-env": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
+ "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.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/esrap": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.0.tgz",
+ "integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ }
+ },
+ "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-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT",
+ "peer": true
+ },
+ "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/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "license": "MIT"
+ },
+ "node_modules/eventsource-parser": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz",
+ "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "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-equals": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.3.2.tgz",
+ "integrity": "sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "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/fastq": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "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": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "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/form-data": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/form-data-encoder": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
+ "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==",
+ "license": "MIT"
+ },
+ "node_modules/formdata-node": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
+ "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
+ "license": "MIT",
+ "dependencies": {
+ "node-domexception": "1.0.0",
+ "web-streams-polyfill": "4.0.0-beta.3"
+ },
+ "engines": {
+ "node": ">= 12.20"
+ }
+ },
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "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==",
+ "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/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/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "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-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "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.12.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.12.0.tgz",
+ "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "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/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "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/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true,
+ "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==",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.0.0"
+ }
+ },
+ "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/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/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "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/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",
+ "optional": true
+ },
+ "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-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-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-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==",
+ "dev": true,
+ "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-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-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-reference": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
+ "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/estree": "^1.0.6"
+ }
+ },
+ "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==",
+ "dev": true,
+ "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/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "dev": true,
+ "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": "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/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsondiffpatch": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz",
+ "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/diff-match-patch": "^1.0.36",
+ "chalk": "^5.3.0",
+ "diff-match-patch": "^1.0.5"
+ },
+ "bin": {
+ "jsondiffpatch": "bin/jsondiffpatch.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/jsondiffpatch/node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "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/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/locate-character": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
+ "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "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/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": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/lucide-react": {
+ "version": "0.344.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.344.0.tgz",
+ "integrity": "sha512-6YyBnn91GB45VuVT96bYCOKElbJzUHqp65vX8cDcu55MQL9T969v4dhGClpljamuI/+KMO9P6w9Acq1CVQGvIQ==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.19",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
+ "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
+ "license": "MIT",
+ "peer": true,
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "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/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "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/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==",
+ "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/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": "15.0.3",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.0.3.tgz",
+ "integrity": "sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==",
+ "license": "MIT",
+ "dependencies": {
+ "@next/env": "15.0.3",
+ "@swc/counter": "0.1.3",
+ "@swc/helpers": "0.5.13",
+ "busboy": "1.6.0",
+ "caniuse-lite": "^1.0.30001579",
+ "postcss": "8.4.31",
+ "styled-jsx": "5.1.6"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "15.0.3",
+ "@next/swc-darwin-x64": "15.0.3",
+ "@next/swc-linux-arm64-gnu": "15.0.3",
+ "@next/swc-linux-arm64-musl": "15.0.3",
+ "@next/swc-linux-x64-gnu": "15.0.3",
+ "@next/swc-linux-x64-musl": "15.0.3",
+ "@next/swc-win32-arm64-msvc": "15.0.3",
+ "@next/swc-win32-x64-msvc": "15.0.3",
+ "sharp": "^0.33.5"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.1.0",
+ "@playwright/test": "^1.41.2",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-66855b96-20241106",
+ "react-dom": "^18.2.0 || 19.0.0-rc-66855b96-20241106",
+ "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/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-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "deprecated": "Use your platform's native DOMException instead",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.23",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz",
+ "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==",
+ "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/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "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==",
+ "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/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/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "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/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==",
+ "dev": true,
+ "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/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==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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/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/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/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==",
+ "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/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/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/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-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
+ "node_modules/react-smooth": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz",
+ "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-equals": "^5.0.1",
+ "prop-types": "^15.8.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.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/recharts": {
+ "version": "2.15.4",
+ "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz",
+ "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==",
+ "license": "MIT",
+ "dependencies": {
+ "clsx": "^2.0.0",
+ "eventemitter3": "^4.0.1",
+ "lodash": "^4.17.21",
+ "react-is": "^18.3.1",
+ "react-smooth": "^4.0.4",
+ "recharts-scale": "^0.4.4",
+ "tiny-invariant": "^1.3.1",
+ "victory-vendor": "^36.6.8"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/recharts-scale": {
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
+ "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
+ "license": "MIT",
+ "dependencies": {
+ "decimal.js-light": "^2.4.1"
+ }
+ },
+ "node_modules/recharts/node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "license": "MIT"
+ },
+ "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.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/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.0",
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "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": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "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/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/secure-json-parse": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
+ "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "devOptional": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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.33.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
+ "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.5",
+ "@img/sharp-darwin-x64": "0.33.5",
+ "@img/sharp-libvips-darwin-arm64": "1.0.4",
+ "@img/sharp-libvips-darwin-x64": "1.0.4",
+ "@img/sharp-libvips-linux-arm": "1.0.5",
+ "@img/sharp-libvips-linux-arm64": "1.0.4",
+ "@img/sharp-libvips-linux-s390x": "1.0.4",
+ "@img/sharp-libvips-linux-x64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
+ "@img/sharp-linux-arm": "0.33.5",
+ "@img/sharp-linux-arm64": "0.33.5",
+ "@img/sharp-linux-s390x": "0.33.5",
+ "@img/sharp-linux-x64": "0.33.5",
+ "@img/sharp-linuxmusl-arm64": "0.33.5",
+ "@img/sharp-linuxmusl-x64": "0.33.5",
+ "@img/sharp-wasm32": "0.33.5",
+ "@img/sharp-win32-ia32": "0.33.5",
+ "@img/sharp-win32-x64": "0.33.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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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",
+ "optional": true,
+ "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/sswr": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/sswr/-/sswr-2.2.0.tgz",
+ "integrity": "sha512-clTszLPZkmycALTHD1mXGU+mOtA/MIoLgS1KGTTzFNVm9rytQVykgRaP+z1zl572cz0bTqj4rFVoC2N+IGK4Sg==",
+ "license": "MIT",
+ "dependencies": {
+ "swrev": "^4.0.0"
+ },
+ "peerDependencies": {
+ "svelte": "^4.0.0 || ^5.0.0"
+ }
+ },
+ "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/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/streamsearch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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/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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/string-width/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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "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/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "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/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/sucrase": {
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "^10.3.10",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/sucrase/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/sucrase/node_modules/glob": {
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "dev": true,
+ "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/sucrase/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/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/svelte": {
+ "version": "5.39.11",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.39.11.tgz",
+ "integrity": "sha512-8MxWVm2+3YwrFbPaxOlT1bbMi6OTenrAgks6soZfiaS8Fptk4EVyRIFhJc3RpO264EeSNwgjWAdki0ufg4zkGw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.4",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@sveltejs/acorn-typescript": "^1.0.5",
+ "@types/estree": "^1.0.5",
+ "acorn": "^8.12.1",
+ "aria-query": "^5.3.1",
+ "axobject-query": "^4.1.0",
+ "clsx": "^2.1.1",
+ "esm-env": "^1.2.1",
+ "esrap": "^2.1.0",
+ "is-reference": "^3.0.3",
+ "locate-character": "^3.0.0",
+ "magic-string": "^0.30.11",
+ "zimmerframe": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/swr": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz",
+ "integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==",
+ "license": "MIT",
+ "dependencies": {
+ "dequal": "^2.0.3",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/swrev": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/swrev/-/swrev-4.0.0.tgz",
+ "integrity": "sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA==",
+ "license": "MIT"
+ },
+ "node_modules/swrv": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/swrv/-/swrv-1.1.0.tgz",
+ "integrity": "sha512-pjllRDr2s0iTwiE5Isvip51dZGR7GjLH1gCSVyE8bQnbAx6xackXsFdojau+1O5u98yHF5V73HQGOFxKUXO9gQ==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "vue": ">=3.2.26 < 4"
+ }
+ },
+ "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/tailwindcss": {
+ "version": "3.4.18",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
+ "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
+ "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/tailwindcss-animate": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
+ "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || insiders"
+ }
+ },
+ "node_modules/tailwindcss/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/tailwindcss/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/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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/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-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/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/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
+ "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/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/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/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": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "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/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/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/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.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "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-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/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/victory-vendor": {
+ "version": "36.9.2",
+ "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
+ "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==",
+ "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/vue": {
+ "version": "3.5.22",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
+ "integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.22",
+ "@vue/compiler-sfc": "3.5.22",
+ "@vue/runtime-dom": "3.5.22",
+ "@vue/server-renderer": "3.5.22",
+ "@vue/shared": "3.5.22"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/web-streams-polyfill": {
+ "version": "4.0.0-beta.3",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
+ "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "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-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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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/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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "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/zimmerframe": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
+ "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/zod": {
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-to-json-schema": {
+ "version": "3.24.6",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz",
+ "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==",
+ "license": "ISC",
+ "peerDependencies": {
+ "zod": "^3.24.1"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8fb362d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "swot-analysis-platform",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev -p 3003 -H 0.0.0.0",
+ "build": "next build",
+ "start": "next start -p 3003 -H 0.0.0.0",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "@anthropic-ai/sdk": "^0.32.0",
+ "@google/generative-ai": "^0.24.1",
+ "@huggingface/inference": "^4.11.1",
+ "ai": "^3.4.0",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.0",
+ "json5": "^2.2.3",
+ "lucide-react": "^0.344.0",
+ "next": "15.0.3",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "recharts": "^2.12.7",
+ "tailwind-merge": "^2.2.1",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@types/node": "^22.9.0",
+ "@types/react": "^18.3.12",
+ "@types/react-dom": "^18.3.1",
+ "autoprefixer": "^10.4.18",
+ "eslint": "^8.57.0",
+ "eslint-config-next": "15.0.3",
+ "postcss": "^8.4.35",
+ "tailwindcss": "^3.4.1",
+ "tailwindcss-animate": "^1.0.7",
+ "typescript": "^5.6.2"
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..33ad091
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/src/app/api/analyze/route.ts b/src/app/api/analyze/route.ts
new file mode 100644
index 0000000..9845ec6
--- /dev/null
+++ b/src/app/api/analyze/route.ts
@@ -0,0 +1,67 @@
+import { NextRequest, NextResponse } from 'next/server'
+import {
+ swotWorkflow,
+ historicalWorkflow,
+ startupCostsWorkflow,
+ marketAnalysisWorkflow,
+ actionPlanWorkflow
+} from '@/lib/ai-workflows'
+import { z } from 'zod'
+
+// Request validation schema
+const AnalysisRequestSchema = z.object({
+ businessName: z.string().min(1),
+ businessType: z.string().min(1),
+ location: z.string().min(1),
+ radiusMiles: z.number().min(1).max(100).optional().default(10),
+})
+
+export async function POST(request: NextRequest) {
+ try {
+ // Parse and validate request body
+ const body = await request.json()
+ const validatedData = AnalysisRequestSchema.parse(body)
+
+ // OPTIMIZATION: Only generate SWOT analysis by default
+ // Other sections will be loaded on-demand
+ const swotAnalysis = await swotWorkflow.generateAnalysis(
+ validatedData.businessName,
+ validatedData.businessType,
+ validatedData.location
+ )
+
+ return NextResponse.json({
+ success: true,
+ data: {
+ swotAnalysis,
+ // Other sections will be loaded via separate API calls
+ historicalContext: null,
+ startupCosts: null,
+ marketAnalysis: null,
+ actionPlan: null,
+ },
+ })
+ } catch (error) {
+ console.error('Analysis generation error:', error)
+
+ if (error instanceof z.ZodError) {
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Invalid request data',
+ details: error.errors,
+ },
+ { status: 400 }
+ )
+ }
+
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Failed to generate analysis',
+ message: error instanceof Error ? error.message : 'Unknown error',
+ },
+ { status: 500 }
+ )
+ }
+}
diff --git a/src/app/api/mcp/fetch/[documentId]/route.ts b/src/app/api/mcp/fetch/[documentId]/route.ts
new file mode 100644
index 0000000..3b2ab69
--- /dev/null
+++ b/src/app/api/mcp/fetch/[documentId]/route.ts
@@ -0,0 +1,39 @@
+import { NextRequest, NextResponse } from 'next/server'
+import { mcpClient } from '@/lib/mcp-client'
+
+export async function GET(
+ request: NextRequest,
+ { params }: { params: Promise<{ documentId: string }> }
+) {
+ try {
+ const { documentId } = await params
+
+ if (!documentId) {
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Document ID is required',
+ },
+ { status: 400 }
+ )
+ }
+
+ const document = await mcpClient.fetch(documentId)
+
+ return NextResponse.json({
+ success: true,
+ document,
+ })
+ } catch (error) {
+ console.error('MCP fetch error:', error)
+
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Failed to fetch document',
+ message: error instanceof Error ? error.message : 'Unknown error',
+ },
+ { status: 500 }
+ )
+ }
+}
diff --git a/src/app/api/mcp/search/route.ts b/src/app/api/mcp/search/route.ts
new file mode 100644
index 0000000..5d0b011
--- /dev/null
+++ b/src/app/api/mcp/search/route.ts
@@ -0,0 +1,53 @@
+import { NextRequest, NextResponse } from 'next/server'
+import { mcpClient } from '@/lib/mcp-client'
+import { z } from 'zod'
+
+const SearchRequestSchema = z.object({
+ query: z.string().min(1),
+ filters: z
+ .object({
+ documentType: z.array(z.string()).optional(),
+ dateFrom: z.string().optional(),
+ dateTo: z.string().optional(),
+ location: z.string().optional(),
+ })
+ .optional(),
+ limit: z.number().int().positive().max(50).default(10),
+})
+
+export async function POST(request: NextRequest) {
+ try {
+ const body = await request.json()
+ const { query, filters, limit } = SearchRequestSchema.parse(body)
+
+ const results = await mcpClient.search(query, filters, limit)
+
+ return NextResponse.json({
+ success: true,
+ results,
+ count: results.length,
+ })
+ } catch (error) {
+ console.error('MCP search error:', error)
+
+ if (error instanceof z.ZodError) {
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Invalid search parameters',
+ details: error.errors,
+ },
+ { status: 400 }
+ )
+ }
+
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Search failed',
+ message: error instanceof Error ? error.message : 'Unknown error',
+ },
+ { status: 500 }
+ )
+ }
+}
diff --git a/src/app/api/opportunities/route.ts b/src/app/api/opportunities/route.ts
new file mode 100644
index 0000000..c13ab24
--- /dev/null
+++ b/src/app/api/opportunities/route.ts
@@ -0,0 +1,147 @@
+import { NextRequest, NextResponse } from 'next/server'
+import { aiProvider } from '@/lib/ai-provider-multi'
+import { z } from 'zod'
+import JSON5 from 'json5'
+
+const OpportunitiesRequestSchema = z.object({
+ location: z.string().min(1),
+ capitalOnHand: z.number().optional(),
+})
+
+interface BusinessOpportunity {
+ id: string
+ businessType: string
+ description: string
+ viabilityScore: number
+ reasoning: string
+ estimatedStartupCost: number
+ estimatedMonthlyRevenue: number
+ keyStrengths: string[]
+ demandLevel: 'high' | 'medium' | 'low'
+ competitionLevel: 'high' | 'medium' | 'low'
+ timeToProfit: string
+}
+
+export async function POST(request: NextRequest) {
+ try {
+ const body = await request.json()
+ const validatedData = OpportunitiesRequestSchema.parse(body)
+
+ const prompt = `You are a business analyst with deep knowledge of ${validatedData.location}'s market, demographics, and economic conditions.
+
+CRITICAL: Use REAL market data and realistic financial projections based on ${validatedData.location}'s:
+- Actual median household income
+- Real estate costs and commercial rent rates
+- Local consumer spending patterns
+- Current market saturation levels
+- Existing competition analysis
+- Actual wage rates for employees
+- Real utility and operational costs
+
+${validatedData.capitalOnHand ? `CAPITAL CONSTRAINT: The entrepreneur has ONLY $${validatedData.capitalOnHand.toLocaleString()} available. ALL suggestions must be REALISTICALLY achievable with this budget.` : 'Include businesses across different capital requirements from $5K to $500K.'}
+
+Provide TOP 5 VIABLE business opportunities with BRUTALLY HONEST assessments:
+
+REQUIREMENTS:
+1. Use REAL startup costs (equipment, inventory, deposits, permits, insurance, initial marketing)
+2. Use REALISTIC monthly revenue (based on actual local market capacity, not wishful thinking)
+3. Account for REAL operating expenses (rent, utilities, payroll, insurance, supplies)
+4. Consider ACTUAL competition levels in ${validatedData.location}
+5. Factor in LOCAL demand and market saturation
+6. Include realistic time to profitability (most businesses take 12-24 months)
+7. Viability scores should reflect REAL success rates (most businesses fail, be honest)
+
+Return ONLY a JSON object:
+{
+ "opportunities": [
+ {
+ "businessType": "Mobile Car Detailing Service",
+ "description": "High-end mobile detailing for luxury car owners",
+ "viabilityScore": 85,
+ "reasoning": "Low barriers to entry, proven demand from 47% luxury vehicle ownership rate, minimal competition in suburbs",
+ "estimatedStartupCost": 12000,
+ "estimatedMonthlyRevenue": 8500,
+ "keyStrengths": ["Low overhead", "Flexible scheduling", "Recurring customers"],
+ "demandLevel": "high",
+ "competitionLevel": "low",
+ "timeToProfit": "4-6 months"
+ }
+ ]
+}
+
+CRITICAL RULES:
+- Viability scores: 70-95 (be realistic, few businesses are 95%+ viable)
+- Startup costs: Based on ACTUAL market prices in ${validatedData.location}
+- Monthly revenue: Conservative estimates based on LOCAL market capacity
+- Time to profit: Realistic (most take 6-18 months, some 2+ years)
+- Competition: Based on actual market conditions
+- NO overly optimistic projections
+- Sort by viability score (highest first)
+- Return ONLY the JSON, no markdown`
+
+ const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 3000,
+ temperature: 0.7,
+ })
+
+ console.log(`[Opportunities] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
+ console.log(`[Opportunities] Response length: ${response.content.length} chars`)
+
+ // Extract and parse JSON
+ const jsonMatch = response.content.match(/\{[\s\S]*\}/)
+ if (!jsonMatch) {
+ console.error('[Opportunities] No JSON found in response:', response.content.substring(0, 500))
+ throw new Error('No valid JSON found in response')
+ }
+
+ let parsed
+ try {
+ parsed = JSON5.parse(jsonMatch[0])
+ } catch (parseError) {
+ console.error('[Opportunities] JSON parse failed. Response:', jsonMatch[0].substring(0, 1000))
+ throw new Error('Failed to parse AI response as JSON')
+ }
+
+ // Add IDs to opportunities
+ const opportunities: BusinessOpportunity[] = (parsed.opportunities || []).map((opp: any, index: number) => ({
+ ...opp,
+ id: `opp-${Date.now()}-${index}`,
+ }))
+
+ // Ensure we have at least some opportunities
+ if (opportunities.length === 0) {
+ throw new Error('No opportunities generated')
+ }
+
+ return NextResponse.json({
+ success: true,
+ data: {
+ location: validatedData.location,
+ opportunities,
+ generatedAt: new Date().toISOString(),
+ },
+ })
+ } catch (error) {
+ console.error('Opportunities generation error:', error)
+
+ if (error instanceof z.ZodError) {
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Invalid request data',
+ details: error.errors,
+ },
+ { status: 400 }
+ )
+ }
+
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Failed to generate opportunities',
+ message: error instanceof Error ? error.message : 'Unknown error',
+ },
+ { status: 500 }
+ )
+ }
+}
diff --git a/src/app/api/sections/route.ts b/src/app/api/sections/route.ts
new file mode 100644
index 0000000..fc01cff
--- /dev/null
+++ b/src/app/api/sections/route.ts
@@ -0,0 +1,84 @@
+import { NextRequest, NextResponse } from 'next/server'
+import {
+ historicalWorkflow,
+ startupCostsWorkflow,
+ marketAnalysisWorkflow,
+ actionPlanWorkflow
+} from '@/lib/ai-workflows'
+import { z } from 'zod'
+
+const SectionRequestSchema = z.object({
+ section: z.enum(['historical', 'startup', 'market', 'action']),
+ businessType: z.string().min(1),
+ location: z.string().min(1),
+ radiusMiles: z.number().optional().default(10),
+})
+
+export async function POST(request: NextRequest) {
+ try {
+ const body = await request.json()
+ const validatedData = SectionRequestSchema.parse(body)
+
+ let result
+
+ switch (validatedData.section) {
+ case 'historical':
+ result = await historicalWorkflow.generateHistoricalContext(
+ validatedData.location
+ )
+ break
+
+ case 'startup':
+ result = await startupCostsWorkflow.generateStartupCosts(
+ validatedData.businessType,
+ validatedData.location
+ )
+ break
+
+ case 'market':
+ result = await marketAnalysisWorkflow.generateMarketAnalysis(
+ validatedData.businessType,
+ validatedData.location,
+ validatedData.radiusMiles
+ )
+ break
+
+ case 'action':
+ result = await actionPlanWorkflow.generateActionPlan(
+ validatedData.businessType,
+ validatedData.location
+ )
+ break
+
+ default:
+ throw new Error('Invalid section')
+ }
+
+ return NextResponse.json({
+ success: true,
+ data: result,
+ })
+ } catch (error) {
+ console.error(`Section generation error:`, error)
+
+ if (error instanceof z.ZodError) {
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Invalid request data',
+ details: error.errors,
+ },
+ { status: 400 }
+ )
+ }
+
+ return NextResponse.json(
+ {
+ success: false,
+ error: 'Failed to generate section',
+ message: error instanceof Error ? error.message : 'Unknown error',
+ },
+ { status: 500 }
+ )
+ }
+}
diff --git a/src/app/globals.css b/src/app/globals.css
new file mode 100644
index 0000000..00b08e3
--- /dev/null
+++ b/src/app/globals.css
@@ -0,0 +1,59 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 222.2 84% 4.9%;
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 84% 4.9%;
+ --popover: 0 0% 100%;
+ --popover-foreground: 222.2 84% 4.9%;
+ --primary: 221.2 83.2% 53.3%;
+ --primary-foreground: 210 40% 98%;
+ --secondary: 210 40% 96.1%;
+ --secondary-foreground: 222.2 47.4% 11.2%;
+ --muted: 210 40% 96.1%;
+ --muted-foreground: 215.4 16.3% 46.9%;
+ --accent: 210 40% 96.1%;
+ --accent-foreground: 222.2 47.4% 11.2%;
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 210 40% 98%;
+ --border: 214.3 31.8% 91.4%;
+ --input: 214.3 31.8% 91.4%;
+ --ring: 221.2 83.2% 53.3%;
+ --radius: 0.5rem;
+ }
+
+ .dark {
+ --background: 222.2 84% 4.9%;
+ --foreground: 210 40% 98%;
+ --card: 222.2 84% 4.9%;
+ --card-foreground: 210 40% 98%;
+ --popover: 222.2 84% 4.9%;
+ --popover-foreground: 210 40% 98%;
+ --primary: 217.2 91.2% 59.8%;
+ --primary-foreground: 222.2 47.4% 11.2%;
+ --secondary: 217.2 32.6% 17.5%;
+ --secondary-foreground: 210 40% 98%;
+ --muted: 217.2 32.6% 17.5%;
+ --muted-foreground: 215 20.2% 65.1%;
+ --accent: 217.2 32.6% 17.5%;
+ --accent-foreground: 210 40% 98%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 210 40% 98%;
+ --border: 217.2 32.6% 17.5%;
+ --input: 217.2 32.6% 17.5%;
+ --ring: 224.3 76.3% 48%;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
new file mode 100644
index 0000000..f5d0936
--- /dev/null
+++ b/src/app/layout.tsx
@@ -0,0 +1,19 @@
+import type { Metadata } from "next"
+import "./globals.css"
+
+export const metadata: Metadata = {
+ title: "SWOT Analysis Platform - Local Business Viability",
+ description: "AI-powered SWOT analysis platform for evaluating local business opportunities",
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+ <html lang="en">
+ <body className="font-sans">{children}</body>
+ </html>
+ )
+}
diff --git a/src/app/page.tsx b/src/app/page.tsx
new file mode 100644
index 0000000..1e4e10c
--- /dev/null
+++ b/src/app/page.tsx
@@ -0,0 +1,490 @@
+'use client'
+
+import { useState } from 'react'
+import { Search } from 'lucide-react'
+import { ScoreCard } from '@/components/swot/ScoreCard'
+import { SWOTChart } from '@/components/swot/SWOTChart'
+import { HistoricalContext } from '@/components/historical/HistoricalContext'
+import { CompetitorMap } from '@/components/market/CompetitorMap'
+import { MarketSizeChart } from '@/components/market/MarketSizeChart'
+import { IncomeProjections } from '@/components/market/IncomeProjections'
+import { MindMap } from '@/components/mindmap/MindMap'
+import { ActionPlan } from '@/components/action-plan/ActionPlan'
+import { SearchForm, SearchFormData } from '@/components/search/SearchForm'
+import { StartupCapitalBreakdown } from '@/components/financial/StartupCapitalBreakdown'
+import { LoadingTicker } from '@/components/LoadingTicker'
+
+// Mock data for demonstration - replace with actual API calls
+import { mockSWOTData, mockSaaSSWOTData } from '@/lib/mock-data'
+
+export default function Home() {
+ const [selectedExample, setSelectedExample] = useState<'coffee' | 'saas'>('coffee')
+ const [analysisData, setAnalysisData] = useState(mockSWOTData)
+ const [isAnalyzing, setIsAnalyzing] = useState(false)
+ const [isComplete, setIsComplete] = useState(false)
+ const [hasSearched, setHasSearched] = useState(false)
+ const [opportunities, setOpportunities] = useState<any[]>([])
+ const [showOpportunities, setShowOpportunities] = useState(false)
+
+ // Section loading states
+ const [loadingSections, setLoadingSections] = useState<Record<string, boolean>>({})
+ const [loadedSections, setLoadedSections] = useState<Record<string, boolean>>({})
+ const [currentSearchData, setCurrentSearchData] = useState<SearchFormData | null>(null)
+
+ const handleExampleSwitch = (example: 'coffee' | 'saas') => {
+ setSelectedExample(example)
+ setAnalysisData(example === 'coffee' ? mockSWOTData : mockSaaSSWOTData)
+ setHasSearched(true)
+ setLoadedSections({})
+ }
+
+ const loadSection = async (section: 'historical' | 'startup' | 'market' | 'action') => {
+ if (!currentSearchData) return
+
+ setLoadingSections(prev => ({ ...prev, [section]: true }))
+
+ try {
+ const response = await fetch('/api/sections', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ section,
+ businessType: currentSearchData.businessType,
+ location: currentSearchData.location,
+ radiusMiles: currentSearchData.radiusMiles,
+ }),
+ })
+
+ if (!response.ok) {
+ throw new Error(`Failed to load ${section} section`)
+ }
+
+ const result = await response.json()
+
+ if (result.success && result.data) {
+ setAnalysisData(prev => ({
+ ...prev,
+ [section === 'historical' ? 'historicalContext' :
+ section === 'startup' ? 'startupCosts' :
+ section === 'market' ? 'marketAnalysis' : 'actionPlan']: result.data
+ }))
+ setLoadedSections(prev => ({ ...prev, [section]: true }))
+ }
+ } catch (error) {
+ console.error(`Error loading ${section}:`, error)
+ alert(`Failed to load ${section} section`)
+ } finally {
+ setLoadingSections(prev => ({ ...prev, [section]: false }))
+ }
+ }
+
+ const handleSearch = async (searchData: SearchFormData) => {
+ setIsAnalyzing(true)
+ setIsComplete(false)
+ setShowOpportunities(false)
+ setCurrentSearchData(searchData)
+ setLoadedSections({}) // Reset loaded sections
+
+ try {
+ // If searchMode is opportunities, call opportunities API
+ if (searchData.searchMode === 'opportunities') {
+ const response = await fetch('/api/opportunities', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ location: searchData.location,
+ capitalOnHand: searchData.capitalOnHand,
+ }),
+ })
+
+ if (!response.ok) {
+ throw new Error(`API error: ${response.statusText}`)
+ }
+
+ const result = await response.json()
+
+ if (result.success && result.data) {
+ setOpportunities(result.data.opportunities || [])
+ setShowOpportunities(true)
+ setIsComplete(true)
+ setHasSearched(false) // Don't show SWOT analysis
+
+ setTimeout(() => {
+ setIsAnalyzing(false)
+ setIsComplete(false)
+ }, 1500)
+ } else {
+ throw new Error(result.error || 'Failed to generate opportunities')
+ }
+ return
+ }
+
+ // Call the API to generate analysis
+ const response = await fetch('/api/analyze', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ businessName: `${searchData.businessType} in ${searchData.location}`,
+ businessType: searchData.businessType,
+ location: searchData.location,
+ radiusMiles: searchData.radiusMiles,
+ }),
+ })
+
+ if (!response.ok) {
+ throw new Error(`API error: ${response.statusText}`)
+ }
+
+ const result = await response.json()
+
+ if (result.success && result.data) {
+ // Use real API data for all sections
+ setAnalysisData({
+ swotAnalysis: result.data.swotAnalysis || mockSWOTData.swotAnalysis,
+ historicalContext: result.data.historicalContext || mockSWOTData.historicalContext,
+ startupCosts: result.data.startupCosts || mockSWOTData.startupCosts,
+ marketAnalysis: result.data.marketAnalysis || mockSWOTData.marketAnalysis,
+ actionPlan: result.data.actionPlan || mockSWOTData.actionPlan,
+ })
+ } else {
+ throw new Error(result.error || 'Analysis failed')
+ }
+
+ // Show completion state with green checkmark
+ setIsComplete(true)
+ setHasSearched(true)
+ setShowOpportunities(false)
+
+ // Hide loader after showing success for 1.5 seconds
+ setTimeout(() => {
+ setIsAnalyzing(false)
+ setIsComplete(false)
+ }, 1500)
+ } catch (error) {
+ console.error('Analysis error:', error)
+ alert(`Failed to generate analysis: ${error instanceof Error ? error.message : 'Unknown error'}`)
+ setIsAnalyzing(false)
+ setIsComplete(false)
+ }
+ }
+
+ const { swotAnalysis, historicalContext, marketAnalysis, startupCosts, actionPlan } = analysisData
+
+ return (
+ <div>
+ {/* Loading Ticker Overlay */}
+ {isAnalyzing && <LoadingTicker isComplete={isComplete} />}
+
+ <main className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100">
+ {/* Header */}
+ <header className="bg-white shadow-sm border-b">
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
+ <h1 className="text-4xl font-bold text-gray-900">
+ SWOT Analysis Platform
+ </h1>
+ <p className="mt-2 text-lg text-gray-600">
+ AI-Powered Local Business Viability Analysis
+ </p>
+ </div>
+ </header>
+
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
+ {/* Example Selector */}
+ <section className="mb-8">
+ <div className="bg-white rounded-xl shadow-md p-6 border-2 border-gray-200">
+ <h3 className="text-lg font-semibold text-gray-900 mb-3">View Example SWOT Analysis:</h3>
+ <div className="flex gap-4">
+ <button
+ onClick={() => handleExampleSwitch('coffee')}
+ className={`flex-1 py-3 px-6 rounded-lg font-semibold transition-all duration-200 ${
+ selectedExample === 'coffee'
+ ? 'bg-gradient-to-r from-amber-600 to-orange-600 text-white shadow-lg'
+ : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
+ }`}
+ >
+ Coffee Shop Example
+ </button>
+ <button
+ onClick={() => handleExampleSwitch('saas')}
+ className={`flex-1 py-3 px-6 rounded-lg font-semibold transition-all duration-200 ${
+ selectedExample === 'saas'
+ ? 'bg-gradient-to-r from-blue-600 to-indigo-600 text-white shadow-lg'
+ : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
+ }`}
+ >
+ SaaS Application Example
+ </button>
+ </div>
+ </div>
+ </section>
+
+ {/* Search Form Section - Always visible */}
+ <section className="mb-12">
+ <SearchForm onSearch={handleSearch} isLoading={isAnalyzing} />
+ </section>
+
+ {/* Business Opportunities List */}
+ {showOpportunities && opportunities.length > 0 && (
+ <section className="mb-12">
+ <div className="bg-gradient-to-r from-green-600 to-emerald-600 text-white rounded-xl p-8 mb-6">
+ <h2 className="text-3xl font-bold mb-2">Top Business Opportunities</h2>
+ <p className="text-green-100">Realistic opportunities based on local market data and actual startup costs</p>
+ </div>
+
+ <div className="grid gap-6">
+ {opportunities.map((opp, index) => (
+ <div
+ key={opp.id}
+ className="bg-white rounded-xl shadow-lg p-6 border-2 border-gray-200 hover:border-green-500 transition-all duration-200"
+ >
+ <div className="flex items-start gap-4">
+ <div className="flex-shrink-0">
+ <div className="w-16 h-16 bg-gradient-to-br from-green-500 to-emerald-500 rounded-full flex items-center justify-center text-white font-bold text-2xl">
+ #{index + 1}
+ </div>
+ </div>
+
+ <div className="flex-1">
+ <div className="flex items-start justify-between mb-3">
+ <div>
+ <h3 className="text-2xl font-bold text-gray-900 mb-1">{opp.businessType}</h3>
+ <p className="text-gray-600">{opp.description}</p>
+ </div>
+ <div className="ml-4 text-right">
+ <div className="inline-block bg-green-100 text-green-800 px-4 py-2 rounded-lg font-bold text-lg">
+ {opp.viabilityScore}%
+ </div>
+ <p className="text-xs text-gray-500 mt-1">Viability</p>
+ </div>
+ </div>
+
+ <div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4">
+ <p className="text-sm text-blue-900"><strong>Why it works:</strong> {opp.reasoning}</p>
+ </div>
+
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
+ <div className="bg-gray-50 rounded-lg p-3">
+ <p className="text-xs text-gray-600 mb-1">Startup Cost</p>
+ <p className="font-bold text-gray-900">${(opp.estimatedStartupCost || 0).toLocaleString()}</p>
+ </div>
+ <div className="bg-gray-50 rounded-lg p-3">
+ <p className="text-xs text-gray-600 mb-1">Monthly Revenue</p>
+ <p className="font-bold text-green-700">${(opp.estimatedMonthlyRevenue || 0).toLocaleString()}/mo</p>
+ </div>
+ <div className="bg-gray-50 rounded-lg p-3">
+ <p className="text-xs text-gray-600 mb-1">Competition</p>
+ <p className={`font-bold ${opp.competitionLevel === 'low' ? 'text-green-600' : opp.competitionLevel === 'medium' ? 'text-yellow-600' : 'text-red-600'}`}>
+ {opp.competitionLevel || 'Medium'}
+ </p>
+ </div>
+ <div className="bg-gray-50 rounded-lg p-3">
+ <p className="text-xs text-gray-600 mb-1">Time to Profit</p>
+ <p className="font-bold text-gray-900">{opp.timeToProfit || 'N/A'}</p>
+ </div>
+ </div>
+
+ <div className="flex flex-wrap gap-2">
+ {(opp.keyStrengths || []).map((strength: string, idx: number) => (
+ <span key={idx} className="inline-block bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm font-medium">
+ ✓ {strength}
+ </span>
+ ))}
+ </div>
+
+ <div className="mt-4 pt-4 border-t border-gray-200">
+ <button
+ onClick={() => {
+ handleSearch({
+ location: opportunities[0]?.location || '',
+ businessType: opp.businessType,
+ radiusMiles: 10,
+ searchMode: 'single',
+ })
+ }}
+ className="w-full bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 flex items-center justify-center gap-2"
+ >
+ <Search className="h-5 w-5" />
+ Analyze This Opportunity
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </section>
+ )}
+
+ {/* Analysis Results */}
+ {hasSearched && (
+ <>
+ {/* The Good Question Section */}
+ <section className="mb-12">
+ <ScoreCard analysis={swotAnalysis} />
+ </section>
+
+ {/* Full SWOT Analysis */}
+ <section className="mb-12">
+ <h2 className="text-3xl font-bold mb-6">Detailed SWOT Analysis</h2>
+ <SWOTChart
+ strengths={swotAnalysis.strengths}
+ weaknesses={swotAnalysis.weaknesses}
+ opportunities={swotAnalysis.opportunities}
+ threats={swotAnalysis.threats}
+ />
+ </section>
+
+ {/* Historical Context */}
+ <section className="mb-12">
+ <div className="flex items-center justify-between mb-6">
+ <h2 className="text-3xl font-bold">Historical & Trajectory Context</h2>
+ {!loadedSections.historical && !loadingSections.historical && (
+ <button
+ onClick={() => loadSection('historical')}
+ className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
+ >
+ Load Details
+ </button>
+ )}
+ </div>
+ {loadingSections.historical && (
+ <div className="bg-white rounded-xl shadow-lg p-8 text-center">
+ <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
+ <p className="text-gray-600">Loading historical context...</p>
+ </div>
+ )}
+ {loadedSections.historical && historicalContext && (
+ <HistoricalContext context={historicalContext} />
+ )}
+ {!loadedSections.historical && !loadingSections.historical && (
+ <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
+ <p className="text-gray-600 text-center">Click "Load Details" to view historical context and market trajectory</p>
+ </div>
+ )}
+ </section>
+
+ {/* Startup Capital Breakdown */}
+ <section className="mb-12">
+ <div className="flex items-center justify-between mb-6">
+ <h2 className="text-3xl font-bold">Startup Capital Required</h2>
+ {!loadedSections.startup && !loadingSections.startup && (
+ <button
+ onClick={() => loadSection('startup')}
+ className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
+ >
+ Load Details
+ </button>
+ )}
+ </div>
+ {loadingSections.startup && (
+ <div className="bg-white rounded-xl shadow-lg p-8 text-center">
+ <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
+ <p className="text-gray-600">Loading startup costs...</p>
+ </div>
+ )}
+ {loadedSections.startup && startupCosts && (
+ <StartupCapitalBreakdown startupCosts={startupCosts} />
+ )}
+ {!loadedSections.startup && !loadingSections.startup && (
+ <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
+ <p className="text-gray-600 text-center">Click "Load Details" to view detailed startup cost breakdown</p>
+ </div>
+ )}
+ </section>
+
+ {/* Market Analysis */}
+ <section className="mb-12">
+ <div className="flex items-center justify-between mb-6">
+ <h2 className="text-3xl font-bold">Market Deep Dive</h2>
+ {!loadedSections.market && !loadingSections.market && (
+ <button
+ onClick={() => loadSection('market')}
+ className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
+ >
+ Load Details
+ </button>
+ )}
+ </div>
+ {loadingSections.market && (
+ <div className="bg-white rounded-xl shadow-lg p-8 text-center">
+ <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
+ <p className="text-gray-600">Loading market analysis...</p>
+ </div>
+ )}
+ {loadedSections.market && marketAnalysis && (
+ <div className="space-y-6">
+ <CompetitorMap
+ competitors={marketAnalysis.competitors}
+ businessType={swotAnalysis.businessType}
+ />
+ <MarketSizeChart
+ marketSize={marketAnalysis.marketSize}
+ demographics={marketAnalysis.demographics}
+ />
+ <IncomeProjections projections={marketAnalysis.incomeProjections} />
+ </div>
+ )}
+ {!loadedSections.market && !loadingSections.market && (
+ <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
+ <p className="text-gray-600 text-center">Click "Load Details" to view competitor analysis, market size, and income projections</p>
+ </div>
+ )}
+ </section>
+
+ {/* Mind Map */}
+ <section className="mb-12">
+ <h2 className="text-3xl font-bold mb-6">System Architecture</h2>
+ <MindMap />
+ </section>
+
+ {/* Action Plan */}
+ <section className="mb-12">
+ <div className="flex items-center justify-between mb-6">
+ <h2 className="text-3xl font-bold">Implementation Roadmap</h2>
+ {!loadedSections.action && !loadingSections.action && (
+ <button
+ onClick={() => loadSection('action')}
+ className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
+ >
+ Load Details
+ </button>
+ )}
+ </div>
+ {loadingSections.action && (
+ <div className="bg-white rounded-xl shadow-lg p-8 text-center">
+ <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
+ <p className="text-gray-600">Loading action plan...</p>
+ </div>
+ )}
+ {loadedSections.action && actionPlan && (
+ <ActionPlan actionItems={actionPlan} />
+ )}
+ {!loadedSections.action && !loadingSections.action && (
+ <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
+ <p className="text-gray-600 text-center">Click "Load Details" to view detailed implementation roadmap</p>
+ </div>
+ )}
+ </section>
+ </>
+ )}
+ </div>
+
+ {/* Footer */}
+ <footer className="bg-white border-t mt-16">
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
+ <div className="text-center text-gray-600">
+ <p className="text-sm">
+ Powered by Claude AI and Model Context Protocol (MCP)
+ </p>
+ {hasSearched && (
+ <p className="text-xs mt-2" suppressHydrationWarning>
+ Analysis generated on {new Date(swotAnalysis.dateGenerated).toLocaleDateString()}
+ </p>
+ )}
+ </div>
+ </div>
+ </footer>
+ </main>
+ </div>
+ )
+}
diff --git a/src/components/LoadingTicker.tsx b/src/components/LoadingTicker.tsx
new file mode 100644
index 0000000..1362f36
--- /dev/null
+++ b/src/components/LoadingTicker.tsx
@@ -0,0 +1,104 @@
+'use client'
+
+import { useEffect, useState } from 'react'
+
+const sarcasticRemarks = [
+ "Consulting the magic 8-ball of business wisdom...",
+ "Teaching AI to pretend it knows about your neighborhood...",
+ "Scanning Yelp reviews with a very serious expression...",
+ "Asking ChatGPT if it's ever actually been to your city...",
+ "Generating buzzwords to make this sound professional...",
+ "Pretending to analyze market trends we just made up...",
+ "Consulting ancient business scrolls (Wikipedia)...",
+ "Running complex algorithms (Googling stuff)...",
+ "Channeling the spirit of every failed startup founder...",
+ "Convincing the AI this is definitely a good idea...",
+ "Throwing darts at a business plan dartboard...",
+ "Asking the nearest successful business owner for tips...",
+ "Calculating how many lattes you'll need to sell daily...",
+ "Determining if your idea is 'disruptive' enough...",
+ "Checking if there's already 5 of these on your street...",
+ "Measuring the vibes... they're pretty good, actually...",
+ "Consulting our crystal ball (it's cloudy today)...",
+ "Running your idea through the 'will this work' algorithm...",
+ "Asking AI to be optimistic for once...",
+ "Generating competitor analysis from thin air...",
+ "Calculating startup costs (spoiler: it's expensive)...",
+ "Determining market saturation levels (very yes)...",
+ "Researching historical context (thanks, Wikipedia)...",
+ "Projecting income (with aggressive optimism)...",
+ "Analyzing demographics (people who have money)...",
+ "Estimating your runway (better start running)...",
+ "Checking if this is 2008 all over again...",
+ "Validating your business model (crossing fingers)...",
+ "Generating SWOT analysis... emphasis on 'Threats'...",
+ "Measuring local competition (it's fierce out there)...",
+]
+
+interface LoadingTickerProps {
+ isComplete?: boolean
+}
+
+export function LoadingTicker({ isComplete = false }: LoadingTickerProps) {
+ const [currentRemark, setCurrentRemark] = useState(0)
+ const [fade, setFade] = useState(true)
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setFade(false)
+ setTimeout(() => {
+ setCurrentRemark((prev) => (prev + 1) % sarcasticRemarks.length)
+ setFade(true)
+ }, 300)
+ }, 3000)
+
+ return () => clearInterval(interval)
+ }, [])
+
+ return (
+ <div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center">
+ <div className="bg-white rounded-lg shadow-2xl p-8 max-w-md w-full mx-4">
+ <div className="flex flex-col items-center space-y-6">
+ {/* Status Emoticon - Red while loading, Green when complete */}
+ <div className="relative flex items-center justify-center">
+ {isComplete ? (
+ <div className="text-6xl animate-bounce">✅</div>
+ ) : (
+ <div className="text-6xl animate-pulse">🔴</div>
+ )}
+ </div>
+
+ {/* Title */}
+ <h3 className="text-xl font-bold text-gray-900">
+ {isComplete ? 'Analysis Complete!' : 'Analyzing Your Brilliant Idea...'}
+ </h3>
+
+ {/* Sarcastic ticker */}
+ <div className="h-20 flex items-center justify-center">
+ <p
+ className={`text-sm text-gray-600 italic text-center transition-opacity duration-300 ${
+ fade ? 'opacity-100' : 'opacity-0'
+ }`}
+ >
+ {isComplete ? 'Done! Preparing your results...' : sarcasticRemarks[currentRemark]}
+ </p>
+ </div>
+
+ {/* Progress indication */}
+ <div className="w-full bg-gray-200 rounded-full h-2">
+ <div
+ className={`h-2 rounded-full transition-all duration-500 ${
+ isComplete ? 'bg-green-600 w-full' : 'bg-red-600 animate-pulse'
+ }`}
+ style={{ width: isComplete ? '100%' : '70%' }}
+ ></div>
+ </div>
+
+ <p className="text-xs text-gray-500">
+ {isComplete ? 'Success!' : 'This usually takes 15-30 seconds...'}
+ </p>
+ </div>
+ </div>
+ </div>
+ )
+}
diff --git a/src/components/action-plan/ActionPlan.tsx b/src/components/action-plan/ActionPlan.tsx
new file mode 100644
index 0000000..6afa7a2
--- /dev/null
+++ b/src/components/action-plan/ActionPlan.tsx
@@ -0,0 +1,166 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import {
+ CheckCircle2,
+ Circle,
+ Clock,
+ DollarSign,
+ AlertCircle,
+} from 'lucide-react'
+import type { ActionItem } from '@/types/swot'
+
+interface ActionPlanProps {
+ actionItems: ActionItem[]
+}
+
+export function ActionPlan({ actionItems }: ActionPlanProps) {
+ const getPriorityColor = (priority: ActionItem['priority']) => {
+ switch (priority) {
+ case 'critical':
+ return 'destructive'
+ case 'high':
+ return 'warning'
+ case 'medium':
+ return 'secondary'
+ case 'low':
+ return 'outline'
+ }
+ }
+
+ const getCategoryIcon = (category: ActionItem['category']) => {
+ const iconClass = 'h-5 w-5'
+ switch (category) {
+ case 'domain':
+ return <Circle className={iconClass} />
+ case 'infrastructure':
+ return <Circle className={iconClass} />
+ case 'marketing':
+ return <Circle className={iconClass} />
+ case 'research':
+ return <Circle className={iconClass} />
+ case 'development':
+ return <Circle className={iconClass} />
+ }
+ }
+
+ const getStatusIcon = (status: ActionItem['status']) => {
+ switch (status) {
+ case 'completed':
+ return <CheckCircle2 className="h-5 w-5 text-green-600" />
+ case 'in-progress':
+ return <Clock className="h-5 w-5 text-blue-600" />
+ case 'not-started':
+ return <Circle className="h-5 w-5 text-gray-400" />
+ }
+ }
+
+ const groupedItems = actionItems.reduce((acc, item) => {
+ if (!acc[item.category]) {
+ acc[item.category] = []
+ }
+ acc[item.category].push(item)
+ return acc
+ }, {} as Record<string, ActionItem[]>)
+
+ const categoryNames: Record<ActionItem['category'], string> = {
+ domain: 'Domain & Hosting',
+ infrastructure: 'Infrastructure Setup',
+ marketing: 'Marketing & Advertising',
+ research: 'Market Research',
+ development: 'Development',
+ }
+
+ return (
+ <Card>
+ <CardHeader>
+ <CardTitle>Next Steps & Action Plan</CardTitle>
+ <CardDescription>
+ Recommended actions to launch your business
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-6">
+ {Object.entries(groupedItems).map(([category, items]) => (
+ <div key={category}>
+ <h3 className="text-lg font-semibold mb-3 flex items-center gap-2">
+ {getCategoryIcon(category as ActionItem['category'])}
+ {categoryNames[category as ActionItem['category']]}
+ </h3>
+ <div className="space-y-3">
+ {items.map(item => (
+ <div
+ key={item.id}
+ className="border rounded-lg p-4 hover:shadow-md transition-shadow"
+ >
+ <div className="flex items-start justify-between mb-2">
+ <div className="flex items-start gap-3 flex-1">
+ {getStatusIcon(item.status)}
+ <div className="flex-1">
+ <h4 className="font-semibold">{item.title}</h4>
+ <p className="text-sm text-muted-foreground mt-1">
+ {item.description}
+ </p>
+ </div>
+ </div>
+ <Badge variant={getPriorityColor(item.priority)}>
+ {item.priority}
+ </Badge>
+ </div>
+
+ <div className="flex items-center gap-4 mt-3 text-sm">
+ {item.estimatedCost && (
+ <div className="flex items-center gap-1 text-muted-foreground">
+ <DollarSign className="h-4 w-4" />
+ <span>${item.estimatedCost.toLocaleString()}</span>
+ </div>
+ )}
+ {item.estimatedTime && (
+ <div className="flex items-center gap-1 text-muted-foreground">
+ <Clock className="h-4 w-4" />
+ <span>{item.estimatedTime}</span>
+ </div>
+ )}
+ </div>
+
+ {item.dependencies && item.dependencies.length > 0 && (
+ <div className="mt-3 flex items-start gap-2">
+ <AlertCircle className="h-4 w-4 text-orange-500 mt-0.5" />
+ <div className="text-xs text-muted-foreground">
+ <strong>Dependencies:</strong> Requires completion of other tasks
+ </div>
+ </div>
+ )}
+ </div>
+ ))}
+ </div>
+ </div>
+ ))}
+ </div>
+
+ {/* Summary Stats */}
+ <div className="grid grid-cols-3 gap-4 mt-6 p-4 bg-muted/50 rounded-lg">
+ <div className="text-center">
+ <div className="text-2xl font-bold text-green-600">
+ {actionItems.filter(i => i.status === 'completed').length}
+ </div>
+ <div className="text-xs text-muted-foreground">Completed</div>
+ </div>
+ <div className="text-center">
+ <div className="text-2xl font-bold text-blue-600">
+ {actionItems.filter(i => i.status === 'in-progress').length}
+ </div>
+ <div className="text-xs text-muted-foreground">In Progress</div>
+ </div>
+ <div className="text-center">
+ <div className="text-2xl font-bold text-gray-600">
+ {actionItems.filter(i => i.status === 'not-started').length}
+ </div>
+ <div className="text-xs text-muted-foreground">Not Started</div>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ )
+}
diff --git a/src/components/financial/StartupCapitalBreakdown.tsx b/src/components/financial/StartupCapitalBreakdown.tsx
new file mode 100644
index 0000000..0264947
--- /dev/null
+++ b/src/components/financial/StartupCapitalBreakdown.tsx
@@ -0,0 +1,262 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import {
+ PieChart,
+ Pie,
+ Cell,
+ BarChart,
+ Bar,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from 'recharts'
+import { DollarSign, ShoppingCart, RefreshCw, TrendingUp, Package } from 'lucide-react'
+import type { StartupCosts, AssetItem } from '@/types/swot'
+
+interface StartupCapitalBreakdownProps {
+ startupCosts: StartupCosts
+}
+
+export function StartupCapitalBreakdown({ startupCosts }: StartupCapitalBreakdownProps) {
+ const formatCurrency = (value: number | undefined) => {
+ if (value === undefined || value === null || isNaN(value)) {
+ return '$0'
+ }
+ return `$${value.toLocaleString()}`
+ }
+
+ const getPriorityColor = (priority: AssetItem['priority']) => {
+ switch (priority) {
+ case 'essential':
+ return 'destructive'
+ case 'recommended':
+ return 'warning'
+ case 'optional':
+ return 'secondary'
+ }
+ }
+
+ const getCategoryIcon = (category: AssetItem['category']) => {
+ switch (category) {
+ case 'equipment':
+ return <Package className="h-4 w-4" />
+ case 'technology':
+ return <Package className="h-4 w-4" />
+ default:
+ return <ShoppingCart className="h-4 w-4" />
+ }
+ }
+
+ // Prepare one-time expenses chart data
+ const oneTimeData = [
+ { name: 'Assets', value: startupCosts.oneTimeExpenses.assets.reduce((sum, asset) => sum + (asset.purchasePrice || 0) * asset.quantity, 0) },
+ { name: 'Legal Fees', value: startupCosts.oneTimeExpenses.legalFees },
+ { name: 'Permits', value: startupCosts.oneTimeExpenses.permits },
+ { name: 'Inventory', value: startupCosts.oneTimeExpenses.initialInventory },
+ { name: 'Deposits', value: startupCosts.oneTimeExpenses.deposits },
+ ...startupCosts.oneTimeExpenses.other.map(item => ({ name: item.description, value: item.amount })),
+ ].filter(item => item.value > 0)
+
+ // Prepare recurring expenses chart data
+ const recurringData = [
+ { name: 'Rent', value: startupCosts.recurringExpenses.rent },
+ { name: 'Utilities', value: startupCosts.recurringExpenses.utilities },
+ { name: 'Insurance', value: startupCosts.recurringExpenses.insurance },
+ { name: 'Payroll', value: startupCosts.recurringExpenses.payroll },
+ { name: 'Marketing', value: startupCosts.recurringExpenses.marketing },
+ ...startupCosts.recurringExpenses.other.map(item => ({ name: item.description, value: item.amount })),
+ ].filter(item => item.value > 0)
+
+ const COLORS = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444', '#ec4899', '#14b8a6', '#f97316']
+
+ return (
+ <div className="space-y-6">
+ {/* Summary Cards */}
+ <div className="grid md:grid-cols-3 gap-4">
+ <Card className="border-blue-200 bg-blue-50/50">
+ <CardHeader className="pb-3">
+ <CardTitle className="text-sm font-medium flex items-center gap-2 text-blue-700">
+ <DollarSign className="h-4 w-4" />
+ Total Startup Capital
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="text-3xl font-bold text-blue-900">
+ {formatCurrency(startupCosts.totalStartupCapital)}
+ </div>
+ <p className="text-xs text-blue-600 mt-1">One-time investment needed</p>
+ </CardContent>
+ </Card>
+
+ <Card className="border-orange-200 bg-orange-50/50">
+ <CardHeader className="pb-3">
+ <CardTitle className="text-sm font-medium flex items-center gap-2 text-orange-700">
+ <RefreshCw className="h-4 w-4" />
+ Monthly Burn Rate
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="text-3xl font-bold text-orange-900">
+ {formatCurrency(startupCosts.monthlyBurnRate)}
+ </div>
+ <p className="text-xs text-orange-600 mt-1">Recurring monthly expenses</p>
+ </CardContent>
+ </Card>
+
+ <Card className="border-green-200 bg-green-50/50">
+ <CardHeader className="pb-3">
+ <CardTitle className="text-sm font-medium flex items-center gap-2 text-green-700">
+ <TrendingUp className="h-4 w-4" />
+ Runway
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="text-3xl font-bold text-green-900">
+ {startupCosts.runwayMonths} months
+ </div>
+ <p className="text-xs text-green-600 mt-1">Operating runway estimate</p>
+ </CardContent>
+ </Card>
+ </div>
+
+ {/* Charts */}
+ <div className="grid md:grid-cols-2 gap-6">
+ {/* One-Time Expenses Pie Chart */}
+ <Card>
+ <CardHeader>
+ <CardTitle>One-Time Expenses Breakdown</CardTitle>
+ <CardDescription>Initial capital requirements</CardDescription>
+ </CardHeader>
+ <CardContent>
+ <ResponsiveContainer width="100%" height={300}>
+ <PieChart>
+ <Pie
+ data={oneTimeData}
+ cx="50%"
+ cy="50%"
+ labelLine={false}
+ label={({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`}
+ outerRadius={100}
+ fill="#8884d8"
+ dataKey="value"
+ >
+ {oneTimeData.map((entry, index) => (
+ <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
+ ))}
+ </Pie>
+ <Tooltip formatter={(value: any) => formatCurrency(value)} />
+ </PieChart>
+ </ResponsiveContainer>
+ </CardContent>
+ </Card>
+
+ {/* Recurring Expenses Bar Chart */}
+ <Card>
+ <CardHeader>
+ <CardTitle>Monthly Recurring Expenses</CardTitle>
+ <CardDescription>Ongoing operational costs</CardDescription>
+ </CardHeader>
+ <CardContent>
+ <ResponsiveContainer width="100%" height={300}>
+ <BarChart data={recurringData}>
+ <CartesianGrid strokeDasharray="3 3" />
+ <XAxis dataKey="name" angle={-45} textAnchor="end" height={100} />
+ <YAxis tickFormatter={formatCurrency} />
+ <Tooltip formatter={(value: any) => formatCurrency(value)} />
+ <Bar dataKey="value" fill="#3b82f6">
+ {recurringData.map((entry, index) => (
+ <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
+ ))}
+ </Bar>
+ </BarChart>
+ </ResponsiveContainer>
+ </CardContent>
+ </Card>
+ </div>
+
+ {/* Assets Breakdown */}
+ <Card>
+ <CardHeader>
+ <CardTitle>Required Assets & Equipment</CardTitle>
+ <CardDescription>
+ Detailed list of assets needed with purchase and rental options
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-4">
+ {startupCosts.oneTimeExpenses.assets.map((asset) => (
+ <div
+ key={asset.id}
+ className="border rounded-lg p-4 hover:shadow-md transition-shadow"
+ >
+ <div className="flex items-start justify-between mb-2">
+ <div className="flex items-start gap-3 flex-1">
+ <div className="mt-1">{getCategoryIcon(asset.category)}</div>
+ <div className="flex-1">
+ <h4 className="font-semibold">{asset.name}</h4>
+ <p className="text-sm text-muted-foreground mt-1">
+ {asset.description}
+ </p>
+ <div className="flex items-center gap-2 mt-2">
+ <Badge variant="outline" className="text-xs">
+ {asset.category}
+ </Badge>
+ <Badge variant={getPriorityColor(asset.priority)} className="text-xs">
+ {asset.priority}
+ </Badge>
+ <span className="text-xs text-muted-foreground">
+ Qty: {asset.quantity}
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div className="grid grid-cols-2 gap-4 mt-3 pt-3 border-t">
+ {asset.purchasePrice && (
+ <div className={asset.isRental ? 'opacity-50' : ''}>
+ <div className="text-xs text-muted-foreground mb-1">
+ Purchase Option
+ </div>
+ <div className="text-lg font-bold text-blue-700">
+ {formatCurrency(asset.purchasePrice * asset.quantity)}
+ </div>
+ <div className="text-xs text-muted-foreground">
+ {formatCurrency(asset.purchasePrice)} × {asset.quantity}
+ </div>
+ </div>
+ )}
+ {asset.rentalRate && (
+ <div className={!asset.isRental ? 'opacity-50' : ''}>
+ <div className="text-xs text-muted-foreground mb-1">
+ Rental Option
+ </div>
+ <div className="text-lg font-bold text-green-700">
+ {formatCurrency(asset.rentalRate.amount * asset.quantity)}/
+ {asset.rentalRate.period === 'monthly' ? 'mo' : 'yr'}
+ </div>
+ <div className="text-xs text-muted-foreground">
+ {formatCurrency(asset.rentalRate.amount)} × {asset.quantity}
+ </div>
+ </div>
+ )}
+ </div>
+
+ {asset.isRental && asset.rentalRate && (
+ <div className="mt-2 text-xs bg-green-50 text-green-700 p-2 rounded">
+ ✓ Recommended: Rental option selected
+ </div>
+ )}
+ </div>
+ ))}
+ </div>
+ </CardContent>
+ </Card>
+ </div>
+ )
+}
diff --git a/src/components/historical/HistoricalContext.tsx b/src/components/historical/HistoricalContext.tsx
new file mode 100644
index 0000000..9dcf901
--- /dev/null
+++ b/src/components/historical/HistoricalContext.tsx
@@ -0,0 +1,55 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
+import { BookOpen } from 'lucide-react'
+import { HistoricalTimeline } from './HistoricalTimeline'
+import { TrajectoryCharts } from './TrajectoryCharts'
+import type { HistoricalContext as HistoricalContextType } from '@/types/swot'
+
+interface HistoricalContextProps {
+ context: HistoricalContextType | null
+}
+
+export function HistoricalContext({ context }: HistoricalContextProps) {
+ if (!context) {
+ return (
+ <Card>
+ <CardContent className="py-8">
+ <p className="text-center text-muted-foreground">
+ No historical context data available
+ </p>
+ </CardContent>
+ </Card>
+ )
+ }
+
+ return (
+ <div className="space-y-6">
+ {/* Summary */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <BookOpen className="h-5 w-5" />
+ Historical Context: {context.areaName}
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="prose prose-sm max-w-none">
+ <p className="text-muted-foreground leading-relaxed whitespace-pre-line">
+ {context.summary}
+ </p>
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* Timeline */}
+ <HistoricalTimeline events={context.keyEvents} />
+
+ {/* Trajectory Charts */}
+ <div>
+ <h3 className="text-2xl font-bold mb-4">Economic Trajectory Analysis</h3>
+ <TrajectoryCharts trajectories={context.trajectories} />
+ </div>
+ </div>
+ )
+}
diff --git a/src/components/historical/HistoricalTimeline.tsx b/src/components/historical/HistoricalTimeline.tsx
new file mode 100644
index 0000000..f15ca0a
--- /dev/null
+++ b/src/components/historical/HistoricalTimeline.tsx
@@ -0,0 +1,91 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import { Calendar } from 'lucide-react'
+import type { HistoricalEvent } from '@/types/swot'
+
+interface HistoricalTimelineProps {
+ events: HistoricalEvent[]
+}
+
+export function HistoricalTimeline({ events }: HistoricalTimelineProps) {
+ const getImpactColor = (impact: 'positive' | 'negative' | 'neutral') => {
+ switch (impact) {
+ case 'positive':
+ return 'bg-green-500'
+ case 'negative':
+ return 'bg-red-500'
+ case 'neutral':
+ return 'bg-gray-500'
+ }
+ }
+
+ const getImpactBadge = (impact: 'positive' | 'negative' | 'neutral') => {
+ switch (impact) {
+ case 'positive':
+ return 'success'
+ case 'negative':
+ return 'destructive'
+ case 'neutral':
+ return 'secondary'
+ }
+ }
+
+ return (
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <Calendar className="h-5 w-5" />
+ Historical Timeline
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="relative">
+ {/* Timeline line */}
+ <div className="absolute left-4 top-0 bottom-0 w-0.5 bg-border" />
+
+ {/* Events */}
+ <div className="space-y-6">
+ {events
+ .sort((a, b) => b.year - a.year)
+ .map((event, index) => (
+ <div key={index} className="relative pl-10">
+ {/* Timeline dot */}
+ <div
+ className={`absolute left-2.5 w-3 h-3 rounded-full ${getImpactColor(
+ event.economicImpact
+ )}`}
+ />
+
+ {/* Event card */}
+ <div className="bg-muted/50 rounded-lg p-4">
+ <div className="flex items-start justify-between mb-2">
+ <div>
+ <div className="font-bold text-lg">{event.year}</div>
+ <h4 className="font-semibold">{event.title}</h4>
+ </div>
+ <div className="flex gap-2">
+ <Badge variant={getImpactBadge(event.economicImpact)}>
+ {event.economicImpact}
+ </Badge>
+ {event.relevance >= 80 && (
+ <Badge variant="outline">High Relevance</Badge>
+ )}
+ </div>
+ </div>
+ <p className="text-sm text-muted-foreground">
+ {event.description}
+ </p>
+ <div className="mt-2 text-xs text-muted-foreground">
+ Relevance to current analysis: {event.relevance}%
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ )
+}
diff --git a/src/components/historical/TrajectoryCharts.tsx b/src/components/historical/TrajectoryCharts.tsx
new file mode 100644
index 0000000..4cb6c33
--- /dev/null
+++ b/src/components/historical/TrajectoryCharts.tsx
@@ -0,0 +1,143 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import {
+ LineChart,
+ Line,
+ AreaChart,
+ Area,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from 'recharts'
+import type { AreaTrajectory } from '@/types/swot'
+
+interface TrajectoryChartsProps {
+ trajectories: AreaTrajectory[]
+}
+
+export function TrajectoryCharts({ trajectories }: TrajectoryChartsProps) {
+ const getTrendColor = (trend: 'increasing' | 'decreasing' | 'stable') => {
+ switch (trend) {
+ case 'increasing':
+ return '#22c55e' // green
+ case 'decreasing':
+ return '#ef4444' // red
+ case 'stable':
+ return '#3b82f6' // blue
+ }
+ }
+
+ const formatMetricName = (metric: string) => {
+ return metric
+ .split('-')
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ')
+ }
+
+ const formatValue = (value: number, metric: string) => {
+ if (metric.includes('population') || metric.includes('employment')) {
+ return value.toLocaleString()
+ }
+ if (metric.includes('rate') || metric.includes('percentage')) {
+ return `${value}%`
+ }
+ if (metric.includes('income') || metric.includes('revenue')) {
+ return `$${value.toLocaleString()}`
+ }
+ return value.toLocaleString()
+ }
+
+ return (
+ <div className="space-y-6">
+ {trajectories.map((trajectory, index) => {
+ const color = getTrendColor(trajectory.trend)
+ const hasForecast = trajectory.forecast && trajectory.forecast.length > 0
+
+ // Combine historical and forecast data
+ const chartData = [
+ ...trajectory.data.map(d => ({
+ year: d.year,
+ value: d.value,
+ type: 'Historical',
+ })),
+ ...(hasForecast
+ ? trajectory.forecast!.map(f => ({
+ year: f.year,
+ value: f.value,
+ type: 'Forecast',
+ confidence: f.confidence,
+ }))
+ : []),
+ ]
+
+ return (
+ <Card key={index}>
+ <CardHeader>
+ <CardTitle>{formatMetricName(trajectory.metric)}</CardTitle>
+ <CardDescription>
+ Trend: <strong className={`text-${trajectory.trend === 'increasing' ? 'green' : trajectory.trend === 'decreasing' ? 'red' : 'blue'}-600`}>
+ {trajectory.trend.charAt(0).toUpperCase() + trajectory.trend.slice(1)}
+ </strong>
+ {hasForecast && ' • Includes forecast data'}
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <ResponsiveContainer width="100%" height={300}>
+ {hasForecast ? (
+ <AreaChart data={chartData}>
+ <CartesianGrid strokeDasharray="3 3" />
+ <XAxis dataKey="year" />
+ <YAxis
+ tickFormatter={(value) => formatValue(value, trajectory.metric)}
+ />
+ <Tooltip
+ formatter={(value: any, name: string) => [
+ formatValue(value, trajectory.metric),
+ name,
+ ]}
+ />
+ <Legend />
+ <Area
+ type="monotone"
+ dataKey="value"
+ stroke={color}
+ fill={color}
+ fillOpacity={0.3}
+ name={formatMetricName(trajectory.metric)}
+ />
+ </AreaChart>
+ ) : (
+ <LineChart data={chartData}>
+ <CartesianGrid strokeDasharray="3 3" />
+ <XAxis dataKey="year" />
+ <YAxis
+ tickFormatter={(value) => formatValue(value, trajectory.metric)}
+ />
+ <Tooltip
+ formatter={(value: any) => [
+ formatValue(value, trajectory.metric),
+ formatMetricName(trajectory.metric),
+ ]}
+ />
+ <Line
+ type="monotone"
+ dataKey="value"
+ stroke={color}
+ strokeWidth={2}
+ dot={{ fill: color, r: 4 }}
+ activeDot={{ r: 6 }}
+ />
+ </LineChart>
+ )}
+ </ResponsiveContainer>
+ </CardContent>
+ </Card>
+ )
+ })}
+ </div>
+ )
+}
diff --git a/src/components/market/CompetitorMap.tsx b/src/components/market/CompetitorMap.tsx
new file mode 100644
index 0000000..3c2a876
--- /dev/null
+++ b/src/components/market/CompetitorMap.tsx
@@ -0,0 +1,111 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import { Store, MapPin, Star, DollarSign } from 'lucide-react'
+import type { CompetitorData } from '@/types/swot'
+
+interface CompetitorMapProps {
+ competitors: CompetitorData[]
+ businessType: string
+}
+
+export function CompetitorMap({ competitors, businessType }: CompetitorMapProps) {
+ const sortedByDistance = [...competitors].sort((a, b) => a.distance - b.distance)
+
+ const getDistanceColor = (distance: number) => {
+ if (distance < 1) return 'text-red-600'
+ if (distance < 3) return 'text-orange-600'
+ if (distance < 5) return 'text-yellow-600'
+ return 'text-green-600'
+ }
+
+ return (
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <Store className="h-5 w-5" />
+ Competitor Analysis
+ </CardTitle>
+ <CardDescription>
+ {competitors.length} {businessType} businesses found in the area
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-4">
+ {sortedByDistance.map((competitor, index) => (
+ <div
+ key={index}
+ className="border rounded-lg p-4 hover:shadow-md transition-shadow"
+ >
+ <div className="flex items-start justify-between mb-2">
+ <div className="flex-1">
+ <h4 className="font-semibold text-lg">{competitor.name}</h4>
+ <p className="text-sm text-muted-foreground">{competitor.type}</p>
+ </div>
+ <div className="flex gap-2">
+ <Badge variant="outline" className={getDistanceColor(competitor.distance)}>
+ <MapPin className="h-3 w-3 mr-1" />
+ {competitor.distance.toFixed(1)} mi
+ </Badge>
+ </div>
+ </div>
+
+ <div className="grid grid-cols-3 gap-4 mt-3">
+ {competitor.yearEstablished && (
+ <div className="text-sm">
+ <span className="text-muted-foreground">Established:</span>
+ <p className="font-medium">{competitor.yearEstablished}</p>
+ </div>
+ )}
+ {competitor.estimatedRevenue && (
+ <div className="text-sm">
+ <span className="text-muted-foreground flex items-center gap-1">
+ <DollarSign className="h-3 w-3" />
+ Est. Revenue:
+ </span>
+ <p className="font-medium">
+ ${(competitor.estimatedRevenue / 1000).toFixed(0)}K
+ </p>
+ </div>
+ )}
+ {competitor.rating && (
+ <div className="text-sm">
+ <span className="text-muted-foreground flex items-center gap-1">
+ <Star className="h-3 w-3" />
+ Rating:
+ </span>
+ <p className="font-medium">{competitor.rating.toFixed(1)}/5.0</p>
+ </div>
+ )}
+ </div>
+ </div>
+ ))}
+ </div>
+
+ {/* Summary Stats */}
+ <div className="grid grid-cols-3 gap-4 mt-6 p-4 bg-muted/50 rounded-lg">
+ <div className="text-center">
+ <div className="text-2xl font-bold text-primary">{competitors.length}</div>
+ <div className="text-xs text-muted-foreground">Total Competitors</div>
+ </div>
+ <div className="text-center">
+ <div className="text-2xl font-bold text-primary">
+ {competitors.filter(c => c.distance < 5).length}
+ </div>
+ <div className="text-xs text-muted-foreground">Within 5 Miles</div>
+ </div>
+ <div className="text-center">
+ <div className="text-2xl font-bold text-primary">
+ {(
+ competitors.reduce((sum, c) => sum + (c.rating || 0), 0) /
+ competitors.filter(c => c.rating).length
+ ).toFixed(1)}
+ </div>
+ <div className="text-xs text-muted-foreground">Avg Rating</div>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ )
+}
diff --git a/src/components/market/IncomeProjections.tsx b/src/components/market/IncomeProjections.tsx
new file mode 100644
index 0000000..3f00ce5
--- /dev/null
+++ b/src/components/market/IncomeProjections.tsx
@@ -0,0 +1,127 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import {
+ LineChart,
+ Line,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from 'recharts'
+import { DollarSign } from 'lucide-react'
+import type { IncomeProjection } from '@/types/swot'
+
+interface IncomeProjectionsProps {
+ projections: IncomeProjection[]
+}
+
+export function IncomeProjections({ projections }: IncomeProjectionsProps) {
+ const formatCurrency = (value: number) => {
+ if (value >= 1000000) {
+ return `$${(value / 1000000).toFixed(1)}M`
+ }
+ if (value >= 1000) {
+ return `$${(value / 1000).toFixed(0)}K`
+ }
+ return `$${value.toLocaleString()}`
+ }
+
+ const chartData = projections.map(p => ({
+ year: p.year,
+ Optimistic: p.optimistic,
+ Realistic: p.realistic,
+ Pessimistic: p.pessimistic,
+ }))
+
+ return (
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <DollarSign className="h-5 w-5" />
+ Income Projections
+ </CardTitle>
+ <CardDescription>
+ Projected annual revenue based on market analysis
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <ResponsiveContainer width="100%" height={350}>
+ <LineChart data={chartData}>
+ <CartesianGrid strokeDasharray="3 3" />
+ <XAxis dataKey="year" />
+ <YAxis tickFormatter={formatCurrency} />
+ <Tooltip
+ formatter={(value: any) => formatCurrency(value)}
+ contentStyle={{ backgroundColor: 'white', border: '1px solid #ccc' }}
+ />
+ <Legend />
+ <Line
+ type="monotone"
+ dataKey="Optimistic"
+ stroke="#22c55e"
+ strokeWidth={2}
+ dot={{ fill: '#22c55e', r: 4 }}
+ />
+ <Line
+ type="monotone"
+ dataKey="Realistic"
+ stroke="#3b82f6"
+ strokeWidth={3}
+ dot={{ fill: '#3b82f6', r: 5 }}
+ />
+ <Line
+ type="monotone"
+ dataKey="Pessimistic"
+ stroke="#ef4444"
+ strokeWidth={2}
+ dot={{ fill: '#ef4444', r: 4 }}
+ />
+ </LineChart>
+ </ResponsiveContainer>
+
+ {/* Projection Details */}
+ <div className="space-y-4 mt-6">
+ {projections.map((projection, index) => (
+ <div key={index} className="border rounded-lg p-4">
+ <div className="flex items-center justify-between mb-3">
+ <div className="font-semibold text-lg">Year {projection.year}</div>
+ <div className="text-sm text-muted-foreground">
+ Confidence: {projection.confidence}%
+ </div>
+ </div>
+ <div className="grid grid-cols-3 gap-4">
+ <div>
+ <div className="text-xs text-green-600 font-medium mb-1">
+ Optimistic
+ </div>
+ <div className="text-xl font-bold text-green-700">
+ {formatCurrency(projection.optimistic)}
+ </div>
+ </div>
+ <div>
+ <div className="text-xs text-blue-600 font-medium mb-1">
+ Realistic
+ </div>
+ <div className="text-xl font-bold text-blue-700">
+ {formatCurrency(projection.realistic)}
+ </div>
+ </div>
+ <div>
+ <div className="text-xs text-red-600 font-medium mb-1">
+ Pessimistic
+ </div>
+ <div className="text-xl font-bold text-red-700">
+ {formatCurrency(projection.pessimistic)}
+ </div>
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </CardContent>
+ </Card>
+ )
+}
diff --git a/src/components/market/MarketSizeChart.tsx b/src/components/market/MarketSizeChart.tsx
new file mode 100644
index 0000000..5b5c5d1
--- /dev/null
+++ b/src/components/market/MarketSizeChart.tsx
@@ -0,0 +1,220 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import {
+ BarChart,
+ Bar,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+ PieChart,
+ Pie,
+ Cell,
+} from 'recharts'
+import { TrendingUp } from 'lucide-react'
+import type { MarketSize } from '@/types/swot'
+
+interface MarketSizeChartProps {
+ marketSize: MarketSize
+ demographics: {
+ population: number
+ medianIncome: number
+ averageHouseholdSize: number
+ targetDemographicPercentage: number
+ }
+}
+
+export function MarketSizeChart({ marketSize, demographics }: MarketSizeChartProps) {
+ const marketData = [
+ {
+ name: 'Total Addressable Market',
+ value: marketSize.totalAddressableMarket,
+ color: '#3b82f6',
+ },
+ {
+ name: 'Serviceable Market',
+ value: marketSize.serviceableMarket,
+ color: '#8b5cf6',
+ },
+ {
+ name: 'Target Market',
+ value: marketSize.targetMarket,
+ color: '#22c55e',
+ },
+ ]
+
+ const barChartData = [
+ {
+ name: 'TAM',
+ value: marketSize.totalAddressableMarket,
+ },
+ {
+ name: 'SAM',
+ value: marketSize.serviceableMarket,
+ },
+ {
+ name: 'SOM',
+ value: marketSize.targetMarket,
+ },
+ ]
+
+ const COLORS = ['#3b82f6', '#8b5cf6', '#22c55e']
+
+ const formatCurrency = (value: number) => {
+ if (value >= 1000000) {
+ return `$${(value / 1000000).toFixed(1)}M`
+ }
+ if (value >= 1000) {
+ return `$${(value / 1000).toFixed(0)}K`
+ }
+ return `$${value.toLocaleString()}`
+ }
+
+ return (
+ <div className="space-y-6">
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <TrendingUp className="h-5 w-5" />
+ Market Size Analysis
+ </CardTitle>
+ <CardDescription>
+ Potential market share: {marketSize.marketSharePotential}%
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="grid md:grid-cols-2 gap-6">
+ {/* Bar Chart */}
+ <div>
+ <h4 className="text-sm font-semibold mb-4">Market Breakdown</h4>
+ <ResponsiveContainer width="100%" height={250}>
+ <BarChart data={barChartData}>
+ <CartesianGrid strokeDasharray="3 3" />
+ <XAxis dataKey="name" />
+ <YAxis tickFormatter={formatCurrency} />
+ <Tooltip formatter={(value: any) => formatCurrency(value)} />
+ <Bar dataKey="value" fill="#3b82f6">
+ {barChartData.map((entry, index) => (
+ <Cell key={`cell-${index}`} fill={COLORS[index]} />
+ ))}
+ </Bar>
+ </BarChart>
+ </ResponsiveContainer>
+ </div>
+
+ {/* Pie Chart */}
+ <div>
+ <h4 className="text-sm font-semibold mb-4">Market Distribution</h4>
+ <ResponsiveContainer width="100%" height={250}>
+ <PieChart>
+ <Pie
+ data={marketData}
+ cx="50%"
+ cy="50%"
+ labelLine={false}
+ label={({ name, percent }) => `${name.split(' ')[0]}: ${(percent * 100).toFixed(0)}%`}
+ outerRadius={80}
+ fill="#8884d8"
+ dataKey="value"
+ >
+ {marketData.map((entry, index) => (
+ <Cell key={`cell-${index}`} fill={entry.color} />
+ ))}
+ </Pie>
+ <Tooltip formatter={(value: any) => formatCurrency(value)} />
+ </PieChart>
+ </ResponsiveContainer>
+ </div>
+ </div>
+
+ {/* Market Details */}
+ <div className="grid md:grid-cols-3 gap-4 mt-6">
+ <div className="bg-blue-50 p-4 rounded-lg">
+ <div className="text-xs text-blue-600 font-medium mb-1">
+ Total Addressable Market
+ </div>
+ <div className="text-2xl font-bold text-blue-900">
+ {formatCurrency(marketSize.totalAddressableMarket)}
+ </div>
+ <div className="text-xs text-blue-600 mt-1">
+ Total market potential
+ </div>
+ </div>
+ <div className="bg-purple-50 p-4 rounded-lg">
+ <div className="text-xs text-purple-600 font-medium mb-1">
+ Serviceable Market
+ </div>
+ <div className="text-2xl font-bold text-purple-900">
+ {formatCurrency(marketSize.serviceableMarket)}
+ </div>
+ <div className="text-xs text-purple-600 mt-1">
+ Realistically serviceable
+ </div>
+ </div>
+ <div className="bg-green-50 p-4 rounded-lg">
+ <div className="text-xs text-green-600 font-medium mb-1">
+ Target Market
+ </div>
+ <div className="text-2xl font-bold text-green-900">
+ {formatCurrency(marketSize.targetMarket)}
+ </div>
+ <div className="text-xs text-green-600 mt-1">
+ Initial target segment
+ </div>
+ </div>
+ </div>
+
+ {/* Assumptions */}
+ {marketSize.assumptions.length > 0 && (
+ <div className="mt-6 p-4 bg-muted/50 rounded-lg">
+ <h4 className="text-sm font-semibold mb-2">Key Assumptions</h4>
+ <ul className="text-sm space-y-1 list-disc list-inside text-muted-foreground">
+ {marketSize.assumptions.map((assumption, index) => (
+ <li key={index}>{assumption}</li>
+ ))}
+ </ul>
+ </div>
+ )}
+ </CardContent>
+ </Card>
+
+ {/* Demographics */}
+ <Card>
+ <CardHeader>
+ <CardTitle>Local Demographics</CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="grid md:grid-cols-4 gap-4">
+ <div className="text-center p-4 bg-muted/50 rounded-lg">
+ <div className="text-3xl font-bold text-primary">
+ {demographics.population.toLocaleString()}
+ </div>
+ <div className="text-sm text-muted-foreground mt-1">Population</div>
+ </div>
+ <div className="text-center p-4 bg-muted/50 rounded-lg">
+ <div className="text-3xl font-bold text-primary">
+ ${demographics.medianIncome.toLocaleString()}
+ </div>
+ <div className="text-sm text-muted-foreground mt-1">Median Income</div>
+ </div>
+ <div className="text-center p-4 bg-muted/50 rounded-lg">
+ <div className="text-3xl font-bold text-primary">
+ {demographics.averageHouseholdSize.toFixed(1)}
+ </div>
+ <div className="text-sm text-muted-foreground mt-1">Avg Household Size</div>
+ </div>
+ <div className="text-center p-4 bg-muted/50 rounded-lg">
+ <div className="text-3xl font-bold text-primary">
+ {demographics.targetDemographicPercentage}%
+ </div>
+ <div className="text-sm text-muted-foreground mt-1">Target Demographic</div>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ </div>
+ )
+}
diff --git a/src/components/mindmap/MindMap.tsx b/src/components/mindmap/MindMap.tsx
new file mode 100644
index 0000000..2fd72b8
--- /dev/null
+++ b/src/components/mindmap/MindMap.tsx
@@ -0,0 +1,230 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import {
+ Database,
+ Brain,
+ BarChart3,
+ Server,
+ Cloud,
+ GitBranch,
+ Zap,
+ TrendingUp,
+} from 'lucide-react'
+
+interface MindMapNode {
+ id: string
+ label: string
+ icon: React.ReactNode
+ color: string
+ children?: MindMapNode[]
+}
+
+export function MindMap() {
+ const mindMapData: MindMapNode = {
+ id: 'root',
+ label: 'Local Business Viability SWOT Engine',
+ icon: <Brain className="h-6 w-6" />,
+ color: 'bg-purple-500',
+ children: [
+ {
+ id: 'data-ingestion',
+ label: 'Data Ingestion (Source)',
+ icon: <Database className="h-5 w-5" />,
+ color: 'bg-blue-500',
+ children: [
+ {
+ id: 'business-dir',
+ label: 'Local Business Directories',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-blue-400',
+ },
+ {
+ id: 'historical',
+ label: 'Historical Documents',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-blue-400',
+ },
+ {
+ id: 'trajectory',
+ label: 'Economic Trajectory Data',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-blue-400',
+ },
+ ],
+ },
+ {
+ id: 'ai-core',
+ label: 'AI Core (Processing)',
+ icon: <Brain className="h-5 w-5" />,
+ color: 'bg-green-500',
+ children: [
+ {
+ id: 'claude',
+ label: 'Claude API',
+ icon: <Zap className="h-4 w-4" />,
+ color: 'bg-green-400',
+ },
+ {
+ id: 'mcp',
+ label: 'MCP Server',
+ icon: <Server className="h-4 w-4" />,
+ color: 'bg-green-400',
+ },
+ {
+ id: 'vector',
+ label: 'Vector Database',
+ icon: <Database className="h-4 w-4" />,
+ color: 'bg-green-400',
+ },
+ ],
+ },
+ {
+ id: 'output',
+ label: 'Output & Visualization',
+ icon: <BarChart3 className="h-5 w-5" />,
+ color: 'bg-orange-500',
+ children: [
+ {
+ id: 'swot',
+ label: 'Full SWOT Analysis',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-orange-400',
+ },
+ {
+ id: 'timeline',
+ label: 'Historical Timeline',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-orange-400',
+ },
+ {
+ id: 'market',
+ label: 'Market Size Projections',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-orange-400',
+ },
+ {
+ id: 'scorecard',
+ label: 'Go/No-Go Scorecard',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-orange-400',
+ },
+ ],
+ },
+ {
+ id: 'infrastructure',
+ label: 'Infrastructure & Development',
+ icon: <Cloud className="h-5 w-5" />,
+ color: 'bg-red-500',
+ children: [
+ {
+ id: 'vercel',
+ label: 'Vercel Deployment',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-red-400',
+ },
+ {
+ id: 'github',
+ label: 'GitHub Repository',
+ icon: <GitBranch className="h-4 w-4" />,
+ color: 'bg-red-400',
+ },
+ {
+ id: 'next-steps',
+ label: 'Next Steps',
+ icon: <TrendingUp className="h-4 w-4" />,
+ color: 'bg-red-400',
+ },
+ ],
+ },
+ ],
+ }
+
+ const renderNode = (node: MindMapNode, level: number = 0) => {
+ const isRoot = level === 0
+ const isLeaf = !node.children || node.children.length === 0
+
+ return (
+ <div key={node.id} className={`${level > 0 ? 'ml-8' : ''} mb-4`}>
+ <div
+ className={`
+ flex items-center gap-3 p-4 rounded-lg border-2
+ ${isRoot ? 'border-purple-500 bg-purple-50 shadow-lg' : 'border-gray-200 bg-white'}
+ hover:shadow-md transition-all cursor-pointer
+ `}
+ >
+ <div className={`${node.color} text-white p-2 rounded-lg`}>
+ {node.icon}
+ </div>
+ <div className="flex-1">
+ <div className={`font-semibold ${isRoot ? 'text-lg' : 'text-sm'}`}>
+ {node.label}
+ </div>
+ {isRoot && (
+ <div className="text-xs text-muted-foreground mt-1">
+ AI-Powered Business Analysis Platform
+ </div>
+ )}
+ </div>
+ {!isLeaf && (
+ <Badge variant="secondary">
+ {node.children?.length} {node.children?.length === 1 ? 'item' : 'items'}
+ </Badge>
+ )}
+ </div>
+
+ {node.children && (
+ <div className="relative">
+ {/* Connecting line */}
+ {level === 0 && (
+ <div className="absolute left-4 top-0 bottom-0 w-0.5 bg-gradient-to-b from-gray-300 to-transparent" />
+ )}
+ <div className="mt-4 space-y-3">
+ {node.children.map(child => renderNode(child, level + 1))}
+ </div>
+ </div>
+ )}
+ </div>
+ )
+ }
+
+ return (
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <GitBranch className="h-5 w-5" />
+ System Architecture Mind Map
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="overflow-x-auto">
+ {renderNode(mindMapData)}
+ </div>
+
+ {/* Legend */}
+ <div className="mt-8 p-4 bg-muted/50 rounded-lg">
+ <h4 className="text-sm font-semibold mb-3">Component Categories</h4>
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
+ <div className="flex items-center gap-2">
+ <div className="w-4 h-4 bg-blue-500 rounded" />
+ <span className="text-xs">Data Sources</span>
+ </div>
+ <div className="flex items-center gap-2">
+ <div className="w-4 h-4 bg-green-500 rounded" />
+ <span className="text-xs">AI Processing</span>
+ </div>
+ <div className="flex items-center gap-2">
+ <div className="w-4 h-4 bg-orange-500 rounded" />
+ <span className="text-xs">Visualizations</span>
+ </div>
+ <div className="flex items-center gap-2">
+ <div className="w-4 h-4 bg-red-500 rounded" />
+ <span className="text-xs">Infrastructure</span>
+ </div>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ )
+}
diff --git a/src/components/search/SearchForm.tsx b/src/components/search/SearchForm.tsx
new file mode 100644
index 0000000..a0b5e74
--- /dev/null
+++ b/src/components/search/SearchForm.tsx
@@ -0,0 +1,347 @@
+'use client'
+
+import { useState } from 'react'
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import { Search, MapPin, Briefcase, Navigation } from 'lucide-react'
+
+interface SearchFormProps {
+ onSearch: (data: SearchFormData) => void
+ isLoading?: boolean
+}
+
+export interface SearchFormData {
+ location: string
+ businessType: string
+ radiusMiles: number
+ capitalOnHand?: number
+ searchMode?: 'single' | 'opportunities'
+}
+
+const topTrendingIdeas = [
+ { business: 'AI-powered SaaS startup', location: 'San Francisco, CA', description: 'Build the next unicorn with GPT wrappers' },
+ { business: 'Craft Coffee Roastery', location: 'Austin, TX', description: 'Single-origin artisan beans for hipsters' },
+ { business: 'Ghost Kitchen (Cloud Kitchen)', location: 'Miami, FL', description: 'Virtual restaurants, real profits' },
+ { business: 'Electric Vehicle Charging Station', location: 'Los Angeles, CA', description: 'Capitalize on the EV revolution' },
+ { business: 'Premium Pet Care & Grooming', location: 'Seattle, WA', description: 'Pamper those fur babies' },
+]
+
+export function SearchForm({ onSearch, isLoading = false }: SearchFormProps) {
+ const [location, setLocation] = useState('')
+ const [businessType, setBusinessType] = useState('')
+ const [radiusMiles, setRadiusMiles] = useState(10)
+ const [capitalOnHand, setCapitalOnHand] = useState('')
+ const [showSuggestions, setShowSuggestions] = useState(false)
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault()
+
+ // If both fields are empty, show suggestions
+ if (!location.trim() && !businessType.trim()) {
+ setShowSuggestions(true)
+ return
+ }
+
+ // If location is provided but no business type, find opportunities
+ if (location.trim() && !businessType.trim()) {
+ onSearch({
+ location: location.trim(),
+ businessType: '',
+ radiusMiles,
+ capitalOnHand: capitalOnHand ? parseInt(capitalOnHand) : undefined,
+ searchMode: 'opportunities',
+ })
+ return
+ }
+
+ // Use defaults if location is empty
+ const finalLocation = location.trim() || 'San Francisco, CA'
+ const finalBusinessType = businessType.trim()
+
+ onSearch({
+ location: finalLocation,
+ businessType: finalBusinessType,
+ radiusMiles,
+ capitalOnHand: capitalOnHand ? parseInt(capitalOnHand) : undefined,
+ searchMode: 'single',
+ })
+ }
+
+ const handleFindOpportunities = () => {
+ if (!location.trim()) {
+ alert('Please enter a location to search for opportunities')
+ return
+ }
+
+ if (!capitalOnHand || parseInt(capitalOnHand) <= 0) {
+ alert('Please enter your available capital amount')
+ return
+ }
+
+ onSearch({
+ location: location.trim(),
+ businessType: '',
+ radiusMiles,
+ capitalOnHand: parseInt(capitalOnHand),
+ searchMode: 'opportunities',
+ })
+ }
+
+ const handleSurprise = (idea: typeof topTrendingIdeas[0]) => {
+ setLocation(idea.location)
+ setBusinessType(idea.business)
+ setShowSuggestions(false)
+ onSearch({
+ location: idea.location,
+ businessType: idea.business,
+ radiusMiles,
+ })
+ }
+
+ const exampleBusinessTypes = [
+ 'Coffee Shop',
+ 'Restaurant',
+ 'Retail Store',
+ 'Gym/Fitness',
+ 'Bakery',
+ 'Salon',
+ 'Tech Startup',
+ 'Consulting',
+ ]
+
+ return (
+ <Card className="w-full">
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-2xl">
+ <Search className="h-6 w-6" />
+ Search Business Ideas in Your Area
+ </CardTitle>
+ <CardDescription>
+ Enter your location and business idea to get an AI-powered SWOT analysis
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <form onSubmit={handleSubmit} className="space-y-6">
+ {/* Location Input */}
+ <div className="space-y-2">
+ <label
+ htmlFor="location"
+ className="flex items-center gap-2 text-sm font-medium"
+ >
+ <MapPin className="h-4 w-4" />
+ Location (City, State)
+ </label>
+ <input
+ id="location"
+ type="text"
+ value={location}
+ onChange={(e) => setLocation(e.target.value)}
+ placeholder="e.g., Portland, OR (leave blank for San Francisco, CA)"
+ className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
+ />
+ <p className="text-xs text-muted-foreground">
+ Leave blank to analyze the best trending location
+ </p>
+ </div>
+
+ {/* Business Type Input */}
+ <div className="space-y-2">
+ <label
+ htmlFor="businessType"
+ className="flex items-center gap-2 text-sm font-medium"
+ >
+ <Briefcase className="h-4 w-4" />
+ Business Idea or Occupation
+ </label>
+ <input
+ id="businessType"
+ type="text"
+ value={businessType}
+ onChange={(e) => setBusinessType(e.target.value)}
+ placeholder="e.g., Specialty Coffee Roastery (leave blank for AI SaaS)"
+ className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
+ />
+ <div className="flex flex-wrap gap-2 mt-2">
+ {exampleBusinessTypes.map((type) => (
+ <Badge
+ key={type}
+ variant="outline"
+ className="cursor-pointer hover:bg-blue-50 transition-colors"
+ onClick={() => setBusinessType(type)}
+ >
+ {type}
+ </Badge>
+ ))}
+ </div>
+ <p className="text-xs text-muted-foreground">
+ Click a suggestion, type your own, or leave blank for best AI idea
+ </p>
+ </div>
+
+ {/* Radius Input */}
+ <div className="space-y-2">
+ <label
+ htmlFor="radius"
+ className="flex items-center gap-2 text-sm font-medium"
+ >
+ <Navigation className="h-4 w-4" />
+ Search Radius: {radiusMiles} miles
+ </label>
+ <div className="flex items-center gap-4">
+ <input
+ id="radius"
+ type="range"
+ min="1"
+ max="50"
+ step="1"
+ value={radiusMiles}
+ onChange={(e) => setRadiusMiles(parseInt(e.target.value))}
+ className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-blue-500"
+ />
+ <div className="text-sm font-medium bg-blue-50 px-3 py-1 rounded-lg min-w-[60px] text-center">
+ {radiusMiles} mi
+ </div>
+ </div>
+ <div className="flex justify-between text-xs text-muted-foreground">
+ <span>1 mile</span>
+ <span>50 miles</span>
+ </div>
+ <p className="text-xs text-muted-foreground">
+ Search for competitors and opportunities within this radius
+ </p>
+ </div>
+
+ {/* Capital on Hand Input */}
+ <div className="space-y-2">
+ <label
+ htmlFor="capital"
+ className="flex items-center gap-2 text-sm font-medium"
+ >
+ <Briefcase className="h-4 w-4" />
+ Capital on Hand (Optional)
+ </label>
+ <div className="relative">
+ <span className="absolute left-4 top-3 text-gray-500">$</span>
+ <input
+ id="capital"
+ type="number"
+ value={capitalOnHand}
+ onChange={(e) => setCapitalOnHand(e.target.value)}
+ placeholder="25000"
+ min="0"
+ step="1000"
+ className="w-full pl-8 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
+ />
+ </div>
+ <p className="text-xs text-muted-foreground">
+ Enter your available capital to find opportunities that match your budget
+ </p>
+ </div>
+
+ {/* Submit Buttons */}
+ <div className="space-y-3">
+ {/* Regular Analysis Button */}
+ <button
+ type="submit"
+ disabled={isLoading}
+ className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white font-semibold py-4 px-6 rounded-lg transition-all duration-200 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
+ >
+ {isLoading ? (
+ <>
+ <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
+ Analyzing...
+ </>
+ ) : (
+ <>
+ <Search className="h-5 w-5" />
+ {!location.trim() && !businessType.trim() ? 'Show Top 5 Trending Ideas' : 'Analyze Business Opportunity'}
+ </>
+ )}
+ </button>
+
+ {/* Find Opportunities Button */}
+ <button
+ type="button"
+ onClick={handleFindOpportunities}
+ disabled={isLoading}
+ className="w-full bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-700 hover:to-emerald-700 disabled:bg-gray-400 text-white font-semibold py-4 px-6 rounded-lg transition-all duration-200 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
+ >
+ <MapPin className="h-5 w-5" />
+ Find Top 10 Opportunities in My Area
+ </button>
+ </div>
+
+ {/* Top 5 Suggestions Modal */}
+ {showSuggestions && (
+ <div className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center p-4">
+ <div className="bg-white rounded-xl shadow-2xl max-w-3xl w-full max-h-[90vh] overflow-y-auto">
+ <div className="p-6 border-b sticky top-0 bg-white">
+ <h2 className="text-2xl font-bold text-gray-900">🔥 Top 5 Trending Business Ideas</h2>
+ <p className="text-sm text-gray-600 mt-1">Click any idea to analyze it, or close to enter your own</p>
+ </div>
+
+ <div className="p-6 space-y-4">
+ {topTrendingIdeas.map((idea, index) => (
+ <button
+ key={index}
+ onClick={() => handleSurprise(idea)}
+ className="w-full text-left p-5 border-2 border-gray-200 rounded-lg hover:border-blue-500 hover:bg-blue-50 transition-all duration-200 group"
+ >
+ <div className="flex items-start justify-between">
+ <div className="flex-1">
+ <div className="flex items-center gap-3 mb-2">
+ <span className="text-2xl font-bold text-blue-600 group-hover:scale-110 transition-transform">
+ #{index + 1}
+ </span>
+ <h3 className="text-lg font-bold text-gray-900">{idea.business}</h3>
+ </div>
+ <p className="text-sm text-gray-600 mb-2">{idea.description}</p>
+ <div className="flex items-center gap-2 text-sm text-gray-500">
+ <MapPin className="h-4 w-4" />
+ {idea.location}
+ </div>
+ </div>
+ <div className="ml-4 text-blue-600 group-hover:translate-x-1 transition-transform">
+ →
+ </div>
+ </div>
+ </button>
+ ))}
+ </div>
+
+ <div className="p-6 border-t bg-gray-50 flex gap-3">
+ <button
+ onClick={() => setShowSuggestions(false)}
+ className="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 font-semibold py-3 px-6 rounded-lg transition-all duration-200"
+ >
+ Close
+ </button>
+ <button
+ onClick={() => {
+ const randomIdea = topTrendingIdeas[Math.floor(Math.random() * topTrendingIdeas.length)]
+ handleSurprise(randomIdea)
+ }}
+ className="flex-1 bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 shadow-lg hover:shadow-xl"
+ >
+ 🎲 Surprise Me!
+ </button>
+ </div>
+ </div>
+ </div>
+ )}
+
+ {/* Help Text */}
+ <div className="bg-blue-50 border border-blue-200 rounded-lg p-4 text-sm">
+ <p className="font-medium text-blue-900 mb-1">How it works:</p>
+ <ol className="list-decimal list-inside space-y-1 text-blue-800">
+ <li>Enter your target location and business idea</li>
+ <li>AI analyzes local competitors, demographics, and market data</li>
+ <li>Get a comprehensive SWOT analysis with visualizations</li>
+ <li>Review action plan and income projections</li>
+ </ol>
+ </div>
+ </form>
+ </CardContent>
+ </Card>
+ )
+}
diff --git a/src/components/swot/SWOTChart.tsx b/src/components/swot/SWOTChart.tsx
new file mode 100644
index 0000000..5b5a8e7
--- /dev/null
+++ b/src/components/swot/SWOTChart.tsx
@@ -0,0 +1,209 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import { TrendingUp, TrendingDown, Target, AlertCircle } from 'lucide-react'
+import type { Strength, Weakness, Opportunity, Threat } from '@/types/swot'
+
+interface SWOTChartProps {
+ strengths: Strength[]
+ weaknesses: Weakness[]
+ opportunities: Opportunity[]
+ threats: Threat[]
+}
+
+export function SWOTChart({ strengths, weaknesses, opportunities, threats }: SWOTChartProps) {
+ const getImpactColor = (impact: 'low' | 'medium' | 'high') => {
+ switch (impact) {
+ case 'high':
+ return 'success'
+ case 'medium':
+ return 'warning'
+ case 'low':
+ return 'secondary'
+ }
+ }
+
+ return (
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
+ {/* Strengths */}
+ <Card className="border-green-200 bg-green-50/50">
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-green-700">
+ <TrendingUp className="h-5 w-5" />
+ Strengths
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-4">
+ {strengths.map((strength) => (
+ <div
+ key={strength.id}
+ className="bg-white p-4 rounded-lg border border-green-200"
+ >
+ <div className="flex items-start justify-between mb-2">
+ <h4 className="font-semibold text-sm">{strength.title}</h4>
+ <Badge variant={getImpactColor(strength.impact)}>
+ {strength.impact}
+ </Badge>
+ </div>
+ <p className="text-sm text-muted-foreground mb-2">
+ {strength.description}
+ </p>
+ <div className="flex items-center justify-between text-xs">
+ <span className="text-muted-foreground">
+ Category: {strength.category}
+ </span>
+ <span className="font-medium">
+ Confidence: {strength.confidence}%
+ </span>
+ </div>
+ </div>
+ ))}
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* Weaknesses */}
+ <Card className="border-red-200 bg-red-50/50">
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-red-700">
+ <TrendingDown className="h-5 w-5" />
+ Weaknesses
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-4">
+ {weaknesses.map((weakness) => (
+ <div
+ key={weakness.id}
+ className="bg-white p-4 rounded-lg border border-red-200"
+ >
+ <div className="flex items-start justify-between mb-2">
+ <h4 className="font-semibold text-sm">{weakness.title}</h4>
+ <Badge variant={getImpactColor(weakness.impact)}>
+ {weakness.impact}
+ </Badge>
+ </div>
+ <p className="text-sm text-muted-foreground mb-2">
+ {weakness.description}
+ </p>
+ {weakness.mitigationStrategy && (
+ <div className="bg-yellow-50 p-2 rounded text-xs mb-2">
+ <strong>Mitigation:</strong> {weakness.mitigationStrategy}
+ </div>
+ )}
+ <div className="flex items-center justify-between text-xs">
+ <span className="text-muted-foreground">
+ Category: {weakness.category}
+ </span>
+ <span className="font-medium">
+ Confidence: {weakness.confidence}%
+ </span>
+ </div>
+ </div>
+ ))}
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* Opportunities */}
+ <Card className="border-blue-200 bg-blue-50/50">
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-blue-700">
+ <Target className="h-5 w-5" />
+ Opportunities
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-4">
+ {opportunities.map((opportunity) => (
+ <div
+ key={opportunity.id}
+ className="bg-white p-4 rounded-lg border border-blue-200"
+ >
+ <div className="flex items-start justify-between mb-2">
+ <h4 className="font-semibold text-sm">{opportunity.title}</h4>
+ <Badge variant={getImpactColor(opportunity.impact)}>
+ {opportunity.impact}
+ </Badge>
+ </div>
+ <p className="text-sm text-muted-foreground mb-2">
+ {opportunity.description}
+ </p>
+ <div className="grid grid-cols-2 gap-2 text-xs">
+ <div>
+ <span className="text-muted-foreground">Timeframe:</span>
+ <span className="ml-1 font-medium">{opportunity.timeframe}</span>
+ </div>
+ <div>
+ <span className="text-muted-foreground">Feasibility:</span>
+ <span className="ml-1 font-medium">{opportunity.feasibility}%</span>
+ </div>
+ <div>
+ <span className="text-muted-foreground">Category:</span>
+ <span className="ml-1">{opportunity.category}</span>
+ </div>
+ <div>
+ <span className="text-muted-foreground">Confidence:</span>
+ <span className="ml-1 font-medium">{opportunity.confidence}%</span>
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* Threats */}
+ <Card className="border-orange-200 bg-orange-50/50">
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2 text-orange-700">
+ <AlertCircle className="h-5 w-5" />
+ Threats
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-4">
+ {threats.map((threat) => (
+ <div
+ key={threat.id}
+ className="bg-white p-4 rounded-lg border border-orange-200"
+ >
+ <div className="flex items-start justify-between mb-2">
+ <h4 className="font-semibold text-sm">{threat.title}</h4>
+ <Badge
+ variant={
+ threat.severity === 'critical'
+ ? 'destructive'
+ : getImpactColor(threat.impact)
+ }
+ >
+ {threat.severity}
+ </Badge>
+ </div>
+ <p className="text-sm text-muted-foreground mb-2">
+ {threat.description}
+ </p>
+ <div className="grid grid-cols-2 gap-2 text-xs">
+ <div>
+ <span className="text-muted-foreground">Category:</span>
+ <span className="ml-1">{threat.category}</span>
+ </div>
+ <div>
+ <span className="text-muted-foreground">Likelihood:</span>
+ <span className="ml-1 font-medium">{threat.likelihood}%</span>
+ </div>
+ <div className="col-span-2">
+ <span className="text-muted-foreground">Confidence:</span>
+ <span className="ml-1 font-medium">{threat.confidence}%</span>
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </CardContent>
+ </Card>
+ </div>
+ )
+}
diff --git a/src/components/swot/ScoreCard.tsx b/src/components/swot/ScoreCard.tsx
new file mode 100644
index 0000000..f28c8a8
--- /dev/null
+++ b/src/components/swot/ScoreCard.tsx
@@ -0,0 +1,108 @@
+'use client'
+
+import { CheckCircle, XCircle, AlertTriangle } from 'lucide-react'
+import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
+import type { SWOTAnalysis } from '@/types/swot'
+
+interface ScoreCardProps {
+ analysis: SWOTAnalysis
+}
+
+export function ScoreCard({ analysis }: ScoreCardProps) {
+ const getRecommendationIcon = () => {
+ switch (analysis.recommendation) {
+ case 'go':
+ return <CheckCircle className="h-24 w-24 text-green-500" />
+ case 'no-go':
+ return <XCircle className="h-24 w-24 text-red-500" />
+ case 'proceed-with-caution':
+ return <AlertTriangle className="h-24 w-24 text-yellow-500" />
+ }
+ }
+
+ const getRecommendationText = () => {
+ switch (analysis.recommendation) {
+ case 'go':
+ return 'GOOD BUSINESS IDEA'
+ case 'no-go':
+ return 'NOT A GOOD BUSINESS IDEA'
+ case 'proceed-with-caution':
+ return 'PROCEED WITH CAUTION'
+ }
+ }
+
+ const getRecommendationColor = () => {
+ switch (analysis.recommendation) {
+ case 'go':
+ return 'text-green-600 border-green-500'
+ case 'no-go':
+ return 'text-red-600 border-red-500'
+ case 'proceed-with-caution':
+ return 'text-yellow-600 border-yellow-500'
+ }
+ }
+
+ const getScoreColor = () => {
+ if (analysis.overallScore >= 70) return 'text-green-600'
+ if (analysis.overallScore >= 50) return 'text-yellow-600'
+ return 'text-red-600'
+ }
+
+ return (
+ <Card className={`border-4 ${getRecommendationColor()}`}>
+ <CardHeader className="text-center">
+ <div className="flex justify-center mb-4">
+ {getRecommendationIcon()}
+ </div>
+ <CardTitle className={`text-4xl font-bold ${getRecommendationColor()}`}>
+ {getRecommendationText()}
+ </CardTitle>
+ <CardDescription className="text-lg mt-2">
+ {analysis.businessName} - {analysis.businessType}
+ </CardDescription>
+ <div className="mt-4">
+ <div className={`text-6xl font-bold ${getScoreColor()}`}>
+ {analysis.overallScore}
+ </div>
+ <div className="text-sm text-muted-foreground mt-1">
+ Viability Score (out of 100)
+ </div>
+ </div>
+ </CardHeader>
+ <CardContent>
+ <div className="bg-muted/50 rounded-lg p-6">
+ <h4 className="font-semibold mb-2">Analysis Summary</h4>
+ <p className="text-sm leading-relaxed">
+ {analysis.recommendationReasoning}
+ </p>
+ </div>
+ <div className="grid grid-cols-4 gap-4 mt-6">
+ <div className="text-center">
+ <div className="text-2xl font-bold text-green-600">
+ {analysis.strengths.length}
+ </div>
+ <div className="text-xs text-muted-foreground">Strengths</div>
+ </div>
+ <div className="text-center">
+ <div className="text-2xl font-bold text-red-600">
+ {analysis.weaknesses.length}
+ </div>
+ <div className="text-xs text-muted-foreground">Weaknesses</div>
+ </div>
+ <div className="text-center">
+ <div className="text-2xl font-bold text-blue-600">
+ {analysis.opportunities.length}
+ </div>
+ <div className="text-xs text-muted-foreground">Opportunities</div>
+ </div>
+ <div className="text-center">
+ <div className="text-2xl font-bold text-orange-600">
+ {analysis.threats.length}
+ </div>
+ <div className="text-xs text-muted-foreground">Threats</div>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ )
+}
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
new file mode 100644
index 0000000..95d5579
--- /dev/null
+++ b/src/components/ui/badge.tsx
@@ -0,0 +1,39 @@
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+import { cn } from "@/lib/utils"
+
+const badgeVariants = cva(
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
+ secondary:
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ destructive:
+ "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
+ outline: "text-foreground",
+ success:
+ "border-transparent bg-green-500 text-white hover:bg-green-600",
+ warning:
+ "border-transparent bg-yellow-500 text-white hover:bg-yellow-600",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+export interface BadgeProps
+ extends React.HTMLAttributes<HTMLDivElement>,
+ VariantProps<typeof badgeVariants> {}
+
+function Badge({ className, variant, ...props }: BadgeProps) {
+ return (
+ <div className={cn(badgeVariants({ variant }), className)} {...props} />
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
new file mode 100644
index 0000000..c1da9be
--- /dev/null
+++ b/src/components/ui/card.tsx
@@ -0,0 +1,78 @@
+import * as React from "react"
+import { cn } from "@/lib/utils"
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes<HTMLDivElement>
+>(({ className, ...props }, ref) => (
+ <div
+ ref={ref}
+ className={cn(
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
+ className
+ )}
+ {...props}
+ />
+))
+Card.displayName = "Card"
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes<HTMLDivElement>
+>(({ className, ...props }, ref) => (
+ <div
+ ref={ref}
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
+ {...props}
+ />
+))
+CardHeader.displayName = "CardHeader"
+
+const CardTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes<HTMLHeadingElement>
+>(({ className, ...props }, ref) => (
+ <h3
+ ref={ref}
+ className={cn(
+ "text-2xl font-semibold leading-none tracking-tight",
+ className
+ )}
+ {...props}
+ />
+))
+CardTitle.displayName = "CardTitle"
+
+const CardDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes<HTMLParagraphElement>
+>(({ className, ...props }, ref) => (
+ <p
+ ref={ref}
+ className={cn("text-sm text-muted-foreground", className)}
+ {...props}
+ />
+))
+CardDescription.displayName = "CardDescription"
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes<HTMLDivElement>
+>(({ className, ...props }, ref) => (
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
+))
+CardContent.displayName = "CardContent"
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes<HTMLDivElement>
+>(({ className, ...props }, ref) => (
+ <div
+ ref={ref}
+ className={cn("flex items-center p-6 pt-0", className)}
+ {...props}
+ />
+))
+CardFooter.displayName = "CardFooter"
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
diff --git a/src/lib/ai-provider-multi.ts b/src/lib/ai-provider-multi.ts
new file mode 100644
index 0000000..d53a3ef
--- /dev/null
+++ b/src/lib/ai-provider-multi.ts
@@ -0,0 +1,320 @@
+import Anthropic from '@anthropic-ai/sdk'
+import { GoogleGenerativeAI } from '@google/generative-ai'
+import { HfInference } from '@huggingface/inference'
+
+/**
+ * Multi-provider AI system with automatic fallback
+ * Priority: Anthropic Claude > Google Gemini > Hugging Face (free)
+ */
+
+export interface AIResponse {
+ content: string
+ provider: 'anthropic' | 'gemini' | 'huggingface'
+ model?: string
+ tokensUsed?: number
+}
+
+export interface AIProviderStats {
+ provider: string
+ requestCount: number
+ totalTokens: number
+ lastError?: string
+ lastErrorTime?: Date
+}
+
+class MultiAIProviderManager {
+ private anthropic: Anthropic
+ private gemini: GoogleGenerativeAI
+ private hf: HfInference
+ private stats: Map<string, AIProviderStats> = new Map()
+
+ // Token tracking per minute
+ private tokenUsageWindow: { timestamp: number; tokens: number; provider: string }[] = []
+
+ // Thresholds
+ private readonly ANTHROPIC_TOKEN_LIMIT_PER_MINUTE = 4000
+ private readonly RATE_LIMIT_COOLDOWN_MS = 60000 // 1 minute
+
+ // Hugging Face models to try (in order of preference)
+ private readonly HF_MODELS = [
+ 'deepseek-ai/DeepSeek-R1:fireworks-ai', // DeepSeek R1 via Fireworks - high quality reasoning
+ 'mistralai/Mixtral-8x7B-Instruct-v0.1', // High quality, good for analysis
+ 'meta-llama/Meta-Llama-3-8B-Instruct', // Fast and reliable
+ 'microsoft/Phi-3-mini-4k-instruct', // Compact but capable
+ 'HuggingFaceH4/zephyr-7b-beta', // Good general purpose
+ ]
+
+ constructor() {
+ this.anthropic = new Anthropic({
+ apiKey: process.env.ANTHROPIC_API_KEY || '',
+ })
+
+ this.gemini = new GoogleGenerativeAI(
+ process.env.GOOGLE_API_KEY || ''
+ )
+
+ this.hf = new HfInference(
+ process.env.HUGGINGFACE_API_KEY || '' // Free tier works without key for many models
+ )
+
+ // Initialize stats
+ this.stats.set('anthropic', { provider: 'anthropic', requestCount: 0, totalTokens: 0 })
+ this.stats.set('gemini', { provider: 'gemini', requestCount: 0, totalTokens: 0 })
+ this.stats.set('huggingface', { provider: 'huggingface', requestCount: 0, totalTokens: 0 })
+ }
+
+ /**
+ * Track token usage in a rolling window
+ */
+ private trackTokenUsage(provider: string, tokens: number) {
+ const now = Date.now()
+ this.tokenUsageWindow.push({ timestamp: now, tokens, provider })
+
+ // Remove entries older than 1 minute
+ this.tokenUsageWindow = this.tokenUsageWindow.filter(
+ entry => now - entry.timestamp < 60000
+ )
+
+ // Update stats
+ const stats = this.stats.get(provider)
+ if (stats) {
+ stats.requestCount++
+ stats.totalTokens += tokens
+ this.stats.set(provider, stats)
+ }
+
+ console.log(`[AI Provider] ${provider} used ${tokens} tokens. Total in last minute: ${this.getTokensInLastMinute(provider)}`)
+ }
+
+ /**
+ * Get total tokens used in the last minute for a provider
+ */
+ private getTokensInLastMinute(provider: string): number {
+ const now = Date.now()
+ return this.tokenUsageWindow
+ .filter(entry => entry.provider === provider && now - entry.timestamp < 60000)
+ .reduce((sum, entry) => sum + entry.tokens, 0)
+ }
+
+ /**
+ * Check if a provider is currently rate limited
+ */
+ private isProviderRateLimited(provider: string): boolean {
+ const stats = this.stats.get(provider)
+ if (!stats?.lastError) return false
+
+ // Check if the last error was a rate limit and within cooldown period
+ if (stats.lastError.includes('rate_limit') ||
+ stats.lastError.includes('credit balance') ||
+ stats.lastError.includes('429') ||
+ stats.lastError.includes('quota')) {
+ const timeSinceError = stats.lastErrorTime ? Date.now() - stats.lastErrorTime.getTime() : Infinity
+ return timeSinceError < this.RATE_LIMIT_COOLDOWN_MS
+ }
+
+ return false
+ }
+
+ /**
+ * Check if we're approaching Anthropic's token limit
+ */
+ private isApproachingTokenLimit(): boolean {
+ const tokensUsed = this.getTokensInLastMinute('anthropic')
+ // Use 80% of limit as threshold
+ return tokensUsed >= this.ANTHROPIC_TOKEN_LIMIT_PER_MINUTE * 0.8
+ }
+
+ /**
+ * Determine which provider to use
+ * Priority: Anthropic (best quality) > Hugging Face (free) > Gemini (backup)
+ */
+ private selectProvider(): 'anthropic' | 'gemini' | 'huggingface' {
+ // Use Anthropic first (highest quality, API key is working)
+ if (!this.isProviderRateLimited('anthropic') && !this.isApproachingTokenLimit() && process.env.ANTHROPIC_API_KEY) {
+ console.log('[AI Provider] Using Anthropic (primary provider)')
+ return 'anthropic'
+ }
+
+ // Try Hugging Face second (free)
+ if (!this.isProviderRateLimited('huggingface')) {
+ console.log('[AI Provider] Using Hugging Face (Anthropic unavailable)')
+ return 'huggingface'
+ }
+
+ // Fallback to Gemini if configured
+ if (!this.isProviderRateLimited('gemini') && process.env.GOOGLE_API_KEY) {
+ console.log('[AI Provider] Using Gemini (other providers unavailable)')
+ return 'gemini'
+ }
+
+ // Last resort: try Anthropic anyway
+ console.log('[AI Provider] All providers rate limited, retrying Anthropic')
+ return 'anthropic'
+ }
+
+ /**
+ * Try Hugging Face with multiple models using chatCompletion API
+ */
+ private async tryHuggingFaceModels(prompt: string, maxTokens: number): Promise<AIResponse> {
+ let lastError: Error | null = null
+
+ for (const model of this.HF_MODELS) {
+ try {
+ console.log(`[AI Provider] Trying Hugging Face model: ${model}`)
+
+ const response = await this.hf.chatCompletion({
+ model,
+ messages: [{ role: 'user', content: prompt }],
+ max_tokens: maxTokens,
+ temperature: 0.7,
+ })
+
+ const content = response.choices?.[0]?.message?.content || ''
+ const estimatedTokens = Math.ceil(content.length / 4)
+
+ this.trackTokenUsage('huggingface', estimatedTokens)
+
+ return {
+ content,
+ provider: 'huggingface',
+ model,
+ tokensUsed: estimatedTokens,
+ }
+ } catch (error: any) {
+ console.log(`[AI Provider] HF model ${model} failed: ${error.message}`)
+ lastError = error
+ // Try next model
+ continue
+ }
+ }
+
+ throw lastError || new Error('All Hugging Face models failed')
+ }
+
+ /**
+ * Generate a completion using the best available provider
+ */
+ async generateCompletion(
+ prompt: string,
+ options: {
+ maxTokens?: number
+ temperature?: number
+ forceProvider?: 'anthropic' | 'gemini' | 'huggingface'
+ } = {}
+ ): Promise<AIResponse> {
+ const provider = options.forceProvider || this.selectProvider()
+ const maxTokens = options.maxTokens || 5000
+ const temperature = options.temperature || 1.0
+
+ try {
+ if (provider === 'anthropic') {
+ const message = await this.anthropic.messages.create({
+ model: 'claude-sonnet-4-5-20250929',
+ max_tokens: maxTokens,
+ temperature,
+ messages: [{ role: 'user', content: prompt }],
+ })
+
+ const content = message.content[0].type === 'text' ? message.content[0].text : ''
+ const tokensUsed = message.usage?.output_tokens || 0
+
+ this.trackTokenUsage('anthropic', tokensUsed)
+
+ return {
+ content,
+ provider: 'anthropic',
+ tokensUsed,
+ }
+ } else if (provider === 'gemini') {
+ const model = this.gemini.getGenerativeModel({
+ model: 'gemini-pro',
+ generationConfig: {
+ maxOutputTokens: maxTokens,
+ temperature,
+ },
+ })
+
+ const result = await model.generateContent(prompt)
+ const response = result.response
+ const content = response.text()
+
+ const estimatedTokens = Math.ceil(content.length / 4)
+ this.trackTokenUsage('gemini', estimatedTokens)
+
+ return {
+ content,
+ provider: 'gemini',
+ tokensUsed: estimatedTokens,
+ }
+ } else {
+ // Try Hugging Face with multiple models
+ return await this.tryHuggingFaceModels(prompt, maxTokens)
+ }
+ } catch (error: any) {
+ // Record error for rate limiting detection
+ const stats = this.stats.get(provider)
+ if (stats) {
+ stats.lastError = error?.message || String(error)
+ stats.lastErrorTime = new Date()
+ this.stats.set(provider, stats)
+ }
+
+ // If primary provider fails, try next in chain
+ if (!options.forceProvider) {
+ const errorMsg = error?.message || String(error)
+ console.log(`[AI Provider] ${provider} failed (${errorMsg}), trying fallback`)
+
+ // Anthropic failed -> try Hugging Face
+ if (provider === 'anthropic') {
+ return this.generateCompletion(prompt, { ...options, forceProvider: 'huggingface' })
+ }
+
+ // Hugging Face failed -> try Gemini if available, otherwise Anthropic
+ if (provider === 'huggingface') {
+ if (process.env.GOOGLE_API_KEY) {
+ return this.generateCompletion(prompt, { ...options, forceProvider: 'gemini' })
+ } else if (process.env.ANTHROPIC_API_KEY) {
+ return this.generateCompletion(prompt, { ...options, forceProvider: 'anthropic' })
+ }
+ }
+
+ // Gemini failed -> try Anthropic
+ if (provider === 'gemini') {
+ if (process.env.ANTHROPIC_API_KEY) {
+ return this.generateCompletion(prompt, { ...options, forceProvider: 'anthropic' })
+ }
+ }
+ }
+
+ throw error
+ }
+ }
+
+ /**
+ * Get current provider statistics
+ */
+ getStats(): Record<string, AIProviderStats> {
+ const result: Record<string, AIProviderStats> = {}
+ this.stats.forEach((value, key) => {
+ result[key] = { ...value }
+ })
+ return result
+ }
+
+ /**
+ * Reset statistics
+ */
+ resetStats() {
+ this.stats.forEach((value, key) => {
+ this.stats.set(key, {
+ provider: value.provider,
+ requestCount: 0,
+ totalTokens: 0,
+ })
+ })
+ this.tokenUsageWindow = []
+ }
+}
+
+// Export singleton instance
+export const aiProvider = new MultiAIProviderManager()
diff --git a/src/lib/ai-provider.ts b/src/lib/ai-provider.ts
new file mode 100644
index 0000000..709398d
--- /dev/null
+++ b/src/lib/ai-provider.ts
@@ -0,0 +1,249 @@
+import Anthropic from '@anthropic-ai/sdk'
+import { GoogleGenerativeAI } from '@google/generative-ai'
+import { mcpClient } from './mcp-client'
+
+/**
+ * Unified AI provider interface with automatic fallback
+ * Tracks token usage via MCP and switches to Gemini when needed
+ */
+
+export interface AIResponse {
+ content: string
+ provider: 'anthropic' | 'gemini'
+ tokensUsed?: number
+}
+
+export interface AIProviderStats {
+ provider: 'anthropic' | 'gemini'
+ requestCount: number
+ totalTokens: number
+ lastError?: string
+ lastErrorTime?: Date
+}
+
+class AIProviderManager {
+ private anthropic: Anthropic
+ private gemini: GoogleGenerativeAI
+ private stats: Map<string, AIProviderStats> = new Map()
+
+ // Token tracking per minute
+ private tokenUsageWindow: { timestamp: number; tokens: number; provider: string }[] = []
+
+ // Thresholds
+ private readonly ANTHROPIC_TOKEN_LIMIT_PER_MINUTE = 4000
+ private readonly RATE_LIMIT_COOLDOWN_MS = 60000 // 1 minute
+
+ constructor() {
+ this.anthropic = new Anthropic({
+ apiKey: process.env.ANTHROPIC_API_KEY || '',
+ })
+
+ this.gemini = new GoogleGenerativeAI(
+ process.env.GOOGLE_API_KEY || ''
+ )
+
+ // Initialize stats
+ this.stats.set('anthropic', {
+ provider: 'anthropic',
+ requestCount: 0,
+ totalTokens: 0,
+ })
+ this.stats.set('gemini', {
+ provider: 'gemini',
+ requestCount: 0,
+ totalTokens: 0,
+ })
+ }
+
+ /**
+ * Track token usage in a rolling window
+ */
+ private trackTokenUsage(provider: string, tokens: number) {
+ const now = Date.now()
+ this.tokenUsageWindow.push({ timestamp: now, tokens, provider })
+
+ // Remove entries older than 1 minute
+ this.tokenUsageWindow = this.tokenUsageWindow.filter(
+ entry => now - entry.timestamp < 60000
+ )
+
+ // Update stats
+ const stats = this.stats.get(provider)
+ if (stats) {
+ stats.requestCount++
+ stats.totalTokens += tokens
+ this.stats.set(provider, stats)
+ }
+
+ // Log to MCP for monitoring (optional - MCP doesn't have built-in monitoring)
+ console.log(`[AI Provider] ${provider} used ${tokens} tokens. Total in last minute: ${this.getTokensInLastMinute(provider)}`)
+ }
+
+ /**
+ * Get total tokens used in the last minute for a provider
+ */
+ private getTokensInLastMinute(provider: string): number {
+ const now = Date.now()
+ return this.tokenUsageWindow
+ .filter(entry => entry.provider === provider && now - entry.timestamp < 60000)
+ .reduce((sum, entry) => sum + entry.tokens, 0)
+ }
+
+ /**
+ * Check if Anthropic is currently rate limited
+ */
+ private isAnthropicRateLimited(): boolean {
+ const stats = this.stats.get('anthropic')
+ if (!stats?.lastError) return false
+
+ // Check if the last error was a rate limit and within cooldown period
+ if (stats.lastError.includes('rate_limit') || stats.lastError.includes('credit balance')) {
+ const timeSinceError = stats.lastErrorTime ? Date.now() - stats.lastErrorTime.getTime() : Infinity
+ return timeSinceError < this.RATE_LIMIT_COOLDOWN_MS
+ }
+
+ return false
+ }
+
+ /**
+ * Check if we're approaching Anthropic's token limit
+ */
+ private isApproachingTokenLimit(): boolean {
+ const tokensUsed = this.getTokensInLastMinute('anthropic')
+ // Use 80% of limit as threshold
+ return tokensUsed >= this.ANTHROPIC_TOKEN_LIMIT_PER_MINUTE * 0.8
+ }
+
+ /**
+ * Determine which provider to use
+ */
+ private selectProvider(): 'anthropic' | 'gemini' {
+ // Check if Anthropic is rate limited
+ if (this.isAnthropicRateLimited()) {
+ console.log('[AI Provider] Anthropic is rate limited, using Gemini')
+ return 'gemini'
+ }
+
+ // Check if approaching token limit
+ if (this.isApproachingTokenLimit()) {
+ console.log('[AI Provider] Approaching Anthropic token limit, using Gemini')
+ return 'gemini'
+ }
+
+ // Default to Anthropic (preferred for quality)
+ return 'anthropic'
+ }
+
+ /**
+ * Generate a completion using the best available provider
+ */
+ async generateCompletion(
+ prompt: string,
+ options: {
+ maxTokens?: number
+ temperature?: number
+ forceProvider?: 'anthropic' | 'gemini'
+ } = {}
+ ): Promise<AIResponse> {
+ const provider = options.forceProvider || this.selectProvider()
+ const maxTokens = options.maxTokens || 5000
+ const temperature = options.temperature || 1.0
+
+ try {
+ if (provider === 'anthropic') {
+ const message = await this.anthropic.messages.create({
+ model: 'claude-sonnet-4-5-20250929',
+ max_tokens: maxTokens,
+ temperature,
+ messages: [{ role: 'user', content: prompt }],
+ })
+
+ const content = message.content[0].type === 'text' ? message.content[0].text : ''
+ const tokensUsed = message.usage?.output_tokens || 0
+
+ this.trackTokenUsage('anthropic', tokensUsed)
+
+ return {
+ content,
+ provider: 'anthropic',
+ tokensUsed,
+ }
+ } else {
+ // Use Gemini as fallback
+ const model = this.gemini.getGenerativeModel({
+ model: 'gemini-1.5-pro',
+ generationConfig: {
+ maxOutputTokens: maxTokens,
+ temperature,
+ },
+ })
+
+ const result = await model.generateContent(prompt)
+ const response = result.response
+ const content = response.text()
+
+ // Gemini doesn't provide exact token usage in the same way
+ // Estimate: ~4 chars per token
+ const estimatedTokens = Math.ceil(content.length / 4)
+
+ this.trackTokenUsage('gemini', estimatedTokens)
+
+ return {
+ content,
+ provider: 'gemini',
+ tokensUsed: estimatedTokens,
+ }
+ }
+ } catch (error: any) {
+ // Record error for rate limiting detection
+ const stats = this.stats.get(provider)
+ if (stats) {
+ stats.lastError = error?.message || String(error)
+ stats.lastErrorTime = new Date()
+ this.stats.set(provider, stats)
+ }
+
+ // If Anthropic fails with rate limit or credit error, try Gemini
+ if (provider === 'anthropic' && !options.forceProvider) {
+ const errorMsg = error?.message || String(error)
+ if (errorMsg.includes('rate_limit') ||
+ errorMsg.includes('credit balance') ||
+ error?.status === 429 ||
+ error?.status === 400) {
+ console.log(`[AI Provider] Anthropic failed (${errorMsg}), falling back to Gemini`)
+ return this.generateCompletion(prompt, { ...options, forceProvider: 'gemini' })
+ }
+ }
+
+ throw error
+ }
+ }
+
+ /**
+ * Get current provider statistics
+ */
+ getStats(): Record<string, AIProviderStats> {
+ const result: Record<string, AIProviderStats> = {}
+ this.stats.forEach((value, key) => {
+ result[key] = { ...value }
+ })
+ return result
+ }
+
+ /**
+ * Reset statistics
+ */
+ resetStats() {
+ this.stats.forEach((value, key) => {
+ this.stats.set(key, {
+ provider: value.provider,
+ requestCount: 0,
+ totalTokens: 0,
+ })
+ })
+ this.tokenUsageWindow = []
+ }
+}
+
+// Export singleton instance
+export const aiProvider = new AIProviderManager()
diff --git a/src/lib/ai-workflows.ts b/src/lib/ai-workflows.ts
new file mode 100644
index 0000000..b86675e
--- /dev/null
+++ b/src/lib/ai-workflows.ts
@@ -0,0 +1,508 @@
+import JSON5 from 'json5'
+import { mcpClient } from './mcp-client'
+import { aiProvider } from './ai-provider-multi'
+import type { SWOTAnalysis, HistoricalContext, MarketAnalysis, StartupCosts } from '@/types/swot'
+
+/**
+ * AI Workflow for generating comprehensive SWOT analysis
+ */
+export class SWOTWorkflow {
+ /**
+ * Generate a complete SWOT analysis using Claude and MCP data
+ */
+ async generateAnalysis(
+ businessName: string,
+ businessType: string,
+ location: string
+ ): Promise<SWOTAnalysis> {
+ // Use Claude directly without MCP for now
+ const prompt = this.buildSWOTPromptSimple(
+ businessName,
+ businessType,
+ location
+ )
+
+ // Use multi-provider AI with automatic fallback
+ try {
+ const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 5000,
+ temperature: 1.0,
+ })
+
+ console.log(`[SWOT] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
+
+ return this.parseSWOTResponse(response.content, businessName, businessType, location)
+ } catch (error) {
+ console.error('[SWOT] Analysis generation failed:', error)
+ throw error
+ }
+ }
+
+ private buildSWOTPromptSimple(
+ businessName: string,
+ businessType: string,
+ location: string
+ ): string {
+ return `You are a business analyst conducting a comprehensive SWOT analysis for a new business venture.
+
+Business Details:
+- Name: ${businessName}
+- Type: ${businessType}
+- Location: ${location}
+
+Using your knowledge of business trends, local market conditions, demographics, and economic factors, please provide a detailed SWOT analysis in the following JSON format:
+
+{
+ "strengths": [
+ {
+ "title": "strength name",
+ "description": "detailed description",
+ "impact": "low|medium|high",
+ "confidence": 0-100,
+ "category": "competitive|financial|operational|market",
+ "sources": ["source references"]
+ }
+ ],
+ "weaknesses": [
+ {
+ "title": "weakness name",
+ "description": "detailed description",
+ "impact": "low|medium|high",
+ "confidence": 0-100,
+ "category": "cost|market|operational|regulatory",
+ "sources": ["source references"],
+ "mitigationStrategy": "how to address this weakness"
+ }
+ ],
+ "opportunities": [
+ {
+ "title": "opportunity name",
+ "description": "detailed description",
+ "impact": "low|medium|high",
+ "confidence": 0-100,
+ "category": "market|trend|technology|regulatory",
+ "timeframe": "immediate|short-term|medium-term|long-term",
+ "feasibility": 0-100,
+ "sources": ["source references"]
+ }
+ ],
+ "threats": [
+ {
+ "title": "threat name",
+ "description": "detailed description",
+ "impact": "low|medium|high",
+ "confidence": 0-100,
+ "category": "competitive|economic|regulatory|market",
+ "severity": "low|medium|high|critical",
+ "likelihood": 0-100,
+ "sources": ["source references"]
+ }
+ ],
+ "overallScore": 0-100,
+ "recommendation": "go|no-go|proceed-with-caution",
+ "recommendationReasoning": "detailed explanation"
+}
+
+IMPORTANT: Provide exactly 3-4 items for each SWOT category. Keep descriptions concise (under 25 words each). Return ONLY the JSON object, no additional text or markdown.`
+ }
+
+ private parseSWOTResponse(
+ response: string,
+ businessName: string,
+ businessType: string,
+ location: string
+ ): SWOTAnalysis {
+ try {
+ // Extract JSON from response (handling potential markdown formatting)
+ const jsonMatch = response.match(/\{[\s\S]*\}/)
+ if (!jsonMatch) {
+ throw new Error('No valid JSON found in response')
+ }
+
+ // Use JSON5 for more lenient parsing (handles trailing commas, etc.)
+ const parsed = JSON5.parse(jsonMatch[0])
+
+ // Add IDs and ensure all required fields
+ const addIds = (items: any[]) =>
+ items.map((item, index) => ({
+ ...item,
+ id: `${Date.now()}-${index}`,
+ }))
+
+ return {
+ businessName,
+ businessType,
+ location,
+ dateGenerated: new Date().toISOString(),
+ strengths: addIds(parsed.strengths || []),
+ weaknesses: addIds(parsed.weaknesses || []),
+ opportunities: addIds(parsed.opportunities || []),
+ threats: addIds(parsed.threats || []),
+ overallScore: parsed.overallScore || 50,
+ recommendation: parsed.recommendation || 'proceed-with-caution',
+ recommendationReasoning: parsed.recommendationReasoning || '',
+ }
+ } catch (error) {
+ console.error('Error parsing SWOT response:', error)
+ throw new Error('Failed to parse SWOT analysis response')
+ }
+ }
+}
+
+/**
+ * AI Workflow for generating historical context and trajectory analysis
+ */
+export class HistoricalWorkflow {
+ async generateHistoricalContext(location: string): Promise<HistoricalContext> {
+ // Use Claude to generate historical context directly
+ const prompt = `Create a comprehensive historical and economic context analysis for ${location}.
+
+Using your knowledge of the area, provide a concise JSON response with:
+1. A brief summary of the area's economic history (1-2 paragraphs, max 150 words)
+2. Exactly 5 key historical events that shaped the local economy
+3. 2-3 economic trajectory data points (population, employment, or business growth)
+
+IMPORTANT: Keep all text concise. Return ONLY the JSON object, no additional text
+
+Format:
+{
+ "summary": "historical summary text",
+ "keyEvents": [
+ {
+ "year": 1990,
+ "title": "event name",
+ "description": "event description",
+ "economicImpact": "positive|negative|neutral",
+ "relevance": 0-100
+ }
+ ],
+ "trajectories": [
+ {
+ "metric": "population",
+ "data": [{"year": 2000, "value": 50000}],
+ "trend": "increasing|decreasing|stable"
+ }
+ ]
+}`
+
+ // Use multi-provider AI with automatic fallback
+ try {
+ const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 3000,
+ temperature: 1.0,
+ })
+
+ console.log(`[Historical] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
+
+ const jsonMatch = response.content.match(/\{[\s\S]*\}/)
+ let parsed = {}
+ if (jsonMatch) {
+ try {
+ // Clean up common JSON issues
+ let jsonString = jsonMatch[0]
+ .replace(/,(\s*[}\]])/g, '$1') // Remove trailing commas
+ .replace(/\b(\d+)([a-zA-Z])/g, '$1 $2') // Fix numbers touching letters
+
+ // Use JSON5 for more lenient parsing
+ parsed = JSON5.parse(jsonString)
+ } catch (parseError) {
+ console.error('[Historical] JSON Parse Error:', parseError)
+ console.error('[Historical] Attempted to parse:', jsonMatch[0].substring(0, 500))
+ // Return empty structure instead of failing
+ parsed = {
+ summary: 'Historical context temporarily unavailable',
+ keyEvents: [],
+ trajectories: []
+ }
+ }
+ }
+
+ return {
+ areaName: location,
+ summary: (parsed as any).summary || 'Historical context temporarily unavailable',
+ keyEvents: (parsed as any).keyEvents || [],
+ trajectories: (parsed as any).trajectories || [],
+ }
+ } catch (error) {
+ console.error('Historical workflow failed:', error)
+ // Return fallback data instead of throwing
+ return {
+ areaName: location,
+ summary: 'Historical context temporarily unavailable',
+ keyEvents: [],
+ trajectories: []
+ }
+ }
+ }
+}
+
+/**
+ * AI Workflow for generating startup costs breakdown
+ */
+export class StartupCostsWorkflow {
+ async generateStartupCosts(
+ businessType: string,
+ location: string
+ ): Promise<StartupCosts> {
+ const prompt = `Create a detailed startup costs breakdown for a ${businessType} in ${location}.
+
+Provide a comprehensive JSON response with:
+1. One-time expenses including assets (equipment, furniture, technology, etc.) with purchase vs rental options
+2. Recurring monthly expenses
+3. Total startup capital required
+4. Monthly burn rate and runway estimate
+
+Format:
+{
+ "oneTimeExpenses": {
+ "assets": [
+ {
+ "name": "Commercial espresso machine",
+ "category": "equipment",
+ "purchasePrice": 15000,
+ "rentalRate": {"amount": 500, "period": "monthly"},
+ "isRental": false,
+ "quantity": 1,
+ "description": "Professional grade espresso machine",
+ "priority": "essential"
+ }
+ ],
+ "legalFees": 2000,
+ "permits": 1500,
+ "initialInventory": 5000,
+ "deposits": 10000,
+ "other": [{"description": "Initial marketing", "amount": 3000}]
+ },
+ "recurringExpenses": {
+ "rent": 4000,
+ "utilities": 500,
+ "insurance": 300,
+ "payroll": 8000,
+ "marketing": 1000,
+ "other": [{"description": "Supplies", "amount": 1500}]
+ },
+ "totalStartupCapital": 75000,
+ "monthlyBurnRate": 15300,
+ "runwayMonths": 12
+}
+
+IMPORTANT: Keep descriptions brief (under 20 words each). Include exactly 6-8 specific assets with realistic pricing for ${businessType} in ${location}.
+For each asset, determine if purchase or rental makes more sense and provide both options when applicable.
+Categories: equipment, furniture, technology, inventory, signage, renovation, other
+Priorities: essential, recommended, optional
+
+Return ONLY the JSON object, no additional text.`
+
+ // Use multi-provider AI with automatic fallback
+ try {
+ const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 5000,
+ temperature: 1.0,
+ })
+
+ console.log(`[Startup Costs] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
+
+ const jsonMatch = response.content.match(/\{[\s\S]*\}/)
+
+ if (!jsonMatch) {
+ throw new Error('Failed to parse startup costs response')
+ }
+
+ // Use JSON5 for more lenient parsing (handles trailing commas, comments, etc.)
+ let parsed
+ try {
+ parsed = JSON5.parse(jsonMatch[0])
+ } catch (parseError) {
+ console.error('JSON Parse Error:', parseError)
+ console.error('Attempted to parse:', jsonMatch[0].substring(0, 500) + '...')
+ throw new Error(`Failed to parse startup costs response: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`)
+ }
+
+ // Add IDs to assets
+ if (parsed.oneTimeExpenses && parsed.oneTimeExpenses.assets) {
+ parsed.oneTimeExpenses.assets = parsed.oneTimeExpenses.assets.map((asset: any, index: number) => ({
+ ...asset,
+ id: `asset-${Date.now()}-${index}`,
+ }))
+ }
+
+ return parsed as StartupCosts
+ } catch (error) {
+ console.error('[Startup Costs] Generation failed:', error)
+ throw error
+ }
+ }
+}
+
+/**
+ * AI Workflow for generating market analysis with competitors
+ */
+export class MarketAnalysisWorkflow {
+ async generateMarketAnalysis(
+ businessType: string,
+ location: string,
+ radiusMiles: number
+ ): Promise<MarketAnalysis> {
+ const prompt = `Create a comprehensive market analysis for a ${businessType} in ${location} within ${radiusMiles} mile radius.
+
+Provide detailed market data including:
+1. 5-8 real competitors in the area (mix of direct and indirect)
+2. Market size calculations (TAM, SAM, SOM)
+3. Demographics of target area
+4. 5-year income projections (optimistic, realistic, pessimistic scenarios)
+
+Format:
+{
+ "competitors": [
+ {
+ "name": "Business Name",
+ "type": "Coffee Shop|Restaurant|etc",
+ "distance": 1.5,
+ "yearEstablished": 2015,
+ "estimatedRevenue": 500000,
+ "rating": 4.5
+ }
+ ],
+ "marketSize": {
+ "totalAddressableMarket": 10000000,
+ "serviceableMarket": 3000000,
+ "targetMarket": 750000,
+ "marketSharePotential": 2.5,
+ "assumptions": [
+ "assumption 1",
+ "assumption 2"
+ ]
+ },
+ "demographics": {
+ "population": 50000,
+ "medianIncome": 75000,
+ "averageHouseholdSize": 2.5,
+ "targetDemographicPercentage": 65
+ },
+ "incomeProjections": [
+ {
+ "year": 1,
+ "optimistic": 400000,
+ "realistic": 280000,
+ "pessimistic": 150000,
+ "confidence": 75
+ }
+ ]
+}
+
+IMPORTANT:
+- Use realistic business names and data for ${location}
+- Include 5 years of projections with decreasing confidence over time
+- Provide 4-5 market size assumptions explaining your calculations
+- Return ONLY the JSON object, no additional text.`
+
+ try {
+ const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 5000,
+ temperature: 1.0,
+ })
+
+ console.log(`[Market Analysis] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
+
+ const jsonMatch = response.content.match(/\{[\s\S]*\}/)
+ if (!jsonMatch) {
+ throw new Error('Failed to parse market analysis response')
+ }
+
+ const parsed = JSON5.parse(jsonMatch[0])
+ return parsed as MarketAnalysis
+ } catch (error) {
+ console.error('[Market Analysis] Generation failed:', error)
+ throw error
+ }
+ }
+}
+
+/**
+ * AI Workflow for generating action plan
+ */
+export class ActionPlanWorkflow {
+ async generateActionPlan(
+ businessType: string,
+ location: string
+ ): Promise<Array<{
+ id: string
+ category: string
+ title: string
+ description: string
+ priority: string
+ estimatedCost?: number
+ estimatedTime: string
+ status: string
+ dependencies?: string[]
+ }>> {
+ const prompt = `Create a detailed action plan for launching a ${businessType} in ${location}.
+
+Provide 12-15 actionable steps covering:
+1. Domain registration and online presence
+2. Infrastructure setup (servers, tools, etc.)
+3. Market research and keyword analysis
+4. Marketing campaign setup
+5. Development/MVP creation
+6. Deployment and operations
+7. Legal and regulatory compliance
+8. Financial planning and funding
+
+Format:
+{
+ "actionItems": [
+ {
+ "category": "domain|infrastructure|research|marketing|development|legal|financial|operations",
+ "title": "Action title",
+ "description": "Detailed description of the action (under 30 words)",
+ "priority": "critical|high|medium|low",
+ "estimatedCost": 500,
+ "estimatedTime": "1 day|3 days|1 week|2 weeks|1 month",
+ "dependencies": ["id1", "id2"]
+ }
+ ]
+}
+
+IMPORTANT:
+- Make actions specific to ${businessType} and ${location}
+- Include realistic costs and timeframes
+- Order actions logically (dependencies first)
+- Keep descriptions concise and actionable
+- Return ONLY the JSON object, no additional text.`
+
+ try {
+ const response = await aiProvider.generateCompletion(prompt, {
+ maxTokens: 4000,
+ temperature: 1.0,
+ })
+
+ console.log(`[Action Plan] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
+
+ const jsonMatch = response.content.match(/\{[\s\S]*\}/)
+ if (!jsonMatch) {
+ throw new Error('Failed to parse action plan response')
+ }
+
+ const parsed = JSON5.parse(jsonMatch[0])
+
+ // Add IDs and status to each action item
+ const actionItems = (parsed.actionItems || []).map((item: any, index: number) => ({
+ ...item,
+ id: `action-${Date.now()}-${index}`,
+ status: 'not-started',
+ }))
+
+ return actionItems
+ } catch (error) {
+ console.error('[Action Plan] Generation failed:', error)
+ throw error
+ }
+ }
+}
+
+// Export workflow instances
+export const swotWorkflow = new SWOTWorkflow()
+export const historicalWorkflow = new HistoricalWorkflow()
+export const startupCostsWorkflow = new StartupCostsWorkflow()
+export const marketAnalysisWorkflow = new MarketAnalysisWorkflow()
+export const actionPlanWorkflow = new ActionPlanWorkflow()
diff --git a/src/lib/mcp-client.ts b/src/lib/mcp-client.ts
new file mode 100644
index 0000000..ee337b7
--- /dev/null
+++ b/src/lib/mcp-client.ts
@@ -0,0 +1,145 @@
+import { MCPSearchResult, MCPDocument } from '@/types/swot'
+
+// MCP Server Configuration
+interface MCPConfig {
+ serverUrl: string
+ apiKey?: string
+}
+
+// Default configuration - should be overridden via environment variables
+const defaultConfig: MCPConfig = {
+ serverUrl: process.env.MCP_SERVER_URL || 'http://localhost:8000',
+ apiKey: process.env.MCP_API_KEY,
+}
+
+/**
+ * MCP Client for interacting with the Model Context Protocol server
+ * Implements search and fetch tools for accessing local business data
+ */
+export class MCPClient {
+ private config: MCPConfig
+
+ constructor(config?: Partial<MCPConfig>) {
+ this.config = { ...defaultConfig, ...config }
+ }
+
+ /**
+ * Search the MCP vector store for relevant documents
+ * @param query - Search query string
+ * @param filters - Optional filters for search (e.g., document type, date range)
+ * @param limit - Maximum number of results to return
+ */
+ async search(
+ query: string,
+ filters?: {
+ documentType?: string[]
+ dateFrom?: string
+ dateTo?: string
+ location?: string
+ },
+ limit: number = 10
+ ): Promise<MCPSearchResult[]> {
+ try {
+ const response = await fetch(`${this.config.serverUrl}/search`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }),
+ },
+ body: JSON.stringify({ query, filters, limit }),
+ })
+
+ if (!response.ok) {
+ throw new Error(`MCP search failed: ${response.statusText}`)
+ }
+
+ const data = await response.json()
+ return data.results as MCPSearchResult[]
+ } catch (error) {
+ console.error('MCP search error:', error)
+ throw error
+ }
+ }
+
+ /**
+ * Fetch the full content of a document by ID
+ * @param documentId - The unique identifier of the document
+ */
+ async fetch(documentId: string): Promise<MCPDocument> {
+ try {
+ const response = await fetch(`${this.config.serverUrl}/fetch/${documentId}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }),
+ },
+ })
+
+ if (!response.ok) {
+ throw new Error(`MCP fetch failed: ${response.statusText}`)
+ }
+
+ const data = await response.json()
+ return data as MCPDocument
+ } catch (error) {
+ console.error('MCP fetch error:', error)
+ throw error
+ }
+ }
+
+ /**
+ * Search for competitors in a specific location and business category
+ */
+ async searchCompetitors(
+ businessType: string,
+ location: string,
+ radius: number = 10
+ ): Promise<MCPSearchResult[]> {
+ const query = `competitors ${businessType} near ${location} within ${radius} miles`
+ return this.search(query, {
+ documentType: ['business-directory', 'competitor-analysis'],
+ location,
+ })
+ }
+
+ /**
+ * Search for historical economic data about a location
+ */
+ async searchHistoricalData(location: string): Promise<MCPSearchResult[]> {
+ const query = `historical economic data ${location} population growth business development`
+ return this.search(query, {
+ documentType: ['historical-document', 'economic-report', 'census-data'],
+ location,
+ })
+ }
+
+ /**
+ * Search for market trends and opportunities
+ */
+ async searchMarketTrends(
+ businessType: string,
+ location: string
+ ): Promise<MCPSearchResult[]> {
+ const query = `market trends opportunities ${businessType} ${location}`
+ return this.search(query, {
+ documentType: ['market-report', 'trend-analysis', 'industry-report'],
+ })
+ }
+
+ /**
+ * Search for regulatory and zoning information
+ */
+ async searchRegulatory(
+ businessType: string,
+ location: string
+ ): Promise<MCPSearchResult[]> {
+ const query = `zoning regulations permits requirements ${businessType} ${location}`
+ return this.search(query, {
+ documentType: ['zoning-map', 'regulatory-document', 'permit-guide'],
+ location,
+ })
+ }
+}
+
+// Export singleton instance
+export const mcpClient = new MCPClient()
diff --git a/src/lib/mock-data.ts b/src/lib/mock-data.ts
new file mode 100644
index 0000000..e2155f0
--- /dev/null
+++ b/src/lib/mock-data.ts
@@ -0,0 +1,1149 @@
+import type { SWOTPlatformData } from '@/types/swot'
+
+// Mock data for demonstration purposes
+export const mockSWOTData: SWOTPlatformData = {
+ swotAnalysis: {
+ businessName: 'Artisan Coffee Roastery',
+ businessType: 'Specialty Coffee Shop & Roastery',
+ location: 'Downtown Portland, OR',
+ dateGenerated: new Date().toISOString(),
+ overallScore: 72,
+ recommendation: 'go',
+ recommendationReasoning:
+ 'The analysis reveals strong market fundamentals with high local demand for specialty coffee, limited direct competition in artisan roasting, and favorable demographic trends. While startup costs are significant and market saturation exists for standard coffee shops, the unique roasting angle and strong local coffee culture provide a competitive advantage. The area shows consistent economic growth and increasing household incomes, supporting premium product viability.',
+ strengths: [
+ {
+ id: '1',
+ title: 'Strong Local Coffee Culture',
+ description:
+ 'Portland has one of the highest per-capita coffee consumption rates in the US, with a sophisticated consumer base appreciating specialty roasting.',
+ impact: 'high',
+ confidence: 95,
+ category: 'market',
+ sources: ['Portland Business Journal', 'Local Market Survey 2024'],
+ },
+ {
+ id: '2',
+ title: 'Limited Artisan Roasting Competition',
+ description:
+ 'Only 2 direct competitors within 5-mile radius offering on-site roasting, creating differentiation opportunity.',
+ impact: 'high',
+ confidence: 88,
+ category: 'competitive',
+ sources: ['Business Directory Analysis', 'Competitor Research'],
+ },
+ {
+ id: '3',
+ title: 'High Median Household Income',
+ description:
+ 'Target area median income of $82,000 supports premium pricing strategy for specialty coffee products.',
+ impact: 'medium',
+ confidence: 92,
+ category: 'financial',
+ sources: ['US Census Data 2024', 'Portland Economic Development'],
+ },
+ {
+ id: '4',
+ title: 'Growing Downtown Foot Traffic',
+ description:
+ 'Recent office developments and residential projects have increased daily foot traffic by 23% year-over-year.',
+ impact: 'high',
+ confidence: 85,
+ category: 'market',
+ sources: ['Downtown Portland Alliance', 'Traffic Study 2024'],
+ },
+ ],
+ weaknesses: [
+ {
+ id: '1',
+ title: 'High Commercial Lease Rates',
+ description:
+ 'Downtown commercial real estate averages $45/sq ft, significantly above regional average of $28/sq ft.',
+ impact: 'high',
+ confidence: 90,
+ category: 'cost',
+ sources: ['Portland Real Estate Market Report'],
+ mitigationStrategy:
+ 'Consider shared roasting facility or smaller initial footprint with expansion plan.',
+ },
+ {
+ id: '2',
+ title: 'Saturated Standard Coffee Market',
+ description:
+ '18 coffee shops (non-roasting) within 2-mile radius creates challenging competitive environment.',
+ impact: 'medium',
+ confidence: 87,
+ category: 'market',
+ sources: ['Business Directory Analysis'],
+ mitigationStrategy:
+ 'Focus on roasting differentiation and wholesale B2B relationships to supplement retail.',
+ },
+ {
+ id: '3',
+ title: 'High Initial Equipment Investment',
+ description:
+ 'Commercial roasting equipment requires $75,000-$125,000 upfront investment before revenue generation.',
+ impact: 'high',
+ confidence: 95,
+ category: 'cost',
+ sources: ['Equipment Vendor Quotes', 'Industry Analysis'],
+ mitigationStrategy:
+ 'Explore equipment leasing or used equipment options to reduce initial capital requirement.',
+ },
+ ],
+ opportunities: [
+ {
+ id: '1',
+ title: 'Emerging Subscription Coffee Services',
+ description:
+ 'Online subscription models showing 34% annual growth, providing convenient access to specialty roasters nationwide.',
+ impact: 'medium',
+ confidence: 82,
+ category: 'trend',
+ timeframe: 'short-term',
+ feasibility: 85,
+ sources: ['Coffee Industry Trends Report 2024'],
+ },
+ {
+ id: '2',
+ title: 'Corporate Wholesale Partnerships',
+ description:
+ 'Local tech companies increasingly offering premium coffee as employee perk, creating B2B opportunity.',
+ impact: 'high',
+ confidence: 78,
+ category: 'market',
+ timeframe: 'immediate',
+ feasibility: 72,
+ sources: ['Portland Tech Industry Survey'],
+ },
+ {
+ id: '3',
+ title: 'Coffee Education Workshops',
+ description:
+ 'Growing interest in coffee education (cupping, brewing methods) creates additional revenue stream.',
+ impact: 'medium',
+ confidence: 75,
+ category: 'market',
+ timeframe: 'medium-term',
+ feasibility: 80,
+ sources: ['Consumer Interest Survey', 'Competitor Analysis'],
+ },
+ {
+ id: '4',
+ title: 'Sustainable/Ethical Sourcing Trend',
+ description:
+ 'Increasing consumer preference for ethically-sourced, sustainable coffee creates premium positioning opportunity.',
+ impact: 'high',
+ confidence: 88,
+ category: 'trend',
+ timeframe: 'immediate',
+ feasibility: 90,
+ sources: ['Consumer Behavior Study 2024', 'Industry Trends'],
+ },
+ ],
+ threats: [
+ {
+ id: '1',
+ title: 'Economic Downturn Impact',
+ description:
+ 'Potential recession could reduce discretionary spending on premium coffee products by 15-25%.',
+ impact: 'high',
+ confidence: 65,
+ category: 'economic',
+ severity: 'high',
+ likelihood: 45,
+ sources: ['Economic Forecast Q1 2025'],
+ },
+ {
+ id: '2',
+ title: 'Large Chain Expansion',
+ description:
+ 'Starbucks Reserve and Blue Bottle considering downtown locations, bringing significant competition.',
+ impact: 'high',
+ confidence: 70,
+ category: 'competitive',
+ severity: 'medium',
+ likelihood: 60,
+ sources: ['Industry News', 'Real Estate Filings'],
+ },
+ {
+ id: '3',
+ title: 'Supply Chain Volatility',
+ description:
+ 'Climate change affecting coffee-growing regions; price volatility and supply disruptions increasing.',
+ impact: 'medium',
+ confidence: 80,
+ category: 'market',
+ severity: 'medium',
+ likelihood: 75,
+ sources: ['Agricultural Reports', 'Coffee Commodity Analysis'],
+ },
+ ],
+ },
+ historicalContext: {
+ areaName: 'Downtown Portland, OR',
+ summary:
+ 'Portland\'s downtown core has evolved from a shipping and logging hub in the late 1800s to a diverse economic center. The area experienced significant growth during the tech boom of the 1990s-2000s, attracting major companies like Intel and Nike headquarters to the metro area.\n\nThe coffee culture in Portland dates back to the 1970s with the establishment of early specialty roasters. The city became known as a coffee destination in the 1990s, coinciding with the broader specialty coffee movement. Downtown specifically has seen waves of coffee shop openings, with peak growth in 2005-2008 and renewed growth from 2015-present.\n\nRecent developments include major residential and mixed-use projects that have increased the downtown population by 15% since 2015, creating a more vibrant street-level economy supportive of independent businesses.',
+ keyEvents: [
+ {
+ year: 1971,
+ title: 'Stumptown Coffee Roasters Founded',
+ description:
+ 'One of the pioneering specialty coffee roasters established in Portland, setting the foundation for the city\'s coffee culture.',
+ economicImpact: 'positive',
+ relevance: 85,
+ },
+ {
+ year: 1995,
+ title: 'Pearl District Redevelopment',
+ description:
+ 'Former industrial area transformed into mixed-use neighborhood, spurring downtown revitalization.',
+ economicImpact: 'positive',
+ relevance: 78,
+ },
+ {
+ year: 2008,
+ title: 'Financial Crisis Impact',
+ description:
+ 'Economic downturn led to closure of 25% of downtown restaurants and cafes, but specialty coffee showed resilience.',
+ economicImpact: 'negative',
+ relevance: 70,
+ },
+ {
+ year: 2015,
+ title: 'Tech Company Expansion',
+ description:
+ 'Major tech companies including Salesforce and Airbnb opened offices, bringing 5,000+ employees downtown.',
+ economicImpact: 'positive',
+ relevance: 92,
+ },
+ {
+ year: 2020,
+ title: 'COVID-19 Pandemic',
+ description:
+ 'Temporary shutdown and shift to remote work reduced downtown foot traffic by 60%, but recovery has been steady.',
+ economicImpact: 'negative',
+ relevance: 88,
+ },
+ {
+ year: 2023,
+ title: 'Return-to-Office Wave',
+ description:
+ 'Major employers implementing hybrid policies brought increased weekday traffic, approaching 85% of pre-pandemic levels.',
+ economicImpact: 'positive',
+ relevance: 95,
+ },
+ ],
+ trajectories: [
+ {
+ metric: 'population',
+ trend: 'increasing',
+ data: [
+ { year: 2015, value: 28500 },
+ { year: 2016, value: 29800 },
+ { year: 2017, value: 30900 },
+ { year: 2018, value: 31800 },
+ { year: 2019, value: 32700 },
+ { year: 2020, value: 31200 },
+ { year: 2021, value: 30800 },
+ { year: 2022, value: 32100 },
+ { year: 2023, value: 33500 },
+ { year: 2024, value: 34200 },
+ ],
+ forecast: [
+ { year: 2025, value: 35000, confidence: 85 },
+ { year: 2026, value: 36200, confidence: 75 },
+ { year: 2027, value: 37500, confidence: 65 },
+ ],
+ },
+ {
+ metric: 'median-income',
+ trend: 'increasing',
+ data: [
+ { year: 2015, value: 68000 },
+ { year: 2016, value: 70500 },
+ { year: 2017, value: 72800 },
+ { year: 2018, value: 75200 },
+ { year: 2019, value: 77500 },
+ { year: 2020, value: 78200 },
+ { year: 2021, value: 79800 },
+ { year: 2022, value: 81000 },
+ { year: 2023, value: 82000 },
+ { year: 2024, value: 82500 },
+ ],
+ },
+ {
+ metric: 'business-establishments',
+ trend: 'stable',
+ data: [
+ { year: 2015, value: 1250 },
+ { year: 2016, value: 1285 },
+ { year: 2017, value: 1320 },
+ { year: 2018, value: 1355 },
+ { year: 2019, value: 1390 },
+ { year: 2020, value: 1180 },
+ { year: 2021, value: 1220 },
+ { year: 2022, value: 1290 },
+ { year: 2023, value: 1340 },
+ { year: 2024, value: 1365 },
+ ],
+ },
+ ],
+ },
+ marketAnalysis: {
+ competitors: [
+ {
+ name: 'Heart Coffee Roasters',
+ type: 'Specialty Coffee Roastery',
+ distance: 0.8,
+ yearEstablished: 2009,
+ estimatedRevenue: 850000,
+ rating: 4.6,
+ },
+ {
+ name: 'Coava Coffee',
+ type: 'Specialty Coffee Roastery',
+ distance: 1.2,
+ yearEstablished: 2008,
+ estimatedRevenue: 1200000,
+ rating: 4.7,
+ },
+ {
+ name: 'Case Study Coffee',
+ type: 'Coffee Shop',
+ distance: 0.5,
+ yearEstablished: 2013,
+ rating: 4.5,
+ },
+ {
+ name: 'Stumptown Coffee - Downtown',
+ type: 'Coffee Shop Chain',
+ distance: 0.9,
+ yearEstablished: 1999,
+ estimatedRevenue: 2500000,
+ rating: 4.4,
+ },
+ {
+ name: 'Courier Coffee',
+ type: 'Coffee Shop',
+ distance: 1.5,
+ yearEstablished: 2005,
+ rating: 4.6,
+ },
+ {
+ name: 'Upper Left Roasters',
+ type: 'Specialty Coffee Roastery',
+ distance: 2.3,
+ yearEstablished: 2016,
+ estimatedRevenue: 450000,
+ rating: 4.8,
+ },
+ ],
+ marketSize: {
+ totalAddressableMarket: 12500000,
+ serviceableMarket: 4200000,
+ targetMarket: 850000,
+ marketSharePotential: 3.5,
+ assumptions: [
+ 'Downtown population of 34,200 with 85% coffee consumption rate',
+ 'Average spend of $8.50 per visit, 3.2 visits per week',
+ 'Capturing 12% of local market within 18 months',
+ 'Wholesale B2B accounts contributing 35% of revenue',
+ 'Average customer lifetime value of $2,400 over 3 years',
+ ],
+ },
+ demographics: {
+ population: 34200,
+ medianIncome: 82500,
+ averageHouseholdSize: 1.8,
+ targetDemographicPercentage: 68,
+ },
+ incomeProjections: [
+ {
+ year: 1,
+ optimistic: 450000,
+ realistic: 320000,
+ pessimistic: 180000,
+ confidence: 75,
+ },
+ {
+ year: 2,
+ optimistic: 720000,
+ realistic: 520000,
+ pessimistic: 350000,
+ confidence: 65,
+ },
+ {
+ year: 3,
+ optimistic: 950000,
+ realistic: 720000,
+ pessimistic: 480000,
+ confidence: 55,
+ },
+ {
+ year: 4,
+ optimistic: 1200000,
+ realistic: 920000,
+ pessimistic: 620000,
+ confidence: 45,
+ },
+ {
+ year: 5,
+ optimistic: 1450000,
+ realistic: 1100000,
+ pessimistic: 750000,
+ confidence: 40,
+ },
+ ],
+ },
+ actionPlan: [
+ {
+ id: '1',
+ category: 'domain',
+ title: 'Purchase Domain Name',
+ description:
+ 'Secure primary .com domain and relevant variations (.coffee, .shop) for brand protection.',
+ priority: 'high',
+ estimatedCost: 150,
+ estimatedTime: '1 day',
+ status: 'not-started',
+ },
+ {
+ id: '2',
+ category: 'infrastructure',
+ title: 'Set Up MCP Server',
+ description:
+ 'Deploy Model Context Protocol server using Python and FastMCP for data integration.',
+ priority: 'critical',
+ estimatedCost: 500,
+ estimatedTime: '1 week',
+ status: 'not-started',
+ },
+ {
+ id: '3',
+ category: 'research',
+ title: 'Google Keyword Cost Analysis',
+ description:
+ 'Research advertising costs for key search terms in local market to plan marketing budget.',
+ priority: 'high',
+ estimatedTime: '3 days',
+ status: 'not-started',
+ },
+ {
+ id: '4',
+ category: 'marketing',
+ title: 'Local Advertising Campaign Setup',
+ description:
+ 'Create targeted local advertising campaigns on Google and social media platforms.',
+ priority: 'medium',
+ estimatedCost: 2500,
+ estimatedTime: '2 weeks',
+ status: 'not-started',
+ dependencies: ['3'],
+ },
+ {
+ id: '5',
+ category: 'development',
+ title: 'Build Three Parallel MVP Versions',
+ description:
+ 'Use Codex to generate three distinct UI implementations for A/B testing and selection.',
+ priority: 'critical',
+ estimatedCost: 0,
+ estimatedTime: '30 minutes',
+ status: 'not-started',
+ },
+ {
+ id: '6',
+ category: 'infrastructure',
+ title: 'Vercel Deployment Setup',
+ description:
+ 'Configure CI/CD pipeline with Vercel for automated deployment and preview branches.',
+ priority: 'high',
+ estimatedCost: 20,
+ estimatedTime: '2 days',
+ status: 'not-started',
+ dependencies: ['5'],
+ },
+ {
+ id: '7',
+ category: 'research',
+ title: 'Economic Trajectory Data Integration',
+ description:
+ 'Integrate Google Charts and economic data sources to display area growth metrics.',
+ priority: 'medium',
+ estimatedTime: '1 week',
+ status: 'not-started',
+ dependencies: ['2'],
+ },
+ ],
+ startupCosts: {
+ oneTimeExpenses: {
+ assets: [],
+ legalFees: 0,
+ permits: 0,
+ initialInventory: 0,
+ deposits: 0,
+ other: [],
+ },
+ recurringExpenses: {
+ rent: 0,
+ utilities: 0,
+ insurance: 0,
+ payroll: 0,
+ marketing: 0,
+ other: [],
+ },
+ totalStartupCapital: 0,
+ monthlyBurnRate: 0,
+ runwayMonths: 0,
+ },
+}
+
+// SaaS Application SWOT Analysis
+export const mockSaaSSWOTData: SWOTPlatformData = {
+ swotAnalysis: {
+ businessName: 'CloudTask Pro',
+ businessType: 'B2B SaaS - Project Management Platform',
+ location: 'Remote/Cloud-based',
+ dateGenerated: new Date().toISOString(),
+ overallScore: 78,
+ recommendation: 'go',
+ recommendationReasoning:
+ 'The SaaS project management market shows strong fundamentals with recurring revenue potential, low marginal costs, and high scalability. While competition is intense from established players like Asana and Monday.com, there are underserved niches in specific verticals. The subscription model provides predictable revenue, and cloud infrastructure enables global reach without physical presence. Customer acquisition costs are manageable with proper targeting, and the potential for viral growth through freemium models is significant.',
+ strengths: [
+ {
+ id: '1',
+ title: 'Recurring Revenue Model',
+ description:
+ 'Subscription-based pricing generates predictable monthly recurring revenue (MRR) with high customer lifetime value and low churn in successful implementations.',
+ impact: 'high',
+ confidence: 95,
+ category: 'financial',
+ sources: ['SaaS Metrics Report 2024', 'Subscription Economy Analysis'],
+ },
+ {
+ id: '2',
+ title: 'Low Marginal Cost of Service',
+ description:
+ 'After initial development, serving additional customers incurs minimal incremental cost, enabling gross margins of 75-85% typical for mature SaaS products.',
+ impact: 'high',
+ confidence: 92,
+ category: 'financial',
+ sources: ['SaaS Financial Benchmarks', 'Cloud Economics Study'],
+ },
+ {
+ id: '3',
+ title: 'Global Market Accessibility',
+ description:
+ 'Cloud-based delivery enables instant global reach without physical infrastructure, accessing $300B+ global project management software market.',
+ impact: 'high',
+ confidence: 90,
+ category: 'market',
+ sources: ['Gartner Market Analysis', 'Global SaaS Trends 2024'],
+ },
+ {
+ id: '4',
+ title: 'Product-Led Growth Potential',
+ description:
+ 'Freemium model and viral features enable organic customer acquisition, reducing CAC by up to 60% compared to traditional sales models.',
+ impact: 'high',
+ confidence: 85,
+ category: 'operational',
+ sources: ['PLG Benchmarks', 'Freemium Conversion Studies'],
+ },
+ {
+ id: '5',
+ title: 'Data-Driven Iteration',
+ description:
+ 'Real-time usage analytics and A/B testing capabilities allow rapid product optimization and feature validation without traditional release cycles.',
+ impact: 'medium',
+ confidence: 88,
+ category: 'operational',
+ sources: ['Product Analytics Best Practices', 'SaaS Development Trends'],
+ },
+ ],
+ weaknesses: [
+ {
+ id: '1',
+ title: 'High Customer Acquisition Cost',
+ description:
+ 'SaaS marketing requires significant upfront investment with CAC often exceeding $400 per customer, requiring 12-18 months to recover costs.',
+ impact: 'high',
+ confidence: 90,
+ category: 'cost',
+ sources: ['SaaS CAC Benchmarks', 'B2B Marketing Cost Analysis'],
+ mitigationStrategy:
+ 'Focus on content marketing, SEO, and product-led growth to reduce paid acquisition dependency. Target higher-value enterprise customers with better LTV:CAC ratios.',
+ },
+ {
+ id: '2',
+ title: 'Intense Market Competition',
+ description:
+ 'Project management SaaS space has 200+ competitors including well-funded incumbents with established brand recognition and feature sets.',
+ impact: 'high',
+ confidence: 95,
+ category: 'market',
+ sources: ['Competitive Landscape Analysis', 'G2 Category Overview'],
+ mitigationStrategy:
+ 'Differentiate through vertical-specific solutions (e.g., construction, marketing agencies) rather than horizontal general-purpose tools.',
+ },
+ {
+ id: '3',
+ title: 'Technical Infrastructure Costs',
+ description:
+ 'Cloud hosting, security compliance (SOC 2, GDPR), and infrastructure monitoring require $15,000-$30,000 monthly investment before achieving scale.',
+ impact: 'medium',
+ confidence: 87,
+ category: 'cost',
+ sources: ['AWS Cost Analysis', 'SaaS Infrastructure Benchmarks'],
+ mitigationStrategy:
+ 'Leverage serverless architecture and modern PaaS solutions to reduce infrastructure overhead. Implement efficient database design and caching strategies.',
+ },
+ {
+ id: '4',
+ title: 'Churn Risk',
+ description:
+ 'Average SaaS churn rate of 5-7% monthly for SMB segment requires constant customer acquisition to maintain growth trajectory.',
+ impact: 'high',
+ confidence: 85,
+ category: 'operational',
+ sources: ['SaaS Churn Benchmarks 2024', 'Customer Retention Studies'],
+ mitigationStrategy:
+ 'Implement robust onboarding, customer success programs, and usage-based alerts to reduce churn. Focus on enterprise segment with <2% annual churn rates.',
+ },
+ ],
+ opportunities: [
+ {
+ id: '1',
+ title: 'AI Integration & Automation',
+ description:
+ 'Incorporating AI-powered task prioritization, automated scheduling, and predictive analytics creates strong differentiation as 78% of PM tools lack advanced AI features.',
+ impact: 'high',
+ confidence: 88,
+ category: 'technology',
+ timeframe: 'immediate',
+ feasibility: 85,
+ sources: ['AI in Project Management Report', 'Technology Adoption Trends'],
+ },
+ {
+ id: '2',
+ title: 'Vertical Market Specialization',
+ description:
+ 'Targeting underserved industries (construction, healthcare, legal) with tailored workflows and compliance features where generic tools fail to meet specific needs.',
+ impact: 'high',
+ confidence: 82,
+ category: 'market',
+ timeframe: 'short-term',
+ feasibility: 90,
+ sources: ['Industry-Specific Software Trends', 'Market Gap Analysis'],
+ },
+ {
+ id: '3',
+ title: 'API & Integration Marketplace',
+ description:
+ 'Building extensive integration ecosystem with 500+ tools creates network effects and increases switching costs, as 65% of teams use 10+ business tools.',
+ impact: 'medium',
+ confidence: 80,
+ category: 'technology',
+ timeframe: 'medium-term',
+ feasibility: 75,
+ sources: ['SaaS Integration Trends', 'Platform Strategy Research'],
+ },
+ {
+ id: '4',
+ title: 'Enterprise Expansion',
+ description:
+ 'Moving upmarket to enterprise customers with advanced security, custom workflows, and dedicated support enables 5-10x higher ARPU.',
+ impact: 'high',
+ confidence: 75,
+ category: 'market',
+ timeframe: 'medium-term',
+ feasibility: 70,
+ sources: ['Enterprise SaaS Benchmarks', 'Upmarket Strategy Analysis'],
+ },
+ {
+ id: '5',
+ title: 'Remote Work Acceleration',
+ description:
+ 'Continued hybrid/remote work adoption drives 15-20% annual growth in collaboration software market through 2027.',
+ impact: 'high',
+ confidence: 90,
+ category: 'trend',
+ timeframe: 'immediate',
+ feasibility: 95,
+ sources: ['Future of Work Report', 'Remote Collaboration Trends'],
+ },
+ ],
+ threats: [
+ {
+ id: '1',
+ title: 'Big Tech Platform Expansion',
+ description:
+ 'Microsoft, Google, and Atlassian continuously expanding project management features within existing suites (Teams, Workspace, Jira), leveraging massive user bases.',
+ impact: 'high',
+ confidence: 85,
+ category: 'competitive',
+ severity: 'high',
+ likelihood: 85,
+ sources: ['Tech Giant Product Roadmaps', 'Platform Strategy Analysis'],
+ },
+ {
+ id: '2',
+ title: 'Economic Downturn - SaaS Budget Cuts',
+ description:
+ 'During recessions, businesses scrutinize software subscriptions, leading to 20-30% increase in churn and extended sales cycles.',
+ impact: 'high',
+ confidence: 70,
+ category: 'economic',
+ severity: 'medium',
+ likelihood: 45,
+ sources: ['Economic Forecast 2025', 'SaaS Recession Impact Study'],
+ },
+ {
+ id: '3',
+ title: 'Data Privacy Regulations',
+ description:
+ 'Expanding global privacy laws (GDPR, CCPA, emerging regulations) require ongoing compliance investments and create operational complexity.',
+ impact: 'medium',
+ confidence: 90,
+ category: 'regulatory',
+ severity: 'medium',
+ likelihood: 95,
+ sources: ['Privacy Law Tracker', 'Compliance Cost Analysis'],
+ },
+ {
+ id: '4',
+ title: 'Commoditization of Features',
+ description:
+ 'Core project management features becoming table stakes, reducing differentiation and putting downward pressure on pricing.',
+ impact: 'medium',
+ confidence: 80,
+ category: 'market',
+ severity: 'medium',
+ likelihood: 70,
+ sources: ['Feature Parity Analysis', 'SaaS Pricing Trends'],
+ },
+ {
+ id: '5',
+ title: 'Security Breaches & Cyber Threats',
+ description:
+ 'Single security incident can cause catastrophic loss of customer trust and potential legal liability, with average breach cost of $4.5M.',
+ impact: 'high',
+ confidence: 75,
+ category: 'competitive',
+ severity: 'critical',
+ likelihood: 35,
+ sources: ['Cybersecurity Threat Report', 'Data Breach Cost Study'],
+ },
+ ],
+ },
+ historicalContext: {
+ areaName: 'Global SaaS Project Management Market',
+ summary:
+ 'The Software-as-a-Service (SaaS) model emerged in the early 2000s as broadband internet and cloud computing infrastructure matured. Salesforce pioneered enterprise SaaS in 1999, proving that mission-critical business software could be delivered via the web.\n\nProject management SaaS specifically gained momentum in the mid-2000s with Basecamp (2004) demonstrating product-led growth and Atlassian (2002) showing bottoms-up adoption could displace enterprise vendors. The 2008 financial crisis accelerated SaaS adoption as companies sought to reduce capital expenditure on IT infrastructure.\n\nThe 2010s saw explosive growth with Asana (2012), Trello (2011), and Monday.com (2014) reaching unicorn status. The COVID-19 pandemic in 2020 created unprecedented demand for remote collaboration tools, with the project management software market growing 35% in 2020-2021.\n\nToday\'s market is characterized by consolidation (Atlassian acquiring Trello), vertical specialization, and AI integration as key competitive factors.',
+ keyEvents: [
+ {
+ year: 1999,
+ title: 'Salesforce Launches - SaaS Pioneering',
+ description:
+ 'Salesforce.com introduces cloud-based CRM, proving viability of subscription software model and paving way for entire SaaS industry.',
+ economicImpact: 'positive',
+ relevance: 85,
+ },
+ {
+ year: 2004,
+ title: 'Basecamp Release',
+ description:
+ '37signals (now Basecamp) launches simple project management tool, demonstrating product-led growth and challenging enterprise complexity.',
+ economicImpact: 'positive',
+ relevance: 90,
+ },
+ {
+ year: 2008,
+ title: 'Financial Crisis Accelerates Cloud Adoption',
+ description:
+ 'Economic downturn drives companies to prefer OpEx (subscriptions) over CapEx (licenses), accelerating SaaS adoption by 40%.',
+ economicImpact: 'positive',
+ relevance: 88,
+ },
+ {
+ year: 2011,
+ title: 'Trello Launch - Kanban for Everyone',
+ description:
+ 'Fog Creek Software releases Trello, making visual project management accessible and viral through freemium model.',
+ economicImpact: 'positive',
+ relevance: 92,
+ },
+ {
+ year: 2012,
+ title: 'Asana Founded by Facebook Co-founder',
+ description:
+ 'Dustin Moskovitz launches Asana targeting team collaboration, bringing Silicon Valley product thinking to enterprise space.',
+ economicImpact: 'positive',
+ relevance: 88,
+ },
+ {
+ year: 2017,
+ title: 'Atlassian Acquires Trello for $425M',
+ description:
+ 'Major consolidation move signals market maturity and importance of capturing freemium users early.',
+ economicImpact: 'positive',
+ relevance: 85,
+ },
+ {
+ year: 2020,
+ title: 'COVID-19 Pandemic - Remote Work Surge',
+ description:
+ 'Forced remote work drives 350% increase in collaboration software adoption, with project management tools becoming mission-critical.',
+ economicImpact: 'positive',
+ relevance: 98,
+ },
+ {
+ year: 2021,
+ title: 'Monday.com IPO at $7B Valuation',
+ description:
+ 'Successful public offering demonstrates investor appetite for work management platforms and validates category.',
+ economicImpact: 'positive',
+ relevance: 90,
+ },
+ {
+ year: 2023,
+ title: 'AI Integration Wave',
+ description:
+ 'ChatGPT and generative AI breakthrough sparks race to integrate AI features into project management tools.',
+ economicImpact: 'positive',
+ relevance: 95,
+ },
+ ],
+ trajectories: [
+ {
+ metric: 'market-size',
+ trend: 'increasing',
+ data: [
+ { year: 2018, value: 4500000000 },
+ { year: 2019, value: 5200000000 },
+ { year: 2020, value: 7100000000 },
+ { year: 2021, value: 9500000000 },
+ { year: 2022, value: 11200000000 },
+ { year: 2023, value: 12800000000 },
+ { year: 2024, value: 14500000000 },
+ ],
+ forecast: [
+ { year: 2025, value: 16800000000, confidence: 85 },
+ { year: 2026, value: 19200000000, confidence: 75 },
+ { year: 2027, value: 22100000000, confidence: 65 },
+ ],
+ },
+ {
+ metric: 'average-arr-per-customer',
+ trend: 'increasing',
+ data: [
+ { year: 2018, value: 2400 },
+ { year: 2019, value: 2600 },
+ { year: 2020, value: 2900 },
+ { year: 2021, value: 3200 },
+ { year: 2022, value: 3600 },
+ { year: 2023, value: 4100 },
+ { year: 2024, value: 4500 },
+ ],
+ },
+ {
+ metric: 'saas-company-count',
+ trend: 'increasing',
+ data: [
+ { year: 2018, value: 8000 },
+ { year: 2019, value: 12000 },
+ { year: 2020, value: 15500 },
+ { year: 2021, value: 20000 },
+ { year: 2022, value: 25000 },
+ { year: 2023, value: 30000 },
+ { year: 2024, value: 34000 },
+ ],
+ },
+ ],
+ },
+ marketAnalysis: {
+ competitors: [
+ {
+ name: 'Asana',
+ type: 'Project Management SaaS',
+ distance: 0, // Global/Cloud
+ yearEstablished: 2012,
+ estimatedRevenue: 650000000,
+ rating: 4.4,
+ },
+ {
+ name: 'Monday.com',
+ type: 'Work OS Platform',
+ distance: 0,
+ yearEstablished: 2014,
+ estimatedRevenue: 900000000,
+ rating: 4.6,
+ },
+ {
+ name: 'ClickUp',
+ type: 'All-in-One Platform',
+ distance: 0,
+ yearEstablished: 2017,
+ estimatedRevenue: 150000000,
+ rating: 4.7,
+ },
+ {
+ name: 'Atlassian Jira',
+ type: 'Agile Project Management',
+ distance: 0,
+ yearEstablished: 2002,
+ estimatedRevenue: 3500000000,
+ rating: 4.3,
+ },
+ {
+ name: 'Notion',
+ type: 'Connected Workspace',
+ distance: 0,
+ yearEstablished: 2016,
+ estimatedRevenue: 200000000,
+ rating: 4.8,
+ },
+ {
+ name: 'Smartsheet',
+ type: 'Enterprise Work Management',
+ distance: 0,
+ yearEstablished: 2006,
+ estimatedRevenue: 750000000,
+ rating: 4.5,
+ },
+ ],
+ marketSize: {
+ totalAddressableMarket: 22000000000, // Global project management software market
+ serviceableMarket: 8500000000, // SMB and Mid-market segment
+ targetMarket: 450000000, // Specific vertical focus (e.g., creative agencies)
+ marketSharePotential: 2.5, // Realistic 2-3 years
+ assumptions: [
+ '450M businesses globally, 35% use project management software',
+ 'Target SMB segment ($10-500k ARR) representing $8.5B opportunity',
+ 'Focus on creative/marketing agencies (5% of SMB market)',
+ 'Average customer paying $3,600/year for 10-seat plan',
+ '2.5% market share achievable with strong vertical focus',
+ ],
+ },
+ demographics: {
+ population: 157000000, // Global SMB businesses
+ medianIncome: 450000, // Average SMB revenue
+ averageHouseholdSize: 12, // Average employees per SMB
+ targetDemographicPercentage: 35, // % using project mgmt software
+ },
+ incomeProjections: [
+ {
+ year: 1,
+ optimistic: 850000,
+ realistic: 480000,
+ pessimistic: 240000,
+ confidence: 70,
+ },
+ {
+ year: 2,
+ optimistic: 2400000,
+ realistic: 1500000,
+ pessimistic: 800000,
+ confidence: 60,
+ },
+ {
+ year: 3,
+ optimistic: 5200000,
+ realistic: 3500000,
+ pessimistic: 1900000,
+ confidence: 50,
+ },
+ {
+ year: 4,
+ optimistic: 9500000,
+ realistic: 6800000,
+ pessimistic: 3800000,
+ confidence: 40,
+ },
+ {
+ year: 5,
+ optimistic: 16000000,
+ realistic: 11500000,
+ pessimistic: 6500000,
+ confidence: 35,
+ },
+ ],
+ },
+ startupCosts: {
+ oneTimeExpenses: {
+ assets: [
+ {
+ id: '1',
+ name: 'Initial Product Development',
+ category: 'technology',
+ purchasePrice: 120000,
+ isRental: false,
+ quantity: 1,
+ description: 'MVP development (6 months, 2 engineers + 1 designer)',
+ priority: 'essential',
+ },
+ {
+ id: '2',
+ name: 'Brand & UI/UX Design',
+ category: 'other',
+ purchasePrice: 25000,
+ isRental: false,
+ quantity: 1,
+ description: 'Logo, brand guidelines, marketing site, product UI',
+ priority: 'essential',
+ },
+ {
+ id: '3',
+ name: 'Initial Marketing Campaign',
+ category: 'other',
+ purchasePrice: 35000,
+ isRental: false,
+ quantity: 1,
+ description: 'Launch campaign, content creation, initial ads',
+ priority: 'recommended',
+ },
+ ],
+ legalFees: 15000,
+ permits: 5000, // Business registration, trademarks
+ initialInventory: 0, // No physical inventory for SaaS
+ deposits: 0,
+ other: [
+ { description: 'Security audit and penetration testing', amount: 12000 },
+ { description: 'SOC 2 compliance initial setup', amount: 25000 },
+ ],
+ },
+ recurringExpenses: {
+ rent: 0, // Remote-first
+ utilities: 2000, // Internet, phone, collaboration tools
+ insurance: 3500, // E&O insurance, cyber liability
+ payroll: 45000, // Founders + 2 contractors monthly
+ marketing: 15000, // Monthly ad spend, content, SEO
+ other: [
+ { description: 'Cloud infrastructure (AWS/GCP)', amount: 8000 },
+ { description: 'SaaS tools stack (CRM, analytics, etc)', amount: 3500 },
+ { description: 'Customer support tools', amount: 1500 },
+ ],
+ },
+ totalStartupCapital: 237000,
+ monthlyBurnRate: 78500,
+ runwayMonths: 18, // With $1.5M seed funding
+ },
+ actionPlan: [
+ {
+ id: '1',
+ category: 'domain',
+ title: 'Secure Domain & Social Handles',
+ description:
+ 'Purchase .com domain, register trademark, secure social media handles across all platforms.',
+ priority: 'critical',
+ estimatedCost: 500,
+ estimatedTime: '2 days',
+ status: 'not-started',
+ },
+ {
+ id: '2',
+ category: 'development',
+ title: 'Build MVP Core Features',
+ description:
+ 'Develop essential features: user auth, project creation, task management, basic collaboration. Focus on speed to market.',
+ priority: 'critical',
+ estimatedCost: 120000,
+ estimatedTime: '16 weeks',
+ status: 'not-started',
+ },
+ {
+ id: '3',
+ category: 'infrastructure',
+ title: 'Set Up Cloud Infrastructure',
+ description:
+ 'Configure production environment on AWS/GCP with auto-scaling, monitoring, backup, and disaster recovery.',
+ priority: 'critical',
+ estimatedCost: 8000,
+ estimatedTime: '2 weeks',
+ status: 'not-started',
+ dependencies: ['2'],
+ },
+ {
+ id: '4',
+ category: 'research',
+ title: 'Define Ideal Customer Profile (ICP)',
+ description:
+ 'Conduct customer interviews, analyze competitor users, define specific vertical and company size to target.',
+ priority: 'critical',
+ estimatedTime: '3 weeks',
+ status: 'not-started',
+ },
+ {
+ id: '5',
+ category: 'marketing',
+ title: 'Build Content Marketing Engine',
+ description:
+ 'Create SEO-optimized blog, video tutorials, comparison pages targeting high-intent keywords.',
+ priority: 'high',
+ estimatedCost: 15000,
+ estimatedTime: '8 weeks',
+ status: 'not-started',
+ dependencies: ['4'],
+ },
+ {
+ id: '6',
+ category: 'development',
+ title: 'Implement Analytics & Tracking',
+ description:
+ 'Set up product analytics (Mixpanel/Amplitude), error tracking (Sentry), user session recording.',
+ priority: 'high',
+ estimatedCost: 3500,
+ estimatedTime: '1 week',
+ status: 'not-started',
+ dependencies: ['2'],
+ },
+ {
+ id: '7',
+ category: 'infrastructure',
+ title: 'Security & Compliance Setup',
+ description:
+ 'Implement security best practices, begin SOC 2 compliance process, conduct penetration testing.',
+ priority: 'high',
+ estimatedCost: 37000,
+ estimatedTime: '12 weeks',
+ status: 'not-started',
+ dependencies: ['3'],
+ },
+ {
+ id: '8',
+ category: 'marketing',
+ title: 'Launch Beta Program',
+ description:
+ 'Recruit 50-100 beta users, collect feedback, iterate on core features before public launch.',
+ priority: 'critical',
+ estimatedTime: '8 weeks',
+ status: 'not-started',
+ dependencies: ['2', '6'],
+ },
+ {
+ id: '9',
+ category: 'development',
+ title: 'Build Integration Ecosystem',
+ description:
+ 'Develop key integrations (Slack, Google Workspace, Microsoft Teams, Zapier) to increase stickiness.',
+ priority: 'medium',
+ estimatedCost: 45000,
+ estimatedTime: '12 weeks',
+ status: 'not-started',
+ dependencies: ['2'],
+ },
+ {
+ id: '10',
+ category: 'marketing',
+ title: 'Paid Acquisition Campaigns',
+ description:
+ 'Launch targeted Google Ads and LinkedIn campaigns focused on ICP with clear attribution tracking.',
+ priority: 'medium',
+ estimatedCost: 25000,
+ estimatedTime: 'Ongoing',
+ status: 'not-started',
+ dependencies: ['4', '8'],
+ },
+ ],
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..d084cca
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/src/types/swot.ts b/src/types/swot.ts
new file mode 100644
index 0000000..d3e5c48
--- /dev/null
+++ b/src/types/swot.ts
@@ -0,0 +1,193 @@
+// Core SWOT Analysis Types
+export interface SWOTElement {
+ id: string
+ title: string
+ description: string
+ impact: 'low' | 'medium' | 'high'
+ confidence: number // 0-100
+ sources: string[]
+}
+
+export interface Strength extends SWOTElement {
+ category: 'competitive' | 'financial' | 'operational' | 'market'
+}
+
+export interface Weakness extends SWOTElement {
+ category: 'cost' | 'market' | 'operational' | 'regulatory'
+ mitigationStrategy?: string
+}
+
+export interface Opportunity extends SWOTElement {
+ category: 'market' | 'trend' | 'technology' | 'regulatory'
+ timeframe: 'immediate' | 'short-term' | 'medium-term' | 'long-term'
+ feasibility: number // 0-100
+}
+
+export interface Threat extends SWOTElement {
+ category: 'competitive' | 'economic' | 'regulatory' | 'market'
+ severity: 'low' | 'medium' | 'high' | 'critical'
+ likelihood: number // 0-100
+}
+
+export interface SWOTAnalysis {
+ businessName: string
+ businessType: string
+ location: string
+ dateGenerated: string
+ strengths: Strength[]
+ weaknesses: Weakness[]
+ opportunities: Opportunity[]
+ threats: Threat[]
+ overallScore: number // 0-100
+ recommendation: 'go' | 'no-go' | 'proceed-with-caution'
+ recommendationReasoning: string
+}
+
+// Historical Context Types
+export interface HistoricalEvent {
+ year: number
+ title: string
+ description: string
+ economicImpact: 'positive' | 'negative' | 'neutral'
+ relevance: number // 0-100
+}
+
+export interface AreaTrajectory {
+ metric: string
+ data: {
+ year: number
+ value: number
+ }[]
+ trend: 'increasing' | 'decreasing' | 'stable'
+ forecast?: {
+ year: number
+ value: number
+ confidence: number
+ }[]
+}
+
+export interface HistoricalContext {
+ areaName: string
+ summary: string
+ keyEvents: HistoricalEvent[]
+ trajectories: AreaTrajectory[]
+}
+
+// Market Analysis Types
+export interface CompetitorData {
+ name: string
+ type: string
+ distance: number // in miles
+ yearEstablished?: number
+ estimatedRevenue?: number
+ rating?: number
+}
+
+export interface MarketSize {
+ totalAddressableMarket: number
+ serviceableMarket: number
+ targetMarket: number
+ marketSharePotential: number // percentage
+ assumptions: string[]
+}
+
+export interface IncomeProjection {
+ year: number
+ optimistic: number
+ realistic: number
+ pessimistic: number
+ confidence: number
+}
+
+export interface MarketAnalysis {
+ competitors: CompetitorData[]
+ marketSize: MarketSize
+ incomeProjections: IncomeProjection[]
+ demographics: {
+ population: number
+ medianIncome: number
+ averageHouseholdSize: number
+ targetDemographicPercentage: number
+ }
+}
+
+// MCP Integration Types
+export interface MCPSearchResult {
+ id: string
+ title: string
+ snippet: string
+ relevance: number
+ source: string
+ datePublished?: string
+}
+
+export interface MCPDocument {
+ id: string
+ content: string
+ metadata: {
+ source: string
+ datePublished?: string
+ author?: string
+ documentType: string
+ }
+}
+
+// Startup Capital Types
+export interface AssetItem {
+ id: string
+ name: string
+ category: 'equipment' | 'furniture' | 'technology' | 'inventory' | 'signage' | 'renovation' | 'other'
+ purchasePrice?: number
+ rentalRate?: {
+ amount: number
+ period: 'monthly' | 'yearly'
+ }
+ isRental: boolean
+ quantity: number
+ description: string
+ priority: 'essential' | 'recommended' | 'optional'
+}
+
+export interface StartupCosts {
+ oneTimeExpenses: {
+ assets: AssetItem[]
+ legalFees: number
+ permits: number
+ initialInventory: number
+ deposits: number
+ other: { description: string; amount: number }[]
+ }
+ recurringExpenses: {
+ rent: number
+ utilities: number
+ insurance: number
+ payroll: number
+ marketing: number
+ other: { description: string; amount: number }[]
+ }
+ totalStartupCapital: number
+ monthlyBurnRate: number
+ runwayMonths: number
+}
+
+// Action Plan Types
+export interface ActionItem {
+ id: string
+ category: 'domain' | 'infrastructure' | 'marketing' | 'research' | 'development'
+ title: string
+ description: string
+ priority: 'low' | 'medium' | 'high' | 'critical'
+ estimatedCost?: number
+ estimatedTime?: string
+ status: 'not-started' | 'in-progress' | 'completed'
+ dependencies?: string[]
+}
+
+// Complete Platform State
+export interface SWOTPlatformData {
+ swotAnalysis: SWOTAnalysis
+ historicalContext: HistoricalContext
+ marketAnalysis: MarketAnalysis
+ startupCosts: StartupCosts
+ actionPlan: ActionItem[]
+}
diff --git a/tailwind.config.ts b/tailwind.config.ts
new file mode 100644
index 0000000..c3225b4
--- /dev/null
+++ b/tailwind.config.ts
@@ -0,0 +1,80 @@
+import type { Config } from "tailwindcss"
+
+const config = {
+ darkMode: ["class"],
+ content: [
+ './pages/**/*.{ts,tsx}',
+ './components/**/*.{ts,tsx}',
+ './app/**/*.{ts,tsx}',
+ './src/**/*.{ts,tsx}',
+ ],
+ prefix: "",
+ theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
+ extend: {
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ "accordion-down": {
+ from: { height: "0" },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: "0" },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ },
+ },
+ },
+ plugins: [require("tailwindcss-animate")],
+} satisfies Config
+
+export default config
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..d7e05e5
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}
(oldest)
·
back to Goodquestion
·
Update Claude model IDs to claude-opus-4-8 (Opus 4.8 upgrade 9365f2a →