diff --git a/.env.example b/.env.example index a598ba7..9b5423c 100644 --- a/.env.example +++ b/.env.example @@ -1,24 +1,24 @@ -# OpenAI Configuration -OPENAI_API_KEY= - -# Embedding Model -EMBEDDING_MODEL=text-embedding-3-small - -# Chat Model -CHAT_MODEL=gpt-4-turbo-preview - -# RAG Configuration -MAX_CHUNKS=5 -SIMILARITY_THRESHOLD=0.7 - -# Chroma Vector Database -CHROMA_HOST=localhost -CHROMA_PORT=8000 -CHROMA_COLLECTION=legal_docs - -# Server Configuration -PORT=3000 -HOST=0.0.0.0 - -# Web Configuration (Next.js) - URL of the RAG API for the frontend -NEXT_PUBLIC_API_URL=http://localhost:3000 +# OpenAI Configuration +OPENAI_API_KEY= + +# Embedding Model +EMBEDDING_MODEL=text-embedding-3-small + +# Chat Model +CHAT_MODEL=gpt-4-turbo-preview + +# RAG Configuration +MAX_CHUNKS=5 +SIMILARITY_THRESHOLD=0.7 + +# Chroma Vector Database +CHROMA_HOST=localhost +CHROMA_PORT=8000 +CHROMA_COLLECTION=legal_docs + +# Server Configuration +PORT=3000 +HOST=0.0.0.0 + +# Web Configuration (Next.js) - URL of the RAG API for the frontend +NEXT_PUBLIC_API_URL=http://localhost:3000 diff --git a/CLAUDE.md b/CLAUDE.md index fedf9ae..de367c7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,138 +1,278 @@ -# CLAUDE.md - -This file provides guidance to Claude Code when working with this repository. - -## Project Overview - -**LlarJove** is a RAG-powered chatbot to help young people (18-35) in Catalunya find housing. It provides information about public aids, tenant rights, and connects users with active programs. - -**Target audience**: Young Catalans looking for housing assistance -**Geographic scope**: Catalunya (pilot), expandable -**Tone**: Accessible, friendly, practical - not legal jargon - -**Architecture**: Monorepo with backend (Node.js + Fastify + RAG) and frontend (React 19 + Vite 6 + Tailwind v4) in separate directories. - -## Commands - -### Backend (API + RAG) -```bash -# Development -pnpm dev # Start server with hot reload (tsx watch) -pnpm build # Compile TypeScript to dist/ - -# Testing -pnpm test # Run backend tests -pnpm test:watch # Watch mode - -# Data ingestion -docker compose up -d chroma # Start vector database -pnpm ingest # Ingest documents into Chroma -pnpm ingest --clear # Clear and re-ingest -``` - -### Frontend (React) -```bash -# Development -pnpm dev:web # Start dev server (http://localhost:5173) -pnpm build:web # Production build - -# Testing -pnpm test:web # Run frontend tests (59 tests with vitest) -``` - -## Architecture - -### Frontend (`web/`) - -**Stack**: React 19 + Vite 6 + TypeScript + Tailwind CSS v4 - -**Structure**: -- `src/components/ui/`: 5 reusable components (Button, Card, Input, Badge, Link) -- `src/components/BrandShowcase.tsx`: Living style guide -- `src/styles/`: Design tokens (colors, typography, spacing) -- `src/lib/`: Utilities (cn for className merging) - -**Design System**: -- **Tokens**: OKLCH colors, Geist font, semantic spacing/radii -- **Pattern**: shadcn/ui approach (`:root` CSS vars + `@theme inline`) -- **Testing**: 59 tests with vitest + jsdom + React Testing Library -- **Accessibility**: WCAG 2.1 touch targets (44px), focus-visible rings - -### Backend RAG Pipeline (`src/rag.ts`) - -``` -Question → buildStandaloneQuestion() → generateEmbedding() - → queryChunks() → rerank() → filterByThreshold() - → buildPrompt() → OpenAI completion - → buildValidatedResponse() → addWarningsIfNeeded() -``` - -**Module Responsibilities**: -- **ingestion/**: Document loading, semantic chunking, OpenAI embeddings -- **retrieval/**: Chroma vector store operations, keyword-based reranking -- **generation/**: Prompt construction, response validation -- **api/**: Fastify endpoints (`/chat`, `/resources`, `/health`) -- **resources/**: Active programs database with deadlines - -### Key Design Patterns - -1. **Semantic chunking**: Documents split by sections (requisitos, plazos, documentación) preserving structure for aid programs. Different from legal article chunking. - -2. **Deadline awareness**: System knows about active/closed programs and warns about upcoming deadlines. - -3. **Practical responses**: Include concrete steps, required documents, and direct links when available. - -4. **Bilingual support**: Content in Catalan/Spanish, responses adapt to user's language. - -## Content Types - -| Type | Chunking Strategy | Metadata | -|------|-------------------|----------| -| Aid programs | By section (requisitos, plazos, docs) | program_name, deadline, amount | -| Tenant rights | By topic/article | law_reference, topic | -| Guides | By step/section | guide_type, difficulty | - -## Environment Variables - -Required: `OPENAI_API_KEY` - -RAG tuning: `MAX_CHUNKS` (default 5), `SIMILARITY_THRESHOLD` (default 0.7) - -## Adding New Content - -1. Add document to `data/` (appropriate subfolder) -2. Document source in `data/SOURCES.md` -3. Run `pnpm ingest` - -## Data Sources - -See `data/SOURCES.md` for complete list of official sources: -- Generalitat de Catalunya - Agència de l'Habitatge -- Bono Alquiler Joven (estatal) -- Ajuntament de Barcelona -- LAU (tenant rights) - -## Frontend Development - -### Component Pattern - -All UI components follow this structure: -- Props extend native HTML attributes (`ButtonHTMLAttributes`, etc.) -- Use `forwardRef` for ref forwarding -- Variants defined as `Record` of Tailwind classes -- `cn()` utility merges class names and resolves Tailwind conflicts -- Comprehensive tests covering variants, states, accessibility - -### Adding New Components - -1. Create `ComponentName.tsx` in `web/src/components/ui/` -2. Create `ComponentName.test.tsx` with full coverage -3. Export from `web/src/components/ui/index.ts` -4. Add to BrandShowcase for visual reference - -### Design Tokens - -Located in `web/src/styles/tokens.css`. To modify: -1. Update `:root` CSS variables -2. Ensure `@theme inline` mapping exists -3. Tailwind utilities auto-update (no rebuild needed for runtime changes) +# CLAUDE.md + +This file provides guidance to Claude Code when working with this repository. + +## Project Overview + +**LlarJove** is a RAG-powered chatbot to help young people (18-35) in Catalunya find housing. It provides information about public aids, tenant rights, and connects users with active programs. + +- **Target audience**: Young Catalans (18-35) looking for housing assistance +- **Geographic scope**: Catalunya (pilot), expandable +- **Tone**: Accessible, friendly, practical - not legal jargon +- **Languages**: Catalan (primary) and Spanish. Responses adapt to user's language. + +### Architecture + +Monorepo with two independently deployed services: + +| Service | Stack | Port (dev) | Dockerfile | Railway config | +|---------|-------|------------|------------|----------------| +| Backend (API + RAG) | Node.js + Fastify + OpenAI | 3000 | `Dockerfile` | `railway-api.toml` | +| Frontend (Landing) | Next.js 15 + React 19 + Tailwind v4 | 3001 | `Dockerfile.web` | `railway-web.toml` | + +### Production URLs + +- **Web (landing)**: `https://llarjove-production.up.railway.app` +- **RAG API / Chat**: `https://llarjove-production-754a.up.railway.app` +- The web's `/chat` route redirects to the RAG API via `CHAT_REDIRECT_URL` env var (runtime, not build-time). + +## Commands + +### Backend (API + RAG) +```bash +pnpm dev # Start server with hot reload (tsx watch) → :3000 +pnpm build # Compile TypeScript to dist/ +pnpm test # Run backend tests +pnpm test:watch # Watch mode + +# Data ingestion (requires OPENAI_API_KEY in .env) +docker compose up -d chroma # Start Chroma vector database +pnpm ingest # Ingest documents into Chroma (or local JSON if Chroma unavailable) +pnpm ingest --clear # Clear and re-ingest all documents +``` + +### Frontend (web/) +```bash +pnpm dev:web # Start Next.js dev server → :3001 +pnpm build:web # Production build (standalone output) +pnpm test:web # Run frontend tests (59 tests with vitest) +``` + +### CI +```bash +pnpm ci # typecheck + test + build (backend) +``` + +## Project Structure + +``` +llarjove/ +├── src/ # Backend (Fastify API + RAG pipeline) +│ ├── index.ts # Server entry point (Fastify, CORS, routes, vector store init) +│ ├── config.ts # Env config (server, OpenAI, RAG, Chroma) +│ ├── types.ts # All TypeScript types/interfaces +│ ├── rag.ts # Main RAG pipeline orchestrator +│ ├── api/ +│ │ └── chat.ts # REST endpoints: /chat, /retrieve, /health, /stats, /resources +│ ├── ingestion/ +│ │ ├── documentLoader.ts # Load .txt/.pdf from filesystem +│ │ ├── chunker.ts # Legal doc chunking (by article) +│ │ ├── aidChunker.ts # Aid program chunking (by ## section) +│ │ └── embedder.ts # OpenAI embedding generation (text-embedding-3-small) +│ ├── retrieval/ +│ │ ├── vectorStore.ts # Chroma client with local JSON fallback +│ │ ├── localVectorStore.ts # JSON-based vector store (cosine similarity) +│ │ └── reranker.ts # Keyword reranking + threshold filtering +│ ├── generation/ +│ │ ├── promptBuilder.ts # System prompt, context formatting, history condensation +│ │ └── responseValidator.ts # Citation extraction, confidence scoring, warnings +│ ├── resources/ +│ │ └── programs.ts # Active housing programs DB (Bono Joven, Borsa Jove, etc.) +│ ├── scripts/ +│ │ └── ingest.ts # CLI: pnpm ingest [--clear] +│ └── public/ +│ └── index.html # Chat UI (served at / by the backend) +│ +├── web/ # Frontend (Next.js 15 landing page) +│ ├── src/ +│ │ ├── app/ +│ │ │ ├── layout.tsx # Root layout (Geist font, lang="ca", global CSS) +│ │ │ ├── page.tsx # Landing page (hero, features, FAQ, waitlist) +│ │ │ ├── WaitlistForm.tsx # Waitlist form (NOT connected to backend yet) +│ │ │ └── chat/ +│ │ │ └── route.ts # GET /chat → redirect to CHAT_REDIRECT_URL (runtime) +│ │ ├── components/ +│ │ │ ├── ui/ # 5 UI primitives (Button, Card, Input, Badge, Link) +│ │ │ └── BrandShowcase.tsx # Living style guide +│ │ ├── lib/ +│ │ │ └── cn.ts # clsx + tailwind-merge utility +│ │ ├── styles/ +│ │ │ ├── tokens.css # Design tokens (OKLCH colors, radii, shadows) +│ │ │ └── fonts.css # Geist font imports +│ │ └── index.css # @theme inline + global styles +│ ├── next.config.ts # Standalone output, TS errors ignored +│ ├── package.json # Next.js 15, React 19, Tailwind v4 +│ └── vitest.config.ts # jsdom environment, React plugin +│ +├── data/ # Documents for RAG ingestion +│ ├── laws/ # Legal: LAU.txt, LPH.txt +│ ├── ajudes/ # Aids: 5 program docs (Bono Joven, Borsa Jove, etc.) +│ ├── vector_store.json # Pre-built local vector store (86 chunks, committed to git) +│ └── SOURCES.md # Official data source documentation +│ +├── docs/adr/ # 6 Architecture Decision Records +├── tests/ # Backend tests (aidChunker, chunker, responseValidator) +│ +├── Dockerfile # Backend: multi-stage, copies data/ for local vector store +├── Dockerfile.web # Frontend: multi-stage, standalone Next.js +├── docker-compose.yml # Chroma vector DB service +├── railway-api.toml # Railway: backend deploy config +├── railway-web.toml # Railway: frontend deploy config +├── .env.example # Env template +└── .github/workflows/ci.yml # CI: typecheck → test → build +``` + +## Backend Architecture + +### RAG Pipeline (`src/rag.ts`) + +``` +User Question + → buildStandaloneQuestion() (resolve history references) + → generateEmbedding() (OpenAI text-embedding-3-small) + → queryChunks() (Chroma or local JSON, retrieve 2× maxChunks) + → rerank() (keyword boost +0.1 text, +0.15 title/section) + → filterByThreshold() (default 0.65) + → slice(0, maxChunks) (default 5) + → buildPrompt() (system prompt in Catalan, context with citations) + → OpenAI gpt-4-turbo-preview (temp 0.3, max 1000 tokens) + → buildValidatedResponse() (extract citations, determine confidence) + → addWarningsIfNeeded() (low → append note, none → replace with fallback) +``` + +### Confidence Levels +- **high**: top score ≥ 0.8 AND citations found +- **medium**: avg score ≥ 0.6 AND citations found +- **low**: citations but low scores → appends warning note +- **none**: no chunks retrieved OR response says "no info" → replaces answer with "No he trobat informació rellevant..." + +### API Endpoints (src/api/chat.ts) + +| Method | Path | Purpose | +|--------|------|---------| +| POST | /chat | Main RAG chat (supports `stream: true` for SSE) | +| POST | /retrieve | Debug: retrieval without generation | +| GET | /health | Vector store mode + document count | +| GET | /stats | Document count + model names | +| GET | /resources | Active housing programs (filter by status/region) | +| GET | /resources/deadlines | Programs with upcoming deadlines | +| GET | /resources/:id | Specific program by ID | + +### Vector Store + +Two modes (auto-fallback): +1. **Chroma** (when `CHROMA_HOST` available): production-grade vector DB +2. **Local JSON** (`data/vector_store.json`): development fallback, committed to git + +The local store uses `import.meta.url` to resolve the path from the module directory (not CWD), so it works in Docker where the compiled JS is in `dist/retrieval/`. + +### Data Documents + +| Directory | Contents | Chunking | Chunks | +|-----------|----------|----------|--------| +| `data/laws/` | LAU.txt, LPH.txt | By article (regex) | 37 | +| `data/ajudes/` | 5 aid programs | By ## section | 49 | +| **Total** | | | **86** | + +After modifying documents: `pnpm ingest --clear` (needs `OPENAI_API_KEY`). +If Chroma is not running, ingestion falls back to local JSON automatically. +**Important**: Commit `data/vector_store.json` after re-ingestion so production (which has no Chroma) gets the updated data. + +## Frontend Architecture + +### Stack +- **Next.js 15** (App Router, standalone output) +- **React 19** + **TypeScript** (strict) +- **Tailwind CSS v4** (PostCSS plugin, `@theme inline`) +- **Geist** font family + +### Design System + +**Tokens** (`web/src/styles/tokens.css` + `web/src/index.css`): +- Colors: OKLCH color space. Primary = teal (`oklch(0.556 0.135 181)`) +- Semantic colors: foreground, muted-foreground, border, input, ring, card, destructive +- Radii: sm (0.5rem) → full (9999px) +- Shadows: sm, md + +**UI Components** (`web/src/components/ui/`): +- `Button` — 5 variants (primary, secondary, outline, destructive, ghost), 3 sizes +- `Card` — with CardHeader, CardContent, CardFooter +- `Input` — with error state +- `Badge` — 4 variants (default, secondary, outline, destructive) +- `Link` — auto-detects external links, adds target/rel + +All components use `forwardRef`, extend native HTML attributes, use `cn()` for class merging, and have comprehensive tests. + +### Pages + +- **`/`** — Landing page (hero, 3-step explainer, benefits, sources, privacy, FAQ, waitlist form) +- **`/chat`** — Route handler that redirects to backend chat UI via `CHAT_REDIRECT_URL` + +### Key Files + +- **`page.tsx`**: Full landing page with sections. Links to `/chat` for "Probar el chat" / "Probar el asistente" CTAs. +- **`WaitlistForm.tsx`**: Form with email, location, profile, and privacy checkbox. Currently prevents default submission (no backend integration). +- **`chat/route.ts`**: Runtime redirect to backend. Reads `CHAT_REDIRECT_URL` or `NEXT_PUBLIC_API_URL` from `process.env`. Falls back to homepage using `x-forwarded-host` headers. + +## Environment Variables + +### Backend (.env) +| Variable | Default | Purpose | +|----------|---------|---------| +| `OPENAI_API_KEY` | (required) | OpenAI API key | +| `PORT` | 3000 | Server port | +| `HOST` | 0.0.0.0 | Server host | +| `EMBEDDING_MODEL` | text-embedding-3-small | Embedding model | +| `CHAT_MODEL` | gpt-4-turbo-preview | Chat completion model | +| `MAX_CHUNKS` | 5 | Max context chunks | +| `SIMILARITY_THRESHOLD` | 0.65 | Min similarity for retrieval | +| `CHROMA_HOST` | localhost | Chroma server host | +| `CHROMA_PORT` | 8000 | Chroma server port | +| `CHROMA_COLLECTION` | legal_docs | Chroma collection name | + +### Frontend (Railway env vars for web service) +| Variable | Purpose | +|----------|---------| +| `CHAT_REDIRECT_URL` | Backend URL for /chat redirect (runtime, NOT build-time) | +| `NEXT_PUBLIC_API_URL` | Fallback for CHAT_REDIRECT_URL | + +## Deployment (Railway) + +Two services from the same repo: +- **API service**: Uses `Dockerfile`, configured in `railway-api.toml`. Has `OPENAI_API_KEY`. +- **Web service**: Uses `Dockerfile.web`, configured in `railway-web.toml`. Has `CHAT_REDIRECT_URL`. + +The API service uses the local JSON vector store (no Chroma in Railway). The `data/vector_store.json` must be committed with all chunks for production to work. + +## Adding New Content + +1. Add document to `data/laws/` or `data/ajudes/` +2. Document source in `data/SOURCES.md` +3. Run `pnpm ingest --clear` (needs `OPENAI_API_KEY`, Chroma optional) +4. Commit `data/vector_store.json` so production gets the new data + +## Git Workflow + +- Branch naming: `feature/`, `fix/`, `deploy/`, `design/` +- Commits follow conventional commits: `feat()`, `fix()`, `data:`, `chore:` +- PRs against `main`, described with Summary + How to test +- CI runs on push: typecheck → test → build + +## Current State & Known Issues + +### What works +- RAG chat with 86 chunks (37 legal + 49 aid) answering questions about housing aids, tenant rights +- Landing page with design system, waitlist form UI, chat redirect +- Dual Railway deployment (API + Web) +- Confidence scoring and source citations + +### What's missing / needs improvement +- WaitlistForm has no backend (form does nothing) +- No user accounts, no chat history persistence +- No analytics configured +- Mixed Catalan/Spanish copy on landing page +- No SEO meta-description +- No testimonials or social proof +- No monetization model +- No i18n system (hardcoded strings) +- Chat UI (`src/public/index.html`) is basic HTML, not integrated into the Next.js design system diff --git a/Dockerfile b/Dockerfile index 7022d50..da036f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,47 +1,47 @@ -# LegalBot RAG - Production Dockerfile -FROM node:20-slim AS builder - -WORKDIR /app - -# Set to commit SHA or timestamp in CI to force fresh build (avoids stale cache) -ARG CACHEBUST= -RUN echo "Build cache key: ${CACHEBUST}" - -# Install dependencies -COPY package.json pnpm-lock.yaml* ./ -RUN npm install -g pnpm && pnpm install --frozen-lockfile - -# Copy source and build -COPY . . -RUN pnpm build - -# Production image -FROM node:20-slim AS runner - -WORKDIR /app - -ENV NODE_ENV=production - -# Install pnpm for production deps -RUN npm install -g pnpm - -# Copy package files -COPY package.json pnpm-lock.yaml* ./ -RUN pnpm install --prod --frozen-lockfile - -# Copy built files, static assets, and data -COPY --from=builder /app/dist ./dist -COPY --from=builder /app/src/public ./dist/public -COPY --from=builder /app/data ./data - -# Fix ownership so non-root user can read vector_store.json -RUN chown -R 1001:1001 /app/data - -# Create non-root user -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 legalbot -USER legalbot - -CMD ["node", "dist/index.js"] - -CMD ["node", "dist/index.js"] +# LegalBot RAG - Production Dockerfile +FROM node:20-slim AS builder + +WORKDIR /app + +# Set to commit SHA or timestamp in CI to force fresh build (avoids stale cache) +ARG CACHEBUST= +RUN echo "Build cache key: ${CACHEBUST}" + +# Install dependencies +COPY package.json pnpm-lock.yaml* ./ +RUN npm install -g pnpm && pnpm install --frozen-lockfile + +# Copy source and build +COPY . . +RUN pnpm build + +# Production image +FROM node:20-slim AS runner + +WORKDIR /app + +ENV NODE_ENV=production + +# Install pnpm for production deps +RUN npm install -g pnpm + +# Copy package files +COPY package.json pnpm-lock.yaml* ./ +RUN pnpm install --prod --frozen-lockfile + +# Copy built files, static assets, and data +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/src/public ./dist/public +COPY --from=builder /app/data ./data + +# Fix ownership so non-root user can read vector_store.json +RUN chown -R 1001:1001 /app/data + +# Create non-root user +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 legalbot +USER legalbot + +CMD ["node", "dist/index.js"] + +CMD ["node", "dist/index.js"] diff --git a/Dockerfile.web b/Dockerfile.web index 6500347..24fbdfa 100644 --- a/Dockerfile.web +++ b/Dockerfile.web @@ -1,27 +1,27 @@ -# LlarJove Web - Next.js standalone for Railway -FROM node:20-slim AS builder - -WORKDIR /app - -COPY web/package.json web/pnpm-lock.yaml* ./ -RUN npm install -g pnpm && pnpm install --frozen-lockfile - -COPY web/ . -RUN mkdir -p public -ENV NEXT_TELEMETRY_DISABLED=1 -RUN pnpm build - -FROM node:20-slim AS runner - -WORKDIR /app - -ENV NODE_ENV=production -ENV NEXT_TELEMETRY_DISABLED=1 - -COPY --from=builder /app/.next/standalone ./ -COPY --from=builder /app/.next/static ./.next/static -COPY --from=builder /app/public ./public - -EXPOSE 3000 -ENV PORT=3000 -CMD ["node", "server.js"] +# LlarJove Web - Next.js standalone for Railway +FROM node:20-slim AS builder + +WORKDIR /app + +COPY web/package.json web/pnpm-lock.yaml* ./ +RUN npm install -g pnpm && pnpm install --frozen-lockfile + +COPY web/ . +RUN mkdir -p public +ENV NEXT_TELEMETRY_DISABLED=1 +RUN pnpm build + +FROM node:20-slim AS runner + +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder /app/.next/static ./.next/static +COPY --from=builder /app/public ./public + +EXPOSE 3000 +ENV PORT=3000 +CMD ["node", "server.js"] diff --git a/README.md b/README.md index b4e1294..e976c12 100644 --- a/README.md +++ b/README.md @@ -1,210 +1,210 @@ -# LlarJove - -> Assistent RAG per ajudar joves catalans a trobar habitatge: informació sobre ajudes, drets i recursos. - -## Què és LlarJove? - -LlarJove és un chatbot que ajuda joves de 18-35 anys a Catalunya a: - -- **Trobar ajudes**: Bono Alquiler Joven, ajudes de la Generalitat, ajudes municipals -- **Conèixer els seus drets**: LAU, fiança, actualitzacions de lloguer -- **Connectar amb recursos**: Borsa Jove, HPO, programes actius amb terminis - -## Quick Start - -### Prerequisits - -- Node.js 20+ -- pnpm -- OpenAI API key - -### Instal·lació - -```bash -git clone -cd llarjove -pnpm install - -# Configurar entorn -cp .env.example .env -# Editar .env i afegir OPENAI_API_KEY - -# Iniciar servidor -pnpm dev -``` - -### Ús de l'API - -```bash -# Preguntar sobre ajudes -curl -X POST http://localhost:3000/chat \ - -H "Content-Type: application/json" \ - -d '{"question": "Què és el Bono Alquiler Joven i quins requisits té?"}' - -# Preguntar sobre drets -curl -X POST http://localhost:3000/chat \ - -H "Content-Type: application/json" \ - -d '{"question": "Quant preavís he de donar per marxar del pis?"}' -``` - -### Resposta d'exemple - -```json -{ - "answer": "El Bono Alquiler Joven és una ajuda de fins a 250€/mes durant 24 mesos per a joves de 18-35 anys. Els requisits principals són:\n\n1. Ingressos ≤ 25.200€ bruts/any\n2. Lloguer ≤ 900€/mes en zones tensionades\n3. No ser propietari d'un altre habitatge\n4. Estar empadronat a l'habitatge\n\n⚠️ Termini 2025: 30 juny - 11 juliol (per ordre d'entrada)\n\n📎 Més info: tramits.gencat.cat", - "sources": [...], - "confidence": "high" -} -``` - -## Preguntes de Demo - -| Pregunta | Tema | -|----------|------| -| "Què és el Bono Alquiler Joven?" | Ajudes estatals | -| "Quins requisits necessito per l'ajuda al lloguer?" | Requisits | -| "Quant preavís he de donar per marxar del pis?" | Drets inquilí (LAU) | -| "Qui paga les reparacions del pis?" | Drets inquilí (LAU) | -| "Què és la Borsa Jove d'Habitatge?" | Recursos Catalunya | - -## Arquitectura - -``` -┌─────────────────────────────────────────────────────────────┐ -│ FRONTEND (web/) │ -│ React 19 + Vite 6 + Tailwind v4 │ -│ Design System: Brand identity + 5 UI components │ -└─────────────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────────────┐ -│ API BACKEND │ -│ Fastify + RAG Pipeline │ -└─────────────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────────────┐ -│ INGESTA (offline) │ -│ Documents → Chunker → Embeddings → Vector Store │ -└─────────────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────────────┐ -│ CONSULTA (runtime) │ -│ Pregunta → Embedding → Cerca semàntica → Rerank │ -│ → Prompt amb context → GPT-4 → Resposta validada │ -└─────────────────────────────────────────────────────────────┘ -``` - -## Estructura del Projecte - -``` -llarjove/ -├── web/ # Frontend (React 19 + Vite 6 + Tailwind v4) -│ ├── src/ -│ │ ├── components/ # UI components + Brand showcase -│ │ ├── styles/ # Design tokens (colors, typography) -│ │ └── lib/ # Utilities (cn, etc.) -│ └── tests/ # 59 tests (vitest + testing-library) -├── src/ # Backend API + RAG -│ ├── ingestion/ # Càrrega i chunking de documents -│ ├── retrieval/ # Vector store i reranking -│ ├── generation/ # Prompts i validació -│ ├── api/ # Endpoints Fastify -│ └── rag.ts # Pipeline principal -├── data/ -│ ├── ajudes/ # Documents sobre ajudes -│ ├── drets/ # Drets de l'inquilí -│ ├── guies/ # Guies pràctiques -│ ├── laws/ # LAU i altres lleis -│ └── SOURCES.md # Llista de fonts oficials -└── tests/ -``` - -## Fonts de Dades - -| Font | Contingut | -|------|-----------| -| [Gencat - Agència Habitatge](https://habitatge.gencat.cat) | Ajudes autonòmiques | -| [Bono Alquiler Joven](https://tramits.gencat.cat) | Ajuda estatal 250€/mes | -| [BCN Joves](https://barcelona.cat/joves) | Recursos Barcelona | -| LAU (Ley 29/1994) | Drets inquilí | - -## Configuració - -| Variable | Default | Descripció | -|----------|---------|------------| -| `OPENAI_API_KEY` | - | Requerit | -| `MAX_CHUNKS` | 5 | Màx. chunks per consulta | -| `SIMILARITY_THRESHOLD` | 0.7 | Puntuació mínima similitud | - -## Endpoints API - -| Mètode | Endpoint | Descripció | -|--------|----------|------------| -| POST | `/chat` | Chat principal | -| GET | `/resources` | Programes actius amb terminis | -| GET | `/health` | Health check | - -## Desenvolupament - -### Backend (API + RAG) -```bash -pnpm dev # Servidor amb hot reload -pnpm test # Tests backend -pnpm ingest # Ingestar documents a Chroma -pnpm build # Compilar TypeScript -``` - -### Frontend (React) -```bash -pnpm dev:web # Dev server (http://localhost:5173) -pnpm test:web # Tests frontend (59 tests) -pnpm build:web # Build producció -``` - -### Brand Design System - -El frontend inclou un **design system complet** amb: -- **Design tokens**: Colors OKLCH, tipografia Geist, espaciat, radis -- **5 UI components**: Button, Card, Input, Badge, Link -- **Tailwind v4**: CSS-first configuration amb `@theme inline` -- **Living style guide**: `/web/src/components/BrandShowcase.tsx` - -Visita http://localhost:3000 després de `pnpm dev:web` per veure la landing i el showcase. - -## Deployment (Railway) - -El projecte es desplega com a **dos serveis** a Railway (mateix repo, dos Dockerfiles). - -| Servei | Dockerfile | Config | Port | -|--------|------------|--------|------| -| **RAG API** | `Dockerfile` | `railway-api.toml` | `PORT` (assignat per Railway) | -| **Web** | `Dockerfile.web` | `railway-web.toml` | `PORT` (assignat per Railway) | - -### Configuració a Railway - -Cal **dos serveis** al mateix projecte Railway: - -1. **Servei RAG API** (el xat i la API) - - Build: Dockerfile `./Dockerfile` (o config `railway-api.toml`). - - Variables: `OPENAI_API_KEY`, `CHROMA_HOST`, `CHROMA_PORT`, `CHROMA_COLLECTION` (si Chroma extern). Railway injecta `PORT`. - - Health check: `/health`. - - En desplegar, Railway assigna una URL (ex: `https://llarjove-api-production.up.railway.app`). **Aquesta URL és on es troba el xat**: en obrir-la al navegador es mostra la interfície del assistent RAG. - -2. **Servei Web** (landing) - - Build: Dockerfile `./Dockerfile.web` (o config `railway-web.toml`). - - Variables: **`NEXT_PUBLIC_API_URL`** = URL pública del servei RAG API (la mateixa que obres per al xat). Sense aquesta variable, la landing no mostrarà el botó "Probar el chat". Railway injecta `PORT`. - - Health check: `/`. - -Cada servei rep un `PORT` dinàmic; no hi ha conflicte de ports. - -## Roadmap - -- [x] Frontend web accessible - **Design system implementat** (PR #2) -- [ ] Integrar frontend amb API backend -- [ ] Notificacions de terminis propers -- [ ] Integració amb Telegram/WhatsApp -- [ ] Expansió a altres CCAA - -## Llicència - -MIT - +# LlarJove + +> Assistent RAG per ajudar joves catalans a trobar habitatge: informació sobre ajudes, drets i recursos. + +## Què és LlarJove? + +LlarJove és un chatbot que ajuda joves de 18-35 anys a Catalunya a: + +- **Trobar ajudes**: Bono Alquiler Joven, ajudes de la Generalitat, ajudes municipals +- **Conèixer els seus drets**: LAU, fiança, actualitzacions de lloguer +- **Connectar amb recursos**: Borsa Jove, HPO, programes actius amb terminis + +## Quick Start + +### Prerequisits + +- Node.js 20+ +- pnpm +- OpenAI API key + +### Instal·lació + +```bash +git clone +cd llarjove +pnpm install + +# Configurar entorn +cp .env.example .env +# Editar .env i afegir OPENAI_API_KEY + +# Iniciar servidor +pnpm dev +``` + +### Ús de l'API + +```bash +# Preguntar sobre ajudes +curl -X POST http://localhost:3000/chat \ + -H "Content-Type: application/json" \ + -d '{"question": "Què és el Bono Alquiler Joven i quins requisits té?"}' + +# Preguntar sobre drets +curl -X POST http://localhost:3000/chat \ + -H "Content-Type: application/json" \ + -d '{"question": "Quant preavís he de donar per marxar del pis?"}' +``` + +### Resposta d'exemple + +```json +{ + "answer": "El Bono Alquiler Joven és una ajuda de fins a 250€/mes durant 24 mesos per a joves de 18-35 anys. Els requisits principals són:\n\n1. Ingressos ≤ 25.200€ bruts/any\n2. Lloguer ≤ 900€/mes en zones tensionades\n3. No ser propietari d'un altre habitatge\n4. Estar empadronat a l'habitatge\n\n⚠️ Termini 2025: 30 juny - 11 juliol (per ordre d'entrada)\n\n📎 Més info: tramits.gencat.cat", + "sources": [...], + "confidence": "high" +} +``` + +## Preguntes de Demo + +| Pregunta | Tema | +|----------|------| +| "Què és el Bono Alquiler Joven?" | Ajudes estatals | +| "Quins requisits necessito per l'ajuda al lloguer?" | Requisits | +| "Quant preavís he de donar per marxar del pis?" | Drets inquilí (LAU) | +| "Qui paga les reparacions del pis?" | Drets inquilí (LAU) | +| "Què és la Borsa Jove d'Habitatge?" | Recursos Catalunya | + +## Arquitectura + +``` +┌─────────────────────────────────────────────────────────────┐ +│ FRONTEND (web/) │ +│ React 19 + Vite 6 + Tailwind v4 │ +│ Design System: Brand identity + 5 UI components │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ API BACKEND │ +│ Fastify + RAG Pipeline │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ INGESTA (offline) │ +│ Documents → Chunker → Embeddings → Vector Store │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ CONSULTA (runtime) │ +│ Pregunta → Embedding → Cerca semàntica → Rerank │ +│ → Prompt amb context → GPT-4 → Resposta validada │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Estructura del Projecte + +``` +llarjove/ +├── web/ # Frontend (React 19 + Vite 6 + Tailwind v4) +│ ├── src/ +│ │ ├── components/ # UI components + Brand showcase +│ │ ├── styles/ # Design tokens (colors, typography) +│ │ └── lib/ # Utilities (cn, etc.) +│ └── tests/ # 59 tests (vitest + testing-library) +├── src/ # Backend API + RAG +│ ├── ingestion/ # Càrrega i chunking de documents +│ ├── retrieval/ # Vector store i reranking +│ ├── generation/ # Prompts i validació +│ ├── api/ # Endpoints Fastify +│ └── rag.ts # Pipeline principal +├── data/ +│ ├── ajudes/ # Documents sobre ajudes +│ ├── drets/ # Drets de l'inquilí +│ ├── guies/ # Guies pràctiques +│ ├── laws/ # LAU i altres lleis +│ └── SOURCES.md # Llista de fonts oficials +└── tests/ +``` + +## Fonts de Dades + +| Font | Contingut | +|------|-----------| +| [Gencat - Agència Habitatge](https://habitatge.gencat.cat) | Ajudes autonòmiques | +| [Bono Alquiler Joven](https://tramits.gencat.cat) | Ajuda estatal 250€/mes | +| [BCN Joves](https://barcelona.cat/joves) | Recursos Barcelona | +| LAU (Ley 29/1994) | Drets inquilí | + +## Configuració + +| Variable | Default | Descripció | +|----------|---------|------------| +| `OPENAI_API_KEY` | - | Requerit | +| `MAX_CHUNKS` | 5 | Màx. chunks per consulta | +| `SIMILARITY_THRESHOLD` | 0.7 | Puntuació mínima similitud | + +## Endpoints API + +| Mètode | Endpoint | Descripció | +|--------|----------|------------| +| POST | `/chat` | Chat principal | +| GET | `/resources` | Programes actius amb terminis | +| GET | `/health` | Health check | + +## Desenvolupament + +### Backend (API + RAG) +```bash +pnpm dev # Servidor amb hot reload +pnpm test # Tests backend +pnpm ingest # Ingestar documents a Chroma +pnpm build # Compilar TypeScript +``` + +### Frontend (React) +```bash +pnpm dev:web # Dev server (http://localhost:5173) +pnpm test:web # Tests frontend (59 tests) +pnpm build:web # Build producció +``` + +### Brand Design System + +El frontend inclou un **design system complet** amb: +- **Design tokens**: Colors OKLCH, tipografia Geist, espaciat, radis +- **5 UI components**: Button, Card, Input, Badge, Link +- **Tailwind v4**: CSS-first configuration amb `@theme inline` +- **Living style guide**: `/web/src/components/BrandShowcase.tsx` + +Visita http://localhost:3000 després de `pnpm dev:web` per veure la landing i el showcase. + +## Deployment (Railway) + +El projecte es desplega com a **dos serveis** a Railway (mateix repo, dos Dockerfiles). + +| Servei | Dockerfile | Config | Port | +|--------|------------|--------|------| +| **RAG API** | `Dockerfile` | `railway-api.toml` | `PORT` (assignat per Railway) | +| **Web** | `Dockerfile.web` | `railway-web.toml` | `PORT` (assignat per Railway) | + +### Configuració a Railway + +Cal **dos serveis** al mateix projecte Railway: + +1. **Servei RAG API** (el xat i la API) + - Build: Dockerfile `./Dockerfile` (o config `railway-api.toml`). + - Variables: `OPENAI_API_KEY`, `CHROMA_HOST`, `CHROMA_PORT`, `CHROMA_COLLECTION` (si Chroma extern). Railway injecta `PORT`. + - Health check: `/health`. + - En desplegar, Railway assigna una URL (ex: `https://llarjove-api-production.up.railway.app`). **Aquesta URL és on es troba el xat**: en obrir-la al navegador es mostra la interfície del assistent RAG. + +2. **Servei Web** (landing) + - Build: Dockerfile `./Dockerfile.web` (o config `railway-web.toml`). + - Variables: **`NEXT_PUBLIC_API_URL`** = URL pública del servei RAG API (la mateixa que obres per al xat). Sense aquesta variable, la landing no mostrarà el botó "Probar el chat". Railway injecta `PORT`. + - Health check: `/`. + +Cada servei rep un `PORT` dinàmic; no hi ha conflicte de ports. + +## Roadmap + +- [x] Frontend web accessible - **Design system implementat** (PR #2) +- [ ] Integrar frontend amb API backend +- [ ] Notificacions de terminis propers +- [ ] Integració amb Telegram/WhatsApp +- [ ] Expansió a altres CCAA + +## Llicència + +MIT + diff --git a/data/ajudes/ajudes-lloguer-generalitat-2025.txt b/data/ajudes/ajudes-lloguer-generalitat-2025.txt index d7c0fa5..2d9d285 100644 --- a/data/ajudes/ajudes-lloguer-generalitat-2025.txt +++ b/data/ajudes/ajudes-lloguer-generalitat-2025.txt @@ -1,102 +1,102 @@ -# Ajudes al pagament del lloguer de la Generalitat (2025) - -## Què és? - -Les **ajudes al pagament del lloguer** són subvencions concedides per la **Generalitat de Catalunya** a través de l'Agència de l'Habitatge per facilitar l'accés i el manteniment de l'habitatge de lloguer. No es tracta del Bono Joven estatal, sinó de programes propis de la Generalitat diferenciats per franges d'edat i adaptats a la situació socioeconòmica de les persones sol·licitants. - -### Programes vigents per al 2025 - -- **Subvencions per a joves de fins a 35 anys**. Dirigides a persones que no hagin fet 35 anys a 31 de gener de 2025 i que siguin titulars d'un contracte de lloguer o de cessió d'ús de l'habitatge habitual i permanent a Catalunya. -- **Subvencions per al tram de 36-64 anys**. Destinades a persones amb edats entre 36 i 64 anys que siguin titulars d'un contracte de lloguer de l'habitatge habitual. -- Altres programes específics (p. ex. per a persones majors de 65 anys o col·lectius vulnerables) es publiquen al llarg de l'any a la web de l'Agència de l'Habitatge. - -## Requisits - -### Edat - -- **Joves**: tenir **menys de 35 anys** el 31/01/2025. -- **Adults (36-64)**: tenir entre **36 i 64 anys** en el moment de la sol·licitud. - -### Residència i contracte - -- Estar **empadronat/ada** a l'habitatge objecte de la sol·licitud i que aquest sigui la residència habitual i permanent. Cal acreditar la inscripció al padró municipal. -- Disposar d'un **contracte de lloguer o de cessió d'ús** formalitzat al seu nom i inscrit en l'INCASÒL (fiança dipositada dins del termini de dos mesos). Els contractes entre familiars fins a segon grau no es consideren subvencionables. - -### Ingressos - -- Els **ingressos anuals de la unitat de convivència** no poden superar el límit de 25.200 € bruts anuals (3,05 vegades l'IRSC) per a joves i un màxim de 24.301,58 € (3 vegades l'IRSC) per al tram de 36-64 anys. Es calcula segons la declaració de la renda 2023 o certificat d'ingressos. -- Es tenen en compte els ingressos de totes les persones que figuren al contracte de lloguer. - -### Lloguer màxim subvencionable - -Els límits varien segons l'àmbit territorial i si es tracta d'un habitatge o una habitació: - -| Zona | Lloguer màxim habitatge (joves) | Lloguer màxim habitatge (36‑64) | Lloguer màxim habitació | -|-----|---------------------------------|---------------------------------|------------------------| -| **Àrea metropolitana de Barcelona** | 950 €/mes | 900 €/mes | 450 €/mes | -| **Resta de comarca de Barcelona** | 650 €/mes | 650 €/mes | 350 €/mes (joves); 300 €/mes (36‑64) | -| **Comarques de Girona** | 750 €/mes | 750 €/mes | 350 €/mes | -| **Comarques de Tarragona** | 700 €/mes | 700 €/mes | 350 €/mes | -| **Comarques de Lleida i Terres de l'Ebre** | 600 €/mes | 600 €/mes | 300 €/mes | - -Per a famílies nombroses, monoparentals o membres amb discapacitat superior al 33 %, el topall s'incrementa fins a **900 €/mes** o **1.100 €/mes** a l'Àrea metropolitana de Barcelona. - -### Altres requisits - -- Estar al corrent del pagament del lloguer i poder acreditar-lo amb rebuts bancaris (no s'accepten pagaments en metàl·lic). -- No ser propietari d'un habitatge ni disposar d'un usufructe que permeti satisfer la necessitat d'habitatge. -- No haver estat beneficiari/a d'ajudes al lloguer incompatibles o no presentar deutes amb l'Agència de l'Habitatge. - -## Quantia - -La quantia de la subvenció es calcula com un **percentatge del cost anual del lloguer** en funció de la relació entre renda de lloguer i ingressos de la unitat de convivència: - -- **20 %** del lloguer anual si l'esforç per al pagament del lloguer és igual o inferior al 30 % dels ingressos. -- **30 %** quan el lloguer suposa entre el 30 % i el 40 % dels ingressos. -- **40 %** si el lloguer supera el 40 % dels ingressos. - -La **subvenció anual màxima** és de **3.000 €** per habitatge i la mínima de **240 €** per any. En el programa de 36-64 anys la subvenció mensual màxima és de **200 €** per habitatge i la mínima de **20 €**. La suma de les ajudes de tots els convivents no pot superar el **75 % del lloguer mensual**. - -## Terminis de sol·licitud - -- **Joves (2025)**: la convocatòria s'obre **el 30 de juny de 2025 a les 09:00 h** i es tanca **l'11 de juliol de 2025 a les 14:00 h**. Les sol·licituds es resolen per un sistema de puntuació i no per ordre de presentació. -- **Adults (36-64)**: el termini de 2025 va ser del **10 de març de 2025** al **11 d'abril de 2025**. En futures convocatòries es preveu un calendari similar. - -## Documentació necessària - -- **Sol·licitud normalitzada** disponible al web de l'Agència de l'Habitatge. -- **Contracte de lloguer** o cessió d'ús signat i còpia dels rebuts de fiança (dipositats a l'INCASÒL). -- **Justificant del dipòsit de fiança** a l'INCASÒL, que s'ha de fer dins dels dos mesos posteriors a la signatura del contracte. -- **Certificat d'empadronament** que acrediti la residència en l'habitatge. -- **DNI o NIE** de totes les persones que figuren a la sol·licitud. -- **Declaració de la renda 2023** o certificats d'ingressos de tots els membres de la unitat de convivència. -- **Justificants de pagament del lloguer** (rebuts bancaris) dels mesos previs a la convocatòria. -- En el cas de lloguer d'habitació, **autorització escrita de la persona propietària**. - -## Exclusions - -- Contractes de lloguer entre persones unides per parentiu fins a segon grau o vinculades societàriament. -- Persones que ja reben el **Bono Joven estatal** per al pagament del lloguer. -- Contractes en què el lloguer superi els límits màxims establerts. -- Persones propietàries d'un habitatge (excepte casos de separació amb resolució judicial). -- Sol·licituds que no compleixin els requisits d'ingressos o documentació obligatòria. - -## Ajudes alternatives - -Si no es compleixen els requisits d'aquesta subvenció, es poden valorar altres ajuts: - -- **Borsa Jove d'Habitatge**: servei municipal que ofereix pisos a lloguer amb preu inferior al de mercat i facilita el dipòsit, la primera mensualitat i l'assegurança. Vegeu el document corresponent. -- **Ajut d'urgència per a persones vulnerables** gestionat pels serveis socials municipals, que pot cobrir fins a tres mesos de lloguer. -- **Programes municipals** d'ajudes al lloguer: molts ajuntaments (Barcelona, L'Hospitalet, Terrassa, Girona, etc.) ofereixen ajudes específiques. Consulteu el document «ajudes-per-municipi». -- **Habitatge protegit de lloguer (HPO)**: inscriure's al registre per accedir a pisos de protecció oficial a preu reduït. Vegeu el document «habitatge-protegit-hpo». - -## Enllaços útils - -- Agència de l'Habitatge de Catalunya – Subvencions al pagament del lloguer de joves (2025): https://habitatge.gencat.cat/ca/ambits/ajuts/subvencionslloguer/joves/ -- Agència de l'Habitatge de Catalunya – Subvencions al pagament del lloguer per a persones entre 36 i 64 anys (2025): https://habitatge.gencat.cat/ca/ambits/ajuts/subvencionslloguer/36-64/ -- Institut Català del Sòl (INCASÒL) – Dipòsit de fiançes: https://incasol.gencat.cat -- Pàgina de preguntes freqüents sobre les subvencions al lloguer: https://habitatge.gencat.cat/ca/ajuts/frequent/ - -## Font - -Informació obtinguda de l'**Agència de l'Habitatge de Catalunya** (convocatòria 2025), consultada el **7 de febrer de 2026** i actualitzada a **20 de juny de 2025**, així com de la normativa del **Institut Català del Sòl (INCASÒL)**, i de les preguntes freqüents de la mateixa Agència. També s'han utilitzat els topalls i percentatges que estableixen les bases de les convocatòries. +# Ajudes al pagament del lloguer de la Generalitat (2025) + +## Què és? + +Les **ajudes al pagament del lloguer** són subvencions concedides per la **Generalitat de Catalunya** a través de l'Agència de l'Habitatge per facilitar l'accés i el manteniment de l'habitatge de lloguer. No es tracta del Bono Joven estatal, sinó de programes propis de la Generalitat diferenciats per franges d'edat i adaptats a la situació socioeconòmica de les persones sol·licitants. + +### Programes vigents per al 2025 + +- **Subvencions per a joves de fins a 35 anys**. Dirigides a persones que no hagin fet 35 anys a 31 de gener de 2025 i que siguin titulars d'un contracte de lloguer o de cessió d'ús de l'habitatge habitual i permanent a Catalunya. +- **Subvencions per al tram de 36-64 anys**. Destinades a persones amb edats entre 36 i 64 anys que siguin titulars d'un contracte de lloguer de l'habitatge habitual. +- Altres programes específics (p. ex. per a persones majors de 65 anys o col·lectius vulnerables) es publiquen al llarg de l'any a la web de l'Agència de l'Habitatge. + +## Requisits + +### Edat + +- **Joves**: tenir **menys de 35 anys** el 31/01/2025. +- **Adults (36-64)**: tenir entre **36 i 64 anys** en el moment de la sol·licitud. + +### Residència i contracte + +- Estar **empadronat/ada** a l'habitatge objecte de la sol·licitud i que aquest sigui la residència habitual i permanent. Cal acreditar la inscripció al padró municipal. +- Disposar d'un **contracte de lloguer o de cessió d'ús** formalitzat al seu nom i inscrit en l'INCASÒL (fiança dipositada dins del termini de dos mesos). Els contractes entre familiars fins a segon grau no es consideren subvencionables. + +### Ingressos + +- Els **ingressos anuals de la unitat de convivència** no poden superar el límit de 25.200 € bruts anuals (3,05 vegades l'IRSC) per a joves i un màxim de 24.301,58 € (3 vegades l'IRSC) per al tram de 36-64 anys. Es calcula segons la declaració de la renda 2023 o certificat d'ingressos. +- Es tenen en compte els ingressos de totes les persones que figuren al contracte de lloguer. + +### Lloguer màxim subvencionable + +Els límits varien segons l'àmbit territorial i si es tracta d'un habitatge o una habitació: + +| Zona | Lloguer màxim habitatge (joves) | Lloguer màxim habitatge (36‑64) | Lloguer màxim habitació | +|-----|---------------------------------|---------------------------------|------------------------| +| **Àrea metropolitana de Barcelona** | 950 €/mes | 900 €/mes | 450 €/mes | +| **Resta de comarca de Barcelona** | 650 €/mes | 650 €/mes | 350 €/mes (joves); 300 €/mes (36‑64) | +| **Comarques de Girona** | 750 €/mes | 750 €/mes | 350 €/mes | +| **Comarques de Tarragona** | 700 €/mes | 700 €/mes | 350 €/mes | +| **Comarques de Lleida i Terres de l'Ebre** | 600 €/mes | 600 €/mes | 300 €/mes | + +Per a famílies nombroses, monoparentals o membres amb discapacitat superior al 33 %, el topall s'incrementa fins a **900 €/mes** o **1.100 €/mes** a l'Àrea metropolitana de Barcelona. + +### Altres requisits + +- Estar al corrent del pagament del lloguer i poder acreditar-lo amb rebuts bancaris (no s'accepten pagaments en metàl·lic). +- No ser propietari d'un habitatge ni disposar d'un usufructe que permeti satisfer la necessitat d'habitatge. +- No haver estat beneficiari/a d'ajudes al lloguer incompatibles o no presentar deutes amb l'Agència de l'Habitatge. + +## Quantia + +La quantia de la subvenció es calcula com un **percentatge del cost anual del lloguer** en funció de la relació entre renda de lloguer i ingressos de la unitat de convivència: + +- **20 %** del lloguer anual si l'esforç per al pagament del lloguer és igual o inferior al 30 % dels ingressos. +- **30 %** quan el lloguer suposa entre el 30 % i el 40 % dels ingressos. +- **40 %** si el lloguer supera el 40 % dels ingressos. + +La **subvenció anual màxima** és de **3.000 €** per habitatge i la mínima de **240 €** per any. En el programa de 36-64 anys la subvenció mensual màxima és de **200 €** per habitatge i la mínima de **20 €**. La suma de les ajudes de tots els convivents no pot superar el **75 % del lloguer mensual**. + +## Terminis de sol·licitud + +- **Joves (2025)**: la convocatòria s'obre **el 30 de juny de 2025 a les 09:00 h** i es tanca **l'11 de juliol de 2025 a les 14:00 h**. Les sol·licituds es resolen per un sistema de puntuació i no per ordre de presentació. +- **Adults (36-64)**: el termini de 2025 va ser del **10 de març de 2025** al **11 d'abril de 2025**. En futures convocatòries es preveu un calendari similar. + +## Documentació necessària + +- **Sol·licitud normalitzada** disponible al web de l'Agència de l'Habitatge. +- **Contracte de lloguer** o cessió d'ús signat i còpia dels rebuts de fiança (dipositats a l'INCASÒL). +- **Justificant del dipòsit de fiança** a l'INCASÒL, que s'ha de fer dins dels dos mesos posteriors a la signatura del contracte. +- **Certificat d'empadronament** que acrediti la residència en l'habitatge. +- **DNI o NIE** de totes les persones que figuren a la sol·licitud. +- **Declaració de la renda 2023** o certificats d'ingressos de tots els membres de la unitat de convivència. +- **Justificants de pagament del lloguer** (rebuts bancaris) dels mesos previs a la convocatòria. +- En el cas de lloguer d'habitació, **autorització escrita de la persona propietària**. + +## Exclusions + +- Contractes de lloguer entre persones unides per parentiu fins a segon grau o vinculades societàriament. +- Persones que ja reben el **Bono Joven estatal** per al pagament del lloguer. +- Contractes en què el lloguer superi els límits màxims establerts. +- Persones propietàries d'un habitatge (excepte casos de separació amb resolució judicial). +- Sol·licituds que no compleixin els requisits d'ingressos o documentació obligatòria. + +## Ajudes alternatives + +Si no es compleixen els requisits d'aquesta subvenció, es poden valorar altres ajuts: + +- **Borsa Jove d'Habitatge**: servei municipal que ofereix pisos a lloguer amb preu inferior al de mercat i facilita el dipòsit, la primera mensualitat i l'assegurança. Vegeu el document corresponent. +- **Ajut d'urgència per a persones vulnerables** gestionat pels serveis socials municipals, que pot cobrir fins a tres mesos de lloguer. +- **Programes municipals** d'ajudes al lloguer: molts ajuntaments (Barcelona, L'Hospitalet, Terrassa, Girona, etc.) ofereixen ajudes específiques. Consulteu el document «ajudes-per-municipi». +- **Habitatge protegit de lloguer (HPO)**: inscriure's al registre per accedir a pisos de protecció oficial a preu reduït. Vegeu el document «habitatge-protegit-hpo». + +## Enllaços útils + +- Agència de l'Habitatge de Catalunya – Subvencions al pagament del lloguer de joves (2025): https://habitatge.gencat.cat/ca/ambits/ajuts/subvencionslloguer/joves/ +- Agència de l'Habitatge de Catalunya – Subvencions al pagament del lloguer per a persones entre 36 i 64 anys (2025): https://habitatge.gencat.cat/ca/ambits/ajuts/subvencionslloguer/36-64/ +- Institut Català del Sòl (INCASÒL) – Dipòsit de fiançes: https://incasol.gencat.cat +- Pàgina de preguntes freqüents sobre les subvencions al lloguer: https://habitatge.gencat.cat/ca/ajuts/frequent/ + +## Font + +Informació obtinguda de l'**Agència de l'Habitatge de Catalunya** (convocatòria 2025), consultada el **7 de febrer de 2026** i actualitzada a **20 de juny de 2025**, així com de la normativa del **Institut Català del Sòl (INCASÒL)**, i de les preguntes freqüents de la mateixa Agència. També s'han utilitzat els topalls i percentatges que estableixen les bases de les convocatòries. diff --git a/data/ajudes/borsa-jove-habitatge.txt b/data/ajudes/borsa-jove-habitatge.txt index 05b54de..4e94280 100644 --- a/data/ajudes/borsa-jove-habitatge.txt +++ b/data/ajudes/borsa-jove-habitatge.txt @@ -1,74 +1,74 @@ -# Borsa Jove d'Habitatge de Barcelona - -## Què és? - -La **Borsa Jove d'Habitatge de Barcelona** és un servei municipal de mediació gestionat pel **Consorci de l'Habitatge de Barcelona** a través de les oficines d'habitatge. Té l'objectiu d'incrementar l'oferta de lloguer assequible i garantir l'accés a l'habitatge de lloguer per a joves i llars en situació de vulnerabilitat. Mitjançant acords amb propietaris de pisos buits, la Borsa ofereix habitatges amb rendes per sota del preu de mercat i assegura l'acompanyament durant tota la vigència del contracte. - -## Requisits - -### Edat i perfil - -- Dirigit principalment a **joves d'entre 18 i 35 anys** i a llars que compleixin els requisits socials i econòmics establerts. La prioritat s'atorga a persones amb **ingressos no superiors a 2,35 vegades l'IRSC**, tot i que el servei és obert a altres llars amb ingressos fins a 4 vegades l'IRSC. - -### Residència i empadronament - -- Cal estar **empadronat a Barcelona** o acreditar residència efectiva a la ciutat. - -### Ingressos - -- **Ingressos mínims**: cal demostrar uns ingressos equivalents a **1 vegada l'IPREM (0,93 vegades l'IRSC)** per garantir la viabilitat econòmica del lloguer. -- **Ingressos màxims**: no superar les **4 vegades l'IRSC**. Les persones amb ingressos **≤ 2,35 vegades l'IRSC** tenen prioritat de mediació. - -### Altres requisits - -- Presentar documentació que acrediti la necessitat d'habitatge (resolucions de desnonament, informe dels serveis socials o contracte de lloguer finalitzat). -- No tenir habitatge en propietat o dret d'ús que cobreixi la necessitat d'habitatge. - -## Quantia - -No es tracta d'una subvenció directa sinó d'un **servei de mediació** que ofereix diversos avantatges econòmics: - -- **Rendes de lloguer inferiors al preu de mercat**: la Borsa negocia amb els propietaris per establir preus ajustats als barems municipals. -- **Cobertura de despeses inicials**: l'Ajuntament paga el dipòsit (fiança), la primera mensualitat i les despeses de contractació per facilitar l'entrada de la unitat de convivència. -- **Ajut d'urgència**: es pot concedir una ajuda de fins a **tres mesos de lloguer** a unitats de convivència en situació d'emergència social. -- **Assessorament i mediació gratuïta**: suport en la signatura del contracte, elaboració d'inventari, assessorament jurídic i mediació en possibles conflictes durant la vigència del contracte. - -## Terminis de sol·licitud - -La inscripció a la Borsa és **oberta tot l'any**. Les persones interessades poden adreçar-se a qualsevol **oficina d'habitatge de Barcelona** per inscriure's i aportar la documentació requerida. - -## Documentació necessària - -Segons la guia oficial, cal aportar: - -- **Sol·licitud de lloguer** i formulari de declaració de necessitat d'habitatge. -- **DNI/NIE** de totes les persones que ocuparan l'habitatge. -- **Documentació acreditativa de la situació d'habitatge** (ordre de desnonament, contracte de lloguer vigent, informe social, etc.). -- **Contractes de treball** i **tres últimes nòmines** de tots els membres que generen ingressos. -- **Informe de vida laboral** o certificat d'ingressos equivalents (pensions, subsidis). -- **Certificat d'empadronament** actualitzat a Barcelona. -- Documentació addicional segons la situació: llibre de família (menors sense DNI), declaracions d'autònoms, informes d'ingressos en metàl·lic, declaració de renda o certificat d'Hisenda, certificats de pensions o d'ajuts per discapacitat. - -## Exclusions - -- Persones amb **ingressos superiors al límit de 4 vegades l'IRSC**. -- Unitats de convivència que disposen d'habitatge adequat o d'un dret d'ús suficient. -- Contractes signats fora de la mediació de la Borsa o habitatges que no compleixin els requisits de qualitat i habitabilitat establerts pel servei. - -## Ajudes alternatives - -Altres programes a considerar: - -- **Subvencions al lloguer** de la Generalitat per a joves i persones de 36-64 anys (vegeu el document «ajudes-lloguer-generalitat-2025»). -- **Habitatge de Protecció Oficial (HPO)**: registre de demandants per accedir a habitatges amb protecció oficial. -- **Ajuts municipals al lloguer**: hi ha convocatòries específiques a diversos municipis de l'àrea metropolitana de Barcelona (L'Hospitalet, Badalona, Sant Adrià, etc.). - -## Enllaços útils - -- Consorci de l'Habitatge de Barcelona – Borsa d'Habitatge: https://www.habitatgebarcelona.cat/ca/serveis/lloguer/mediacio -- Barcelona.cat – Joves i habitatge: https://ajuntament.barcelona.cat/joves/ca -- Oficines de l'Habitatge de Barcelona: https://habitatge.barcelona/ca/oficines - -## Font - -Informació extreta del **Consorci de l'Habitatge de Barcelona** i de les seves oficines d'habitatge, amb referència a la **Borsa d'Habitatge de Lloguer** i a la **Borsa Jove**, consultada el **7 de febrer de 2026**. El servei s'actualitza de manera contínua i prioritza llars amb ingressos inferiors a 2,35 vegades l'IRSC i ofereix avantatges com la cobertura de la fiança i el primer mes de lloguer. +# Borsa Jove d'Habitatge de Barcelona + +## Què és? + +La **Borsa Jove d'Habitatge de Barcelona** és un servei municipal de mediació gestionat pel **Consorci de l'Habitatge de Barcelona** a través de les oficines d'habitatge. Té l'objectiu d'incrementar l'oferta de lloguer assequible i garantir l'accés a l'habitatge de lloguer per a joves i llars en situació de vulnerabilitat. Mitjançant acords amb propietaris de pisos buits, la Borsa ofereix habitatges amb rendes per sota del preu de mercat i assegura l'acompanyament durant tota la vigència del contracte. + +## Requisits + +### Edat i perfil + +- Dirigit principalment a **joves d'entre 18 i 35 anys** i a llars que compleixin els requisits socials i econòmics establerts. La prioritat s'atorga a persones amb **ingressos no superiors a 2,35 vegades l'IRSC**, tot i que el servei és obert a altres llars amb ingressos fins a 4 vegades l'IRSC. + +### Residència i empadronament + +- Cal estar **empadronat a Barcelona** o acreditar residència efectiva a la ciutat. + +### Ingressos + +- **Ingressos mínims**: cal demostrar uns ingressos equivalents a **1 vegada l'IPREM (0,93 vegades l'IRSC)** per garantir la viabilitat econòmica del lloguer. +- **Ingressos màxims**: no superar les **4 vegades l'IRSC**. Les persones amb ingressos **≤ 2,35 vegades l'IRSC** tenen prioritat de mediació. + +### Altres requisits + +- Presentar documentació que acrediti la necessitat d'habitatge (resolucions de desnonament, informe dels serveis socials o contracte de lloguer finalitzat). +- No tenir habitatge en propietat o dret d'ús que cobreixi la necessitat d'habitatge. + +## Quantia + +No es tracta d'una subvenció directa sinó d'un **servei de mediació** que ofereix diversos avantatges econòmics: + +- **Rendes de lloguer inferiors al preu de mercat**: la Borsa negocia amb els propietaris per establir preus ajustats als barems municipals. +- **Cobertura de despeses inicials**: l'Ajuntament paga el dipòsit (fiança), la primera mensualitat i les despeses de contractació per facilitar l'entrada de la unitat de convivència. +- **Ajut d'urgència**: es pot concedir una ajuda de fins a **tres mesos de lloguer** a unitats de convivència en situació d'emergència social. +- **Assessorament i mediació gratuïta**: suport en la signatura del contracte, elaboració d'inventari, assessorament jurídic i mediació en possibles conflictes durant la vigència del contracte. + +## Terminis de sol·licitud + +La inscripció a la Borsa és **oberta tot l'any**. Les persones interessades poden adreçar-se a qualsevol **oficina d'habitatge de Barcelona** per inscriure's i aportar la documentació requerida. + +## Documentació necessària + +Segons la guia oficial, cal aportar: + +- **Sol·licitud de lloguer** i formulari de declaració de necessitat d'habitatge. +- **DNI/NIE** de totes les persones que ocuparan l'habitatge. +- **Documentació acreditativa de la situació d'habitatge** (ordre de desnonament, contracte de lloguer vigent, informe social, etc.). +- **Contractes de treball** i **tres últimes nòmines** de tots els membres que generen ingressos. +- **Informe de vida laboral** o certificat d'ingressos equivalents (pensions, subsidis). +- **Certificat d'empadronament** actualitzat a Barcelona. +- Documentació addicional segons la situació: llibre de família (menors sense DNI), declaracions d'autònoms, informes d'ingressos en metàl·lic, declaració de renda o certificat d'Hisenda, certificats de pensions o d'ajuts per discapacitat. + +## Exclusions + +- Persones amb **ingressos superiors al límit de 4 vegades l'IRSC**. +- Unitats de convivència que disposen d'habitatge adequat o d'un dret d'ús suficient. +- Contractes signats fora de la mediació de la Borsa o habitatges que no compleixin els requisits de qualitat i habitabilitat establerts pel servei. + +## Ajudes alternatives + +Altres programes a considerar: + +- **Subvencions al lloguer** de la Generalitat per a joves i persones de 36-64 anys (vegeu el document «ajudes-lloguer-generalitat-2025»). +- **Habitatge de Protecció Oficial (HPO)**: registre de demandants per accedir a habitatges amb protecció oficial. +- **Ajuts municipals al lloguer**: hi ha convocatòries específiques a diversos municipis de l'àrea metropolitana de Barcelona (L'Hospitalet, Badalona, Sant Adrià, etc.). + +## Enllaços útils + +- Consorci de l'Habitatge de Barcelona – Borsa d'Habitatge: https://www.habitatgebarcelona.cat/ca/serveis/lloguer/mediacio +- Barcelona.cat – Joves i habitatge: https://ajuntament.barcelona.cat/joves/ca +- Oficines de l'Habitatge de Barcelona: https://habitatge.barcelona/ca/oficines + +## Font + +Informació extreta del **Consorci de l'Habitatge de Barcelona** i de les seves oficines d'habitatge, amb referència a la **Borsa d'Habitatge de Lloguer** i a la **Borsa Jove**, consultada el **7 de febrer de 2026**. El servei s'actualitza de manera contínua i prioritza llars amb ingressos inferiors a 2,35 vegades l'IRSC i ofereix avantatges com la cobertura de la fiança i el primer mes de lloguer. diff --git a/data/ajudes/drets-basics-inquili.txt b/data/ajudes/drets-basics-inquili.txt index 194ba3e..9862f5a 100644 --- a/data/ajudes/drets-basics-inquili.txt +++ b/data/ajudes/drets-basics-inquili.txt @@ -1,67 +1,67 @@ -# Guia de drets bàsics de l'inquilí/ina - -## Què és? - -Aquesta guia pràctica resumeix els **drets i obligacions bàsiques de les persones arrendatàries (inquilins/ines)** segons la **Llei d'Arrendaments Urbans (LAU) – Llei 29/1994** i la **Llei 12/2023 de l'habitatge**. Inclou l'actualització de la normativa vigent a 2026 i s'adreça a joves i famílies que lloguen un habitatge a Catalunya. - -## Duració mínima del contracte - -- **5 anys** quan el propietari és persona física i **7 anys** quan el propietari és una persona jurídica. -- Passat aquest termini, el contracte es prorroga **tàcitament** fins a **3 anys** més, excepte si el llogater notifica la voluntat de no renovar amb 30 dies d'antelació o el propietari amb 4 mesos d'antelació. -- En casos de vulnerabilitat acreditada, es poden concedir **pròrrogues extraordinàries** d'1 any i, en zones tensionades, fins a **tres anys addicionals**. - -## Actualització de la renda - -- L'actualització anual de la renda es limita al **2 % l'any 2023**, **3 % l'any 2024** i, a partir de **2025**, al nou **Índex de Referència d'Arrendaments d'Habitatge (IRAV)**. -- Les actualitzacions es duen a terme en la data que indiqui el contracte i només poden basar-se en l'índex publicat; no es poden aplicar increments superiors ni clàusules d'actualització automàtica per damunt d'aquests topalls. - -## Fiança i garanties - -- El **propietari ha d'exigir una fiança en metàl·lic equivalent a una mensualitat** de la renda en el lloguer d'habitatges. Per a locals comercials o altres usos és de dues mensualitats. -- La fiança **no es pot actualitzar** durant els **primer cinc anys** del contracte (o set anys si l'arrendador és persona jurídica). -- Es poden pactar **garanties addicionals**, però en l'arrendament d'habitatge no poden superar **dues mensualitats** de la renda. -- El propietari ha de retornar la fiança un cop finalitzat el contracte; si triga més d'un mes després de rebre les claus, haurà d'abonar **interessos legals**. - -## Dret de desistiment (rescissió anticipada) - -- L'inquilí pot **desistir del contracte** una vegada transcorreguts **sis mesos**, sempre que ho comuniqui al propietari amb una antelació mínima de **30 dies**. -- El contracte pot establir una **indemnització** per al propietari equivalent a una mensualitat de la renda per cada any que resti fins al compliment del contracte, o la part proporcional dels mesos restants. - -## Pròrrogues i finalització del contracte - -- Si cap de les parts notifica la seva voluntat de no renovar dins dels terminis (30 dies l'inquilí, 4 mesos el propietari), el contracte es prorroga automàticament per períodes anuals fins a tres anys. -- El propietari només pot recuperar l'habitatge abans del termini si acredita necessitat d'ús per a si mateix o familiars de primer grau i aquesta clàusula s'ha inclòs en el contracte. - -## Reparacions i manteniment - -- **El propietari** està obligat a realitzar, sense dret a augmentar la renda, **totes les reparacions necessàries** per conservar l'habitatge en condicions d'habitabilitat. Aquesta obligació queda limitada si el deteriorament és imputable a l'inquilí. -- **L'arrendatari** ha de suportar les obres de conservació que no es puguin diferir fins al final del contracte, i la renda es redueix proporcionalment si la reparació dura més de 20 dies. -- Les **petites reparacions** derivades del desgast per l'ús ordinari de l'habitatge són a càrrec de l'inquilí. -- L'inquilí ha de comunicar al propietari la necessitat de reparacions tan aviat com sigui possible i pot executar reparacions urgents per evitar danys, reclamant-ne l'import al propietari. - -## Subarrendament i cessió - -- El **subarrendament** de la totalitat de l'habitatge està prohibit tret que el propietari el consenti per escrit. En cas de subarrendar part de l'habitatge (habitacions), el preu no pot superar el lloguer proporcional i el contracte ha de respectar la LAU i la normativa autonòmica. La Llei 12/2023 ha introduït una regulació específica del lloguer d'habitacions, que obliga a formalitzar contractes escrits i a respectar les mateixes garanties de pròrroga i actualització de renda. -- La **cessió del contracte** (transmissió de la posició d'inquilí a una altra persona) requereix l'autorització prèvia del propietari. - -## Dret d'adquisició preferent (tanteig i retracte) - -- Si el propietari decideix vendre la vivenda arrendada, l'inquilí té **dret de tanteig**: pot adquirir l'habitatge en les mateixes condicions que l'oferta rebuda, en un termini de **30 dies naturals** des de la notificació. -- Si la venda es fa sense notificar o en condicions més avantatjoses, l'inquilí pot exercir el **dret de retracte** i subrogar-se en la compra en les mateixes condicions, també en un termini de **30 dies** des de la notificació de la venda. -- Aquests drets tenen preferència sobre altres drets de tanteig, excepte el retracte del condueño o el que estigui inscrit prèviament al Registre de la Propietat. -- El dret de tanteig i retracte pot ser **renunciat per pacte**; en aquest cas el propietari ha de comunicar igualment la intenció de vendre amb una antelació mínima de 30 dies. - -## Protecció contra desnonaments i mesures socials - -- La Llei 12/2023 estableix que, abans de procedir a un **desnonament per impagament**, el jutge ha de consultar els **serveis socials** per valorar la situació de vulnerabilitat de la unitat de convivència. Si es confirma la vulnerabilitat, s'han d'oferir mesures com ajornaments, lloguer social o allotjaments alternatius. -- En casos d'inquilins vulnerables en zones tensionades, el contracte pot prorrogar-se fins a **tres anys addicionals**. - -## Enllaços útils - -- BOE – Llei d'Arrendaments Urbans (text consolidat): https://www.boe.es/buscar/act.php?id=BOE-A-1994-26003 -- BOE – Llei 12/2023, del 24 de maig, pel dret a l'habitatge: https://www.boe.es/eli/es/l/2023/05/24/12 -- Institut Català del Sòl (INCASÒL) – dipòsit de fiança: https://incasol.gencat.cat - -## Font - -Informació extreta de la **Llei d'Arrendaments Urbans (LAU)** i de la **Llei 12/2023**, amb consultes realitzades el **7 de febrer de 2026**. Els articles 21, 36 i 25 de la LAU regulen respectivament les reparacions, la fiança i els drets de tanteig i retracte. La Llei 12/2023 fixa la durada mínima dels contractes, les pròrrogues i els límits d'actualització de la renda. +# Guia de drets bàsics de l'inquilí/ina + +## Què és? + +Aquesta guia pràctica resumeix els **drets i obligacions bàsiques de les persones arrendatàries (inquilins/ines)** segons la **Llei d'Arrendaments Urbans (LAU) – Llei 29/1994** i la **Llei 12/2023 de l'habitatge**. Inclou l'actualització de la normativa vigent a 2026 i s'adreça a joves i famílies que lloguen un habitatge a Catalunya. + +## Duració mínima del contracte + +- **5 anys** quan el propietari és persona física i **7 anys** quan el propietari és una persona jurídica. +- Passat aquest termini, el contracte es prorroga **tàcitament** fins a **3 anys** més, excepte si el llogater notifica la voluntat de no renovar amb 30 dies d'antelació o el propietari amb 4 mesos d'antelació. +- En casos de vulnerabilitat acreditada, es poden concedir **pròrrogues extraordinàries** d'1 any i, en zones tensionades, fins a **tres anys addicionals**. + +## Actualització de la renda + +- L'actualització anual de la renda es limita al **2 % l'any 2023**, **3 % l'any 2024** i, a partir de **2025**, al nou **Índex de Referència d'Arrendaments d'Habitatge (IRAV)**. +- Les actualitzacions es duen a terme en la data que indiqui el contracte i només poden basar-se en l'índex publicat; no es poden aplicar increments superiors ni clàusules d'actualització automàtica per damunt d'aquests topalls. + +## Fiança i garanties + +- El **propietari ha d'exigir una fiança en metàl·lic equivalent a una mensualitat** de la renda en el lloguer d'habitatges. Per a locals comercials o altres usos és de dues mensualitats. +- La fiança **no es pot actualitzar** durant els **primer cinc anys** del contracte (o set anys si l'arrendador és persona jurídica). +- Es poden pactar **garanties addicionals**, però en l'arrendament d'habitatge no poden superar **dues mensualitats** de la renda. +- El propietari ha de retornar la fiança un cop finalitzat el contracte; si triga més d'un mes després de rebre les claus, haurà d'abonar **interessos legals**. + +## Dret de desistiment (rescissió anticipada) + +- L'inquilí pot **desistir del contracte** una vegada transcorreguts **sis mesos**, sempre que ho comuniqui al propietari amb una antelació mínima de **30 dies**. +- El contracte pot establir una **indemnització** per al propietari equivalent a una mensualitat de la renda per cada any que resti fins al compliment del contracte, o la part proporcional dels mesos restants. + +## Pròrrogues i finalització del contracte + +- Si cap de les parts notifica la seva voluntat de no renovar dins dels terminis (30 dies l'inquilí, 4 mesos el propietari), el contracte es prorroga automàticament per períodes anuals fins a tres anys. +- El propietari només pot recuperar l'habitatge abans del termini si acredita necessitat d'ús per a si mateix o familiars de primer grau i aquesta clàusula s'ha inclòs en el contracte. + +## Reparacions i manteniment + +- **El propietari** està obligat a realitzar, sense dret a augmentar la renda, **totes les reparacions necessàries** per conservar l'habitatge en condicions d'habitabilitat. Aquesta obligació queda limitada si el deteriorament és imputable a l'inquilí. +- **L'arrendatari** ha de suportar les obres de conservació que no es puguin diferir fins al final del contracte, i la renda es redueix proporcionalment si la reparació dura més de 20 dies. +- Les **petites reparacions** derivades del desgast per l'ús ordinari de l'habitatge són a càrrec de l'inquilí. +- L'inquilí ha de comunicar al propietari la necessitat de reparacions tan aviat com sigui possible i pot executar reparacions urgents per evitar danys, reclamant-ne l'import al propietari. + +## Subarrendament i cessió + +- El **subarrendament** de la totalitat de l'habitatge està prohibit tret que el propietari el consenti per escrit. En cas de subarrendar part de l'habitatge (habitacions), el preu no pot superar el lloguer proporcional i el contracte ha de respectar la LAU i la normativa autonòmica. La Llei 12/2023 ha introduït una regulació específica del lloguer d'habitacions, que obliga a formalitzar contractes escrits i a respectar les mateixes garanties de pròrroga i actualització de renda. +- La **cessió del contracte** (transmissió de la posició d'inquilí a una altra persona) requereix l'autorització prèvia del propietari. + +## Dret d'adquisició preferent (tanteig i retracte) + +- Si el propietari decideix vendre la vivenda arrendada, l'inquilí té **dret de tanteig**: pot adquirir l'habitatge en les mateixes condicions que l'oferta rebuda, en un termini de **30 dies naturals** des de la notificació. +- Si la venda es fa sense notificar o en condicions més avantatjoses, l'inquilí pot exercir el **dret de retracte** i subrogar-se en la compra en les mateixes condicions, també en un termini de **30 dies** des de la notificació de la venda. +- Aquests drets tenen preferència sobre altres drets de tanteig, excepte el retracte del condueño o el que estigui inscrit prèviament al Registre de la Propietat. +- El dret de tanteig i retracte pot ser **renunciat per pacte**; en aquest cas el propietari ha de comunicar igualment la intenció de vendre amb una antelació mínima de 30 dies. + +## Protecció contra desnonaments i mesures socials + +- La Llei 12/2023 estableix que, abans de procedir a un **desnonament per impagament**, el jutge ha de consultar els **serveis socials** per valorar la situació de vulnerabilitat de la unitat de convivència. Si es confirma la vulnerabilitat, s'han d'oferir mesures com ajornaments, lloguer social o allotjaments alternatius. +- En casos d'inquilins vulnerables en zones tensionades, el contracte pot prorrogar-se fins a **tres anys addicionals**. + +## Enllaços útils + +- BOE – Llei d'Arrendaments Urbans (text consolidat): https://www.boe.es/buscar/act.php?id=BOE-A-1994-26003 +- BOE – Llei 12/2023, del 24 de maig, pel dret a l'habitatge: https://www.boe.es/eli/es/l/2023/05/24/12 +- Institut Català del Sòl (INCASÒL) – dipòsit de fiança: https://incasol.gencat.cat + +## Font + +Informació extreta de la **Llei d'Arrendaments Urbans (LAU)** i de la **Llei 12/2023**, amb consultes realitzades el **7 de febrer de 2026**. Els articles 21, 36 i 25 de la LAU regulen respectivament les reparacions, la fiança i els drets de tanteig i retracte. La Llei 12/2023 fixa la durada mínima dels contractes, les pròrrogues i els límits d'actualització de la renda. diff --git a/data/ajudes/llei-habitatge-2023-zones-tensionades.txt b/data/ajudes/llei-habitatge-2023-zones-tensionades.txt index 6a83451..7d8881a 100644 --- a/data/ajudes/llei-habitatge-2023-zones-tensionades.txt +++ b/data/ajudes/llei-habitatge-2023-zones-tensionades.txt @@ -1,57 +1,57 @@ -# Llei 12/2023 del dret a l'habitatge – Zones de mercat residencial tensat - -## Què és? - -La **Llei 12/2023, del 24 de maig, pel dret a l'habitatge** (Llei estatal d'habitatge) estableix mesures per moderar els preus del lloguer i incrementar l'oferta d'habitatge assequible. Una de les mesures clau és la declaració de **zones de mercat residencial tensat (zones tensionades)**, àmbits territorials on l'escassetat d'habitatges assequibles i l'augment de les rendes de lloguer justifiquen la intervenció pública. La Generalitat, mitjançant resolucions del Departament de Territori (Resolucions **TER/800/2024** i **TER/2408/2024**), ha declarat **271 municipis catalans** com a zones tensionades, on es limita el preu del lloguer. - -## Què és una zona tensionada? - -Una **zona de mercat residencial tensat** és un municipi o part d'un municipi on el cost mitjà de la hipoteca o del lloguer més despeses i subministraments supera el 30 % dels ingressos mitjans de les llars, o bé on el preu del lloguer ha augmentat almenys un 3 % per sobre de l'IPC en els últims cinc anys. Aquesta declaració permet aplicar topalls als increments de la renda i obligar a referenciar els nous contractes a un **índex de preus de referència**. - -## Llista de municipis declarats zona tensionada a Catalunya - -Segons les resolucions publicades al **Diari Oficial de la Generalitat de Catalunya** i a la pàgina de la Generalitat, hi ha **271 municipis** declarats zona tensionada. Les declaracions s'han fet en dues fases: la **Resolució TER/800/2024** (16 de març de 2024) amb **140 municipis**, i la **Resolució TER/2408/2024** (15 d'octubre de 2024) que n'afegeix **131**. Entre els municipis destacats hi figuren: - -- **Àrea metropolitana de Barcelona**: Barcelona, l'Hospitalet de Llobregat, Badalona, Cornellà de Llobregat, Esplugues de Llobregat, Sant Adrià de Besòs, Sant Cugat del Vallès, Sant Just Desvern, Santa Coloma de Gramenet, Viladecans, Gavà, Castelldefels, Terrassa, Sabadell, Mataró i Granollers. -- **Comarques de Girona**: Girona, Salt, Figueres, Blanes, Lloret de Mar, Palafrugell, Palamós, Olot, Banyoles i Roses. -- **Tarragona i Terres de l'Ebre**: Tarragona, Reus, Salou, Vila-seca, Cambrils, Torredembarra, Tortosa, Amposta i Sant Carles de la Ràpita. -- **Lleida**: Lleida, Balaguer, Tàrrega, Mollerussa, La Seu d'Urgell, Solsona i Tremp. -- **Altres municipis destacats**: Vic, Manresa, Igualada, Figaró-Montmany, Olesa de Montserrat, Vilanova i la Geltrú, Vilafranca del Penedès, Sitges, Castellbisbal, Ripoll, Puigcerdà, Falset, Guissona, Cerdanyola del Vallès, Palafolls, Teià, Valls, Rubí, Sant Quirze del Vallès i molts altres. - -Per consultar el **llistat complet**, la Generalitat ofereix un document en línia que enumera tots els municipis i un visor interactiu. - -## Límits de renda i regulació de preus - -En les zones tensionades, les rendes dels **nous contractes de lloguer** estan subjectes a les següents normes: - -- **Índex de referència estatal**: la renda inicial no pot superar el valor que estableix l'**índex de preus de referència del lloguer** per a la zona i les característiques de l'habitatge. Aquest índex és consultable al portal del Ministeri d'Habitatge. -- **Topall d'increment per a grans tenidors** (propietaris amb més de 10 habitatges): la renda del nou contracte no pot superar la renda del contracte anterior actualitzada amb l'índex de revisió (IPC o IRAV), excepte si l'habitatge ha estat rehabilitat o millorat. -- **Topall d'increment per a petits propietaris**: la renda no pot superar l'índex de referència estatal, encara que la renda anterior fos superior. -- **Actualització anual limitada**: els increments anuals de les rendes estan limitats al **2 % l'any 2023**, **3 % l'any 2024** i, a partir de **2025**, al nou **Índex de Referència d'Arrendaments d'Habitatge (IRAV)**. -- **Duració del contracte**: la Llei 12/2023 estableix una durada mínima de **5 anys** (7 anys si el propietari és una persona jurídica) i pròrrogues obligatòries de tres anys, amb noves pròrrogues extraordinàries d'un any per a llars vulnerables i fins a **tres anys addicionals** en zones tensionades. -- **Despeses d'agència**: les despeses de gestió immobiliària i contractació són a càrrec del propietari, no del llogater. -- **Fiança i garanties**: la fiança legal es manté en **un mes** de lloguer, i les garanties addicionals no poden superar dos mesos, conforme al que ja preveu la Llei d'Arrendaments Urbans (LAU). - -## Duració de la declaració - -La declaració d'un municipi com a zona tensionada té una vigència inicial de **tres anys**, prorrogable anualment mentre es mantinguin les condicions de tensió. La Generalitat revisa periòdicament les dades per determinar si cal renovar o aixecar la declaració. - -## Drets del inquilí en zones tensionades - -Els llogaters que viuen en una zona tensionada gaudeixen de diversos drets addicionals: - -- **Control de l'augment anual de la renda**: cap actualització pot superar el 2 % (2023), 3 % (2024) o l'IRAV (2025). -- **Renovació i pròrrogues obligatòries**: els contractes s'han d'estendre automàticament fins a 3 anys addicionals; si la llar és vulnerable, es pot concedir una pròrroga extraordinària d'1 any, i en zones tensionades fins a 3 anys. -- **Garanties limitades**: el propietari no pot exigir més d'un mes de fiança i dues mensualitats de garanties addicionals. -- **El propietari paga les despeses de gestió**: les comissions d'agència i despeses de formalització del contracte les ha d'assumir el propietari. -- **Dret a la informació**: el propietari ha de proporcionar al llogater el valor de l'índex de referència i la renda de l'anterior contracte perquè es pugui comprovar el compliment dels topalls. - -## Enllaços útils - -- Llistat oficial de municipis tensionats: https://habitatge.gencat.cat/ca/ambits/preus-ingressos-i-zones/limit-preu-lloguer/llistat-municipis-zmrt/ -- Ministeri d'Habitatge – Índex de preus de referència del lloguer: https://www.mivivienda.es/portal/web/indice-referencia-precios -- BOE – Llei 12/2023, del 24 de maig, pel dret a l'habitatge: https://www.boe.es/eli/es/l/2023/05/24/12 - -## Font - -Informació basada en la **Llei 12/2023, del dret a l'habitatge** i les resolucions **TER/800/2024** i **TER/2408/2024** de la Generalitat, consultades el **7 de febrer de 2026**. Les dades de municipis tensionats provenen de la llista publicada per la Generalitat, i els límits de renda i drets dels llogaters es basen en la normativa de la Llei 12/2023 i les notes del Ministeri d'Habitatge. +# Llei 12/2023 del dret a l'habitatge – Zones de mercat residencial tensat + +## Què és? + +La **Llei 12/2023, del 24 de maig, pel dret a l'habitatge** (Llei estatal d'habitatge) estableix mesures per moderar els preus del lloguer i incrementar l'oferta d'habitatge assequible. Una de les mesures clau és la declaració de **zones de mercat residencial tensat (zones tensionades)**, àmbits territorials on l'escassetat d'habitatges assequibles i l'augment de les rendes de lloguer justifiquen la intervenció pública. La Generalitat, mitjançant resolucions del Departament de Territori (Resolucions **TER/800/2024** i **TER/2408/2024**), ha declarat **271 municipis catalans** com a zones tensionades, on es limita el preu del lloguer. + +## Què és una zona tensionada? + +Una **zona de mercat residencial tensat** és un municipi o part d'un municipi on el cost mitjà de la hipoteca o del lloguer més despeses i subministraments supera el 30 % dels ingressos mitjans de les llars, o bé on el preu del lloguer ha augmentat almenys un 3 % per sobre de l'IPC en els últims cinc anys. Aquesta declaració permet aplicar topalls als increments de la renda i obligar a referenciar els nous contractes a un **índex de preus de referència**. + +## Llista de municipis declarats zona tensionada a Catalunya + +Segons les resolucions publicades al **Diari Oficial de la Generalitat de Catalunya** i a la pàgina de la Generalitat, hi ha **271 municipis** declarats zona tensionada. Les declaracions s'han fet en dues fases: la **Resolució TER/800/2024** (16 de març de 2024) amb **140 municipis**, i la **Resolució TER/2408/2024** (15 d'octubre de 2024) que n'afegeix **131**. Entre els municipis destacats hi figuren: + +- **Àrea metropolitana de Barcelona**: Barcelona, l'Hospitalet de Llobregat, Badalona, Cornellà de Llobregat, Esplugues de Llobregat, Sant Adrià de Besòs, Sant Cugat del Vallès, Sant Just Desvern, Santa Coloma de Gramenet, Viladecans, Gavà, Castelldefels, Terrassa, Sabadell, Mataró i Granollers. +- **Comarques de Girona**: Girona, Salt, Figueres, Blanes, Lloret de Mar, Palafrugell, Palamós, Olot, Banyoles i Roses. +- **Tarragona i Terres de l'Ebre**: Tarragona, Reus, Salou, Vila-seca, Cambrils, Torredembarra, Tortosa, Amposta i Sant Carles de la Ràpita. +- **Lleida**: Lleida, Balaguer, Tàrrega, Mollerussa, La Seu d'Urgell, Solsona i Tremp. +- **Altres municipis destacats**: Vic, Manresa, Igualada, Figaró-Montmany, Olesa de Montserrat, Vilanova i la Geltrú, Vilafranca del Penedès, Sitges, Castellbisbal, Ripoll, Puigcerdà, Falset, Guissona, Cerdanyola del Vallès, Palafolls, Teià, Valls, Rubí, Sant Quirze del Vallès i molts altres. + +Per consultar el **llistat complet**, la Generalitat ofereix un document en línia que enumera tots els municipis i un visor interactiu. + +## Límits de renda i regulació de preus + +En les zones tensionades, les rendes dels **nous contractes de lloguer** estan subjectes a les següents normes: + +- **Índex de referència estatal**: la renda inicial no pot superar el valor que estableix l'**índex de preus de referència del lloguer** per a la zona i les característiques de l'habitatge. Aquest índex és consultable al portal del Ministeri d'Habitatge. +- **Topall d'increment per a grans tenidors** (propietaris amb més de 10 habitatges): la renda del nou contracte no pot superar la renda del contracte anterior actualitzada amb l'índex de revisió (IPC o IRAV), excepte si l'habitatge ha estat rehabilitat o millorat. +- **Topall d'increment per a petits propietaris**: la renda no pot superar l'índex de referència estatal, encara que la renda anterior fos superior. +- **Actualització anual limitada**: els increments anuals de les rendes estan limitats al **2 % l'any 2023**, **3 % l'any 2024** i, a partir de **2025**, al nou **Índex de Referència d'Arrendaments d'Habitatge (IRAV)**. +- **Duració del contracte**: la Llei 12/2023 estableix una durada mínima de **5 anys** (7 anys si el propietari és una persona jurídica) i pròrrogues obligatòries de tres anys, amb noves pròrrogues extraordinàries d'un any per a llars vulnerables i fins a **tres anys addicionals** en zones tensionades. +- **Despeses d'agència**: les despeses de gestió immobiliària i contractació són a càrrec del propietari, no del llogater. +- **Fiança i garanties**: la fiança legal es manté en **un mes** de lloguer, i les garanties addicionals no poden superar dos mesos, conforme al que ja preveu la Llei d'Arrendaments Urbans (LAU). + +## Duració de la declaració + +La declaració d'un municipi com a zona tensionada té una vigència inicial de **tres anys**, prorrogable anualment mentre es mantinguin les condicions de tensió. La Generalitat revisa periòdicament les dades per determinar si cal renovar o aixecar la declaració. + +## Drets del inquilí en zones tensionades + +Els llogaters que viuen en una zona tensionada gaudeixen de diversos drets addicionals: + +- **Control de l'augment anual de la renda**: cap actualització pot superar el 2 % (2023), 3 % (2024) o l'IRAV (2025). +- **Renovació i pròrrogues obligatòries**: els contractes s'han d'estendre automàticament fins a 3 anys addicionals; si la llar és vulnerable, es pot concedir una pròrroga extraordinària d'1 any, i en zones tensionades fins a 3 anys. +- **Garanties limitades**: el propietari no pot exigir més d'un mes de fiança i dues mensualitats de garanties addicionals. +- **El propietari paga les despeses de gestió**: les comissions d'agència i despeses de formalització del contracte les ha d'assumir el propietari. +- **Dret a la informació**: el propietari ha de proporcionar al llogater el valor de l'índex de referència i la renda de l'anterior contracte perquè es pugui comprovar el compliment dels topalls. + +## Enllaços útils + +- Llistat oficial de municipis tensionats: https://habitatge.gencat.cat/ca/ambits/preus-ingressos-i-zones/limit-preu-lloguer/llistat-municipis-zmrt/ +- Ministeri d'Habitatge – Índex de preus de referència del lloguer: https://www.mivivienda.es/portal/web/indice-referencia-precios +- BOE – Llei 12/2023, del 24 de maig, pel dret a l'habitatge: https://www.boe.es/eli/es/l/2023/05/24/12 + +## Font + +Informació basada en la **Llei 12/2023, del dret a l'habitatge** i les resolucions **TER/800/2024** i **TER/2408/2024** de la Generalitat, consultades el **7 de febrer de 2026**. Les dades de municipis tensionats provenen de la llista publicada per la Generalitat, i els límits de renda i drets dels llogaters es basen en la normativa de la Llei 12/2023 i les notes del Ministeri d'Habitatge. diff --git a/docs/audit/product-audit-feedback.md b/docs/audit/product-audit-feedback.md new file mode 100644 index 0000000..5a29e44 --- /dev/null +++ b/docs/audit/product-audit-feedback.md @@ -0,0 +1,95 @@ +# Auditoría de Producto - LlarJove + +Fecha: Febrero 2026 + +## Resumen ejecutivo + +LlarJove es un asistente conversacional para jóvenes que buscan vivienda y ayudas en Cataluña. La landing comunica con claridad que pretende simplificar trámites y explicar ayudas públicas, destacando privacidad y fuentes oficiales. El flujo principal se apoya en un chat que responde preguntas con recursos y señala el nivel de confianza. La web carece de información sobre el modelo de negocio, precios o monetización y no muestra señales claras de escalabilidad. La experiencia de usuario es agradable, con un diseño limpio, pero la navegabilidad podría mejorar. Se detectan fallos de copia sin validación en formularios y ausencia de soporte directo. La propuesta de valor es útil aunque genérica y fácilmente copiable. La mayor palanca de crecimiento será la integración con fuentes oficiales y la construcción de una base de datos propia. + +## Startup hunting verdict + +**Tipo**: lifestyle business (actualmente). + +- El servicio resuelve un problema puntual y local (información sobre ayudas y alquiler en Cataluña) y no muestra escala geográfica inmediata. +- No tiene modelo de ingresos definido ni pricing; la beta es gratuita. +- La propuesta se apoya en información pública que puede ser replicada y no hay evidencia de moats fuertes. +- El chat carece de integración con trámites oficiales o automatización de procesos; ofrece respuestas orientativas. +- El canal de distribución principal parece ser una lista de espera; no se observan estrategias de adquisición masiva. + +## Puntuaciones + +| Área | Puntuación | Comentarios | +|------|------------|-------------| +| Propuesta de valor & diferenciación | 5/10 | Información pública, sin funciones exclusivas | +| UX/UI & accesibilidad | 7/10 | Diseño limpio, falta contraste y versión castellano completa | +| Copywriting | 6/10 | Claro pero repetitivo, sin storytelling emocional | +| Conversión (CTA, fricciones, funnel) | 4/10 | CTA lleva a beta, formulario sin confirmación, sin pricing | +| Credibilidad (trust signals) | 6/10 | Cita fuentes oficiales, sin testimonios ni certificaciones | +| SEO/discovery | 5/10 | H1/H2 correctos pero sin meta-description, sin blog | +| Performance | 8/10 | Carga rápida, chat responsive, sin estados de error amigables | +| Monetización/pricing | 2/10 | No hay modelo de negocio visible | +| Retención | 4/10 | Sin motivos para volver, sin notificaciones ni historial | +| **Startup potential score** | **5/10** | Potencial de nicho local, falta modelo de ingresos y moat | + +## Top 10 problemas por impacto + +1. **Ausencia de modelo de negocio** (muy alto) — No hay precios ni servicios de pago +2. **Fácilmente copiable** (alto) — Se basa en información pública +3. **Flujo de retención débil** (alto) — Sin historial, sin recordatorios +4. **Formulario de lista confuso** (medio) — Sin confirmación, sin explicar beneficios +5. **Falta de soporte/contacto** (medio) — "Contacto" apunta a sección lista +6. **Idiomas inconsistentes** (medio) — Mezcla catalán y castellano +7. **Sin social proof** (medio) — Sin testimonios ni casos de uso +8. **Navegación anclada confusa** (medio) — Todo en misma página, sin URLs propias +9. **Falta de accesibilidad** (bajo) — Sin alt-text, contrastes limitados +10. **Sin estrategia de adquisición** (medio) — Sin marketing de contenidos + +## Quick wins + +### ≤2 horas +1. Añadir mensaje de confirmación tras suscribirse +2. Uniformar idioma (un idioma por defecto + selector) +3. Corregir enlace "Contacto" del footer +4. Incluir meta-description y títulos SEO +5. Añadir alt-text a imágenes + +### ≤1 día +6. Actualizar copy del formulario con beneficios concretos +7. Crear sección de testimonios (2-3 casos) +8. Publicar post sobre Bono Alquiler Joven +9. Configurar analytics (Google Analytics / Matomo) +10. Email de bienvenida para lista de espera + +### ≤1 semana +11. MVP de cuenta de usuario con historial y notificaciones +12. Enlace desde oficina de vivienda +13. Plan freemium +14. Localización completa (catalán, castellano, inglés) +15. Prueba de usabilidad con 5 usuarios + +## Backlog priorizado + +| Tarea | Impacto | Esfuerzo | KPI | +|-------|---------|----------|-----| +| Definir modelo de ingresos | Alto | Medio | Revenue, conversión a pago | +| Cuentas con historial y alertas | Alto | Alto | Retención (DAU/MAU) | +| Acuerdos con entidades oficiales | Alto | Alto | Moat, credibilidad | +| Rediseñar formulario + confirmación | Medio | Bajo | Tasa de suscripción | +| Testimonios y casos de uso | Medio | Bajo | Credibilidad y conversión | +| Copy y localización de idiomas | Medio | Bajo | Bounce rate | +| Contenido SEO y newsletter | Medio | Medio | Tráfico orgánico | +| Soporte de contacto directo | Bajo | Bajo | NPS, satisfacción | +| Accesibilidad y performance | Bajo | Medio | Lighthouse scores | +| Analítica y eventos de producto | Medio | Bajo | Conversión y retención | + +## Posicionamiento sugerido + +### Hero section +- **Headline**: "Encuentra vivienda y ayudas en Cataluña sin perderte." +- **Subheadline**: "Te guiamos paso a paso con información verificada, trámites automatizados y alertas personalizadas." +- **CTA**: "Prueba el asistente gratis" (principal) + "Únete a la beta" (secundario) + +### Slogans propuestos +1. "Que el alquiler no te pare: encontramos tu camino en Cataluña." +2. "Deja los PDFs; nosotros te guiamos." +3. "Vive sin dramas: ayudas, derechos y vivienda, claro y al momento." diff --git a/package.json b/package.json index 5405eee..833e310 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,47 @@ -{ - "name": "llarjove", - "version": "0.1.0", - "description": "RAG chatbot per ajudar joves catalans a trobar habitatge - Informació sobre ajudes, drets i recursos", - "main": "dist/index.js", - "type": "module", - "scripts": { - "build": "tsc", - "dev": "tsx watch src/index.ts", - "start": "node dist/index.js", - "ingest": "tsx src/scripts/ingest.ts", - "test": "vitest run", - "test:watch": "vitest", - "typecheck": "tsc --noEmit", - "ci": "pnpm typecheck && pnpm test && pnpm build", - "dev:web": "pnpm --dir web dev", - "build:web": "pnpm --dir web build", - "test:web": "pnpm --dir web test" - }, - "keywords": [ - "rag", - "habitatge", - "joves", - "catalunya", - "ajudes", - "vivienda" - ], - "author": "Charles", - "license": "MIT", - "dependencies": { - "@fastify/cors": "^9.0.1", - "chromadb": "^1.8.1", - "dotenv": "^16.4.5", - "fastify": "^4.28.1", - "openai": "^4.52.7", - "pdf-parse": "^1.1.1", - "uuid": "^10.0.0" - }, - "devDependencies": { - "@types/node": "^20.14.10", - "@types/pdf-parse": "^1.1.4", - "@types/uuid": "^10.0.0", - "tsx": "^4.16.2", - "typescript": "^5.5.3", - "vitest": "^2.0.2" - } -} +{ + "name": "llarjove", + "version": "0.1.0", + "description": "RAG chatbot per ajudar joves catalans a trobar habitatge - Informació sobre ajudes, drets i recursos", + "main": "dist/index.js", + "type": "module", + "scripts": { + "build": "tsc", + "dev": "tsx watch src/index.ts", + "start": "node dist/index.js", + "ingest": "tsx src/scripts/ingest.ts", + "test": "vitest run", + "test:watch": "vitest", + "typecheck": "tsc --noEmit", + "ci": "pnpm typecheck && pnpm test && pnpm build", + "dev:web": "pnpm --dir web dev", + "build:web": "pnpm --dir web build", + "test:web": "pnpm --dir web test" + }, + "keywords": [ + "rag", + "habitatge", + "joves", + "catalunya", + "ajudes", + "vivienda" + ], + "author": "Charles", + "license": "MIT", + "dependencies": { + "@fastify/cors": "^9.0.1", + "chromadb": "^1.8.1", + "dotenv": "^16.4.5", + "fastify": "^4.28.1", + "openai": "^4.52.7", + "pdf-parse": "^1.1.1", + "uuid": "^10.0.0" + }, + "devDependencies": { + "@types/node": "^20.14.10", + "@types/pdf-parse": "^1.1.4", + "@types/uuid": "^10.0.0", + "tsx": "^4.16.2", + "typescript": "^5.5.3", + "vitest": "^2.0.2" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4612c4..2de20f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,518 +1,776 @@ -lockfileVersion: '9.0' +lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -importers: - - .: - dependencies: - '@fastify/cors': - specifier: ^9.0.1 - version: 9.0.1 - chromadb: - specifier: ^1.8.1 - version: 1.10.5(openai@4.104.0) - dotenv: - specifier: ^16.4.5 - version: 16.6.1 - fastify: - specifier: ^4.28.1 - version: 4.29.1 - openai: - specifier: ^4.52.7 - version: 4.104.0 - pdf-parse: - specifier: ^1.1.1 - version: 1.1.4 - uuid: - specifier: ^10.0.0 - version: 10.0.0 - devDependencies: - '@types/node': - specifier: ^20.14.10 - version: 20.19.30 - '@types/pdf-parse': - specifier: ^1.1.4 - version: 1.1.5 - '@types/uuid': - specifier: ^10.0.0 - version: 10.0.0 - tsx: - specifier: ^4.16.2 - version: 4.21.0 - typescript: - specifier: ^5.5.3 - version: 5.9.3 - vitest: - specifier: ^2.0.2 - version: 2.1.9(@types/node@20.19.30) +dependencies: + '@fastify/cors': + specifier: ^9.0.1 + version: 9.0.1 + chromadb: + specifier: ^1.8.1 + version: 1.10.5(openai@4.104.0) + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + fastify: + specifier: ^4.28.1 + version: 4.29.1 + openai: + specifier: ^4.52.7 + version: 4.104.0 + pdf-parse: + specifier: ^1.1.1 + version: 1.1.4 + uuid: + specifier: ^10.0.0 + version: 10.0.0 + +devDependencies: + '@types/node': + specifier: ^20.14.10 + version: 20.19.32 + '@types/pdf-parse': + specifier: ^1.1.4 + version: 1.1.5 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + tsx: + specifier: ^4.16.2 + version: 4.21.0 + typescript: + specifier: ^5.5.3 + version: 5.9.3 + vitest: + specifier: ^2.0.2 + version: 2.1.9(@types/node@20.19.32) packages: - '@esbuild/aix-ppc64@0.21.5': + /@esbuild/aix-ppc64@0.21.5: resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] + requiresBuild: true + dev: true + optional: true - '@esbuild/aix-ppc64@0.27.2': - resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + /@esbuild/aix-ppc64@0.27.3: + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm64@0.21.5': + /@esbuild/android-arm64@0.21.5: resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm64@0.27.2': - resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + /@esbuild/android-arm64@0.27.3: + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm@0.21.5': + /@esbuild/android-arm@0.21.5: resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm@0.27.2': - resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + /@esbuild/android-arm@0.27.3: + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-x64@0.21.5': + /@esbuild/android-x64@0.21.5: resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-x64@0.27.2': - resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + /@esbuild/android-x64@0.27.3: + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-arm64@0.21.5': + /@esbuild/darwin-arm64@0.21.5: resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-arm64@0.27.2': - resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + /@esbuild/darwin-arm64@0.27.3: + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-x64@0.21.5': + /@esbuild/darwin-x64@0.21.5: resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-x64@0.27.2': - resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + /@esbuild/darwin-x64@0.27.3: + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-arm64@0.21.5': + /@esbuild/freebsd-arm64@0.21.5: resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-arm64@0.27.2': - resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + /@esbuild/freebsd-arm64@0.27.3: + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-x64@0.21.5': + /@esbuild/freebsd-x64@0.21.5: resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-x64@0.27.2': - resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + /@esbuild/freebsd-x64@0.27.3: + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm64@0.21.5': + /@esbuild/linux-arm64@0.21.5: resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm64@0.27.2': - resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + /@esbuild/linux-arm64@0.27.3: + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm@0.21.5': + /@esbuild/linux-arm@0.21.5: resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm@0.27.2': - resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + /@esbuild/linux-arm@0.27.3: + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ia32@0.21.5': + /@esbuild/linux-ia32@0.21.5: resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ia32@0.27.2': - resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + /@esbuild/linux-ia32@0.27.3: + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-loong64@0.21.5': + /@esbuild/linux-loong64@0.21.5: resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-loong64@0.27.2': - resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + /@esbuild/linux-loong64@0.27.3: + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-mips64el@0.21.5': + /@esbuild/linux-mips64el@0.21.5: resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-mips64el@0.27.2': - resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + /@esbuild/linux-mips64el@0.27.3: + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ppc64@0.21.5': + /@esbuild/linux-ppc64@0.21.5: resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ppc64@0.27.2': - resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + /@esbuild/linux-ppc64@0.27.3: + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-riscv64@0.21.5': + /@esbuild/linux-riscv64@0.21.5: resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-riscv64@0.27.2': - resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + /@esbuild/linux-riscv64@0.27.3: + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-s390x@0.21.5': + /@esbuild/linux-s390x@0.21.5: resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-s390x@0.27.2': - resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + /@esbuild/linux-s390x@0.27.3: + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-x64@0.21.5': + /@esbuild/linux-x64@0.21.5: resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-x64@0.27.2': - resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + /@esbuild/linux-x64@0.27.3: + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-arm64@0.27.2': - resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + /@esbuild/netbsd-arm64@0.27.3: + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-x64@0.21.5': + /@esbuild/netbsd-x64@0.21.5: resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-x64@0.27.2': - resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + /@esbuild/netbsd-x64@0.27.3: + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-arm64@0.27.2': - resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + /@esbuild/openbsd-arm64@0.27.3: + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-x64@0.21.5': + /@esbuild/openbsd-x64@0.21.5: resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-x64@0.27.2': - resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + /@esbuild/openbsd-x64@0.27.3: + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openharmony-arm64@0.27.2': - resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + /@esbuild/openharmony-arm64@0.27.3: + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@esbuild/sunos-x64@0.21.5': + /@esbuild/sunos-x64@0.21.5: resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: true + optional: true - '@esbuild/sunos-x64@0.27.2': - resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + /@esbuild/sunos-x64@0.27.3: + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-arm64@0.21.5': + /@esbuild/win32-arm64@0.21.5: resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-arm64@0.27.2': - resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + /@esbuild/win32-arm64@0.27.3: + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-ia32@0.21.5': + /@esbuild/win32-ia32@0.21.5: resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-ia32@0.27.2': - resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + /@esbuild/win32-ia32@0.27.3: + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-x64@0.21.5': + /@esbuild/win32-x64@0.21.5: resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-x64@0.27.2': - resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + /@esbuild/win32-x64@0.27.3: + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@fastify/ajv-compiler@3.6.0': + /@fastify/ajv-compiler@3.6.0: resolution: {integrity: sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==} + dependencies: + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + fast-uri: 2.4.0 + dev: false - '@fastify/cors@9.0.1': + /@fastify/cors@9.0.1: resolution: {integrity: sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==} + dependencies: + fastify-plugin: 4.5.1 + mnemonist: 0.39.6 + dev: false - '@fastify/error@3.4.1': + /@fastify/error@3.4.1: resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==} + dev: false - '@fastify/fast-json-stringify-compiler@4.3.0': + /@fastify/fast-json-stringify-compiler@4.3.0: resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} + dependencies: + fast-json-stringify: 5.16.1 + dev: false - '@fastify/merge-json-schemas@0.1.1': + /@fastify/merge-json-schemas@0.1.1: resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} + dependencies: + fast-deep-equal: 3.1.3 + dev: false - '@jridgewell/sourcemap-codec@1.5.5': + /@jridgewell/sourcemap-codec@1.5.5: resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + dev: true - '@pinojs/redact@0.4.0': + /@pinojs/redact@0.4.0: resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + dev: false - '@rollup/rollup-android-arm-eabi@4.57.1': + /@rollup/rollup-android-arm-eabi@4.57.1: resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-android-arm64@4.57.1': + /@rollup/rollup-android-arm64@4.57.1: resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-darwin-arm64@4.57.1': + /@rollup/rollup-darwin-arm64@4.57.1: resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-darwin-x64@4.57.1': + /@rollup/rollup-darwin-x64@4.57.1: resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-freebsd-arm64@4.57.1': + /@rollup/rollup-freebsd-arm64@4.57.1: resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-freebsd-x64@4.57.1': + /@rollup/rollup-freebsd-x64@4.57.1: resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + /@rollup/rollup-linux-arm-gnueabihf@4.57.1: resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm-musleabihf@4.57.1': + /@rollup/rollup-linux-arm-musleabihf@4.57.1: resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-gnu@4.57.1': + /@rollup/rollup-linux-arm64-gnu@4.57.1: resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-musl@4.57.1': + /@rollup/rollup-linux-arm64-musl@4.57.1: resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-loong64-gnu@4.57.1': + /@rollup/rollup-linux-loong64-gnu@4.57.1: resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-loong64-musl@4.57.1': + /@rollup/rollup-linux-loong64-musl@4.57.1: resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-ppc64-gnu@4.57.1': + /@rollup/rollup-linux-ppc64-gnu@4.57.1: resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-ppc64-musl@4.57.1': + /@rollup/rollup-linux-ppc64-musl@4.57.1: resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-riscv64-gnu@4.57.1': + /@rollup/rollup-linux-riscv64-gnu@4.57.1: resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-riscv64-musl@4.57.1': + /@rollup/rollup-linux-riscv64-musl@4.57.1: resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-s390x-gnu@4.57.1': + /@rollup/rollup-linux-s390x-gnu@4.57.1: resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-x64-gnu@4.57.1': + /@rollup/rollup-linux-x64-gnu@4.57.1: resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-x64-musl@4.57.1': + /@rollup/rollup-linux-x64-musl@4.57.1: resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-openbsd-x64@4.57.1': + /@rollup/rollup-openbsd-x64@4.57.1: resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-openharmony-arm64@4.57.1': + /@rollup/rollup-openharmony-arm64@4.57.1: resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} cpu: [arm64] os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-arm64-msvc@4.57.1': + /@rollup/rollup-win32-arm64-msvc@4.57.1: resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-ia32-msvc@4.57.1': + /@rollup/rollup-win32-ia32-msvc@4.57.1: resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-x64-gnu@4.57.1': + /@rollup/rollup-win32-x64-gnu@4.57.1: resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-x64-msvc@4.57.1': + /@rollup/rollup-win32-x64-msvc@4.57.1: resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@types/estree@1.0.8': + /@types/estree@1.0.8: resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + dev: true - '@types/node-fetch@2.6.13': + /@types/node-fetch@2.6.13: resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + dependencies: + '@types/node': 20.19.32 + form-data: 4.0.5 + dev: false - '@types/node@18.19.130': + /@types/node@18.19.130: resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + dependencies: + undici-types: 5.26.5 + dev: false - '@types/node@20.19.30': - resolution: {integrity: sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==} + /@types/node@20.19.32: + resolution: {integrity: sha512-Ez8QE4DMfhjjTsES9K2dwfV258qBui7qxUsoaixZDiTzbde4U12e1pXGNu/ECsUIOi5/zoCxAQxIhQnaUQ2VvA==} + dependencies: + undici-types: 6.21.0 - '@types/pdf-parse@1.1.5': + /@types/pdf-parse@1.1.5: resolution: {integrity: sha512-kBfrSXsloMnUJOKi25s3+hRmkycHfLK6A09eRGqF/N8BkQoPUmaCr+q8Cli5FnfohEz/rsv82zAiPz/LXtOGhA==} + dependencies: + '@types/node': 20.19.32 + dev: true - '@types/uuid@10.0.0': + /@types/uuid@10.0.0: resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + dev: true - '@vitest/expect@2.1.9': + /@vitest/expect@2.1.9: resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + tinyrainbow: 1.2.0 + dev: true - '@vitest/mocker@2.1.9': + /@vitest/mocker@2.1.9(vite@5.4.21): resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} peerDependencies: msw: ^2.4.9 @@ -522,91 +780,160 @@ packages: optional: true vite: optional: true + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + vite: 5.4.21(@types/node@20.19.32) + dev: true - '@vitest/pretty-format@2.1.9': + /@vitest/pretty-format@2.1.9: resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} + dependencies: + tinyrainbow: 1.2.0 + dev: true - '@vitest/runner@2.1.9': + /@vitest/runner@2.1.9: resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} + dependencies: + '@vitest/utils': 2.1.9 + pathe: 1.1.2 + dev: true - '@vitest/snapshot@2.1.9': + /@vitest/snapshot@2.1.9: resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.21 + pathe: 1.1.2 + dev: true - '@vitest/spy@2.1.9': + /@vitest/spy@2.1.9: resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + dependencies: + tinyspy: 3.0.2 + dev: true - '@vitest/utils@2.1.9': + /@vitest/utils@2.1.9: resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + dependencies: + '@vitest/pretty-format': 2.1.9 + loupe: 3.2.1 + tinyrainbow: 1.2.0 + dev: true - abort-controller@3.0.0: + /abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false - abstract-logging@2.0.1: + /abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + dev: false - agentkeepalive@4.6.0: + /agentkeepalive@4.6.0: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} + dependencies: + humanize-ms: 1.2.1 + dev: false - ajv-formats@2.1.1: + /ajv-formats@2.1.1(ajv@8.17.1): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: ajv: ^8.0.0 peerDependenciesMeta: ajv: optional: true + dependencies: + ajv: 8.17.1 + dev: false - ajv-formats@3.0.1: + /ajv-formats@3.0.1(ajv@8.17.1): resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: ajv: ^8.0.0 peerDependenciesMeta: ajv: optional: true + dependencies: + ajv: 8.17.1 + dev: false - ajv@8.17.1: + /ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + dev: false - ansi-regex@5.0.1: + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + dev: false - ansi-styles@4.3.0: + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: false - assertion-error@2.0.1: + /assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + dev: true - asynckit@0.4.0: + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false - atomic-sleep@1.0.0: + /atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} + dev: false - avvio@8.4.0: + /avvio@8.4.0: resolution: {integrity: sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==} + dependencies: + '@fastify/error': 3.4.1 + fastq: 1.20.1 + dev: false - cac@6.7.14: + /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + dev: true - call-bind-apply-helpers@1.0.2: + /call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + dev: false - chai@5.3.3: + /chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + dev: true - check-error@2.1.3: + /check-error@2.1.3: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} + dev: true - chromadb@1.10.5: + /chromadb@1.10.5(openai@4.104.0): resolution: {integrity: sha512-+IeTjjf44pKUY3vp1BacwO2tFAPcWCd64zxPZZm98dVj/kbSBeaHKB2D6eX7iRLHS1PTVASuqoR6mAJ+nrsTBg==} engines: {node: '>=14.17.0'} peerDependencies: @@ -626,27 +953,47 @@ packages: optional: true voyageai: optional: true + dependencies: + cliui: 8.0.1 + isomorphic-fetch: 3.0.0 + openai: 4.104.0 + transitivePeerDependencies: + - encoding + dev: false - cliui@8.0.1: + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false - color-convert@2.0.1: + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: false - color-name@1.1.4: + /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false - combined-stream@1.0.8: + /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false - cookie@0.7.2: + /cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + dev: false - debug@4.4.3: + /debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: @@ -654,211 +1001,418 @@ packages: peerDependenciesMeta: supports-color: optional: true + dependencies: + ms: 2.1.3 + dev: true - deep-eql@5.0.2: + /deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + dev: true - delayed-stream@1.0.0: + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + dev: false - dotenv@16.6.1: + /dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} + dev: false - dunder-proto@1.0.1: + /dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + dev: false - emoji-regex@8.0.0: + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false - es-define-property@1.0.1: + /es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} + dev: false - es-errors@1.3.0: + /es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + dev: false - es-module-lexer@1.7.0: + /es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + dev: true - es-object-atoms@1.1.1: + /es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: false - es-set-tostringtag@2.1.0: + /es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: false - esbuild@0.21.5: + /esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + dev: true - esbuild@0.27.2: - resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + /esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} hasBin: true - - estree-walker@3.0.3: + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + dev: true + + /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.8 + dev: true - event-target-shim@5.0.1: + /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + dev: false - expect-type@1.3.0: + /expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + dev: true - fast-content-type-parse@1.1.0: + /fast-content-type-parse@1.1.0: resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} + dev: false - fast-decode-uri-component@1.0.1: + /fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + dev: false - fast-deep-equal@3.1.3: + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: false - fast-json-stringify@5.16.1: + /fast-json-stringify@5.16.1: resolution: {integrity: sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==} + dependencies: + '@fastify/merge-json-schemas': 0.1.1 + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + fast-deep-equal: 3.1.3 + fast-uri: 2.4.0 + json-schema-ref-resolver: 1.0.1 + rfdc: 1.4.1 + dev: false - fast-querystring@1.1.2: + /fast-querystring@1.1.2: resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: false - fast-uri@2.4.0: + /fast-uri@2.4.0: resolution: {integrity: sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==} + dev: false - fast-uri@3.1.0: + /fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + dev: false - fastify-plugin@4.5.1: + /fastify-plugin@4.5.1: resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} + dev: false - fastify@4.29.1: + /fastify@4.29.1: resolution: {integrity: sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==} + dependencies: + '@fastify/ajv-compiler': 3.6.0 + '@fastify/error': 3.4.1 + '@fastify/fast-json-stringify-compiler': 4.3.0 + abstract-logging: 2.0.1 + avvio: 8.4.0 + fast-content-type-parse: 1.1.0 + fast-json-stringify: 5.16.1 + find-my-way: 8.2.2 + light-my-request: 5.14.0 + pino: 9.14.0 + process-warning: 3.0.0 + proxy-addr: 2.0.7 + rfdc: 1.4.1 + secure-json-parse: 2.7.0 + semver: 7.7.4 + toad-cache: 3.7.0 + dev: false - fastq@1.20.1: + /fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + dependencies: + reusify: 1.1.0 + dev: false - find-my-way@8.2.2: + /find-my-way@8.2.2: resolution: {integrity: sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==} engines: {node: '>=14'} + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 3.1.0 + dev: false - form-data-encoder@1.7.2: + /form-data-encoder@1.7.2: resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + dev: false - form-data@4.0.5: + /form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + dev: false - formdata-node@4.4.1: + /formdata-node@4.4.1: resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} engines: {node: '>= 12.20'} + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + dev: false - forwarded@0.2.0: + /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + dev: false - fsevents@2.3.3: + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + requiresBuild: true + dev: true + optional: true - function-bind@1.1.2: + /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: false - get-intrinsic@1.3.0: + /get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + 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 + dev: false - get-proto@1.0.1: + /get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + dev: false - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + /get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true - gopd@1.2.0: + /gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + dev: false - has-symbols@1.1.0: + /has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + dev: false - has-tostringtag@1.0.2: + /has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.1.0 + dev: false - hasown@2.0.2: + /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: false - humanize-ms@1.2.1: + /humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + dependencies: + ms: 2.1.3 + dev: false - ipaddr.js@1.9.1: + /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + dev: false - is-fullwidth-code-point@3.0.0: + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + dev: false - isomorphic-fetch@3.0.0: + /isomorphic-fetch@3.0.0: resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} + dependencies: + node-fetch: 2.7.0 + whatwg-fetch: 3.6.20 + transitivePeerDependencies: + - encoding + dev: false - json-schema-ref-resolver@1.0.1: + /json-schema-ref-resolver@1.0.1: resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} + dependencies: + fast-deep-equal: 3.1.3 + dev: false - json-schema-traverse@1.0.0: + /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: false - light-my-request@5.14.0: + /light-my-request@5.14.0: resolution: {integrity: sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==} + dependencies: + cookie: 0.7.2 + process-warning: 3.0.0 + set-cookie-parser: 2.7.2 + dev: false - loupe@3.2.1: + /loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + dev: true - magic-string@0.30.21: + /magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + dev: true - math-intrinsics@1.1.0: + /math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + dev: false - mime-db@1.52.0: + /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + dev: false - mime-types@2.1.35: + /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false - mnemonist@0.39.6: + /mnemonist@0.39.6: resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==} + dependencies: + obliterator: 2.0.5 + dev: false - ms@2.1.3: + /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: + /nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + dev: true - node-domexception@1.0.0: + /node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead + dev: false - node-ensure@0.0.0: + /node-ensure@0.0.0: resolution: {integrity: sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==} + dev: false - node-fetch@2.7.0: + /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} peerDependencies: @@ -866,15 +1420,20 @@ packages: peerDependenciesMeta: encoding: optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false - obliterator@2.0.5: + /obliterator@2.0.5: resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==} + dev: false - on-exit-leak-free@2.1.2: + /on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} + dev: false - openai@4.104.0: + /openai@4.104.0: resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} hasBin: true peerDependencies: @@ -885,175 +1444,316 @@ packages: optional: true zod: optional: true + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false - pathe@1.1.2: + /pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: true - pathval@2.0.1: + /pathval@2.0.1: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + dev: true - pdf-parse@1.1.4: + /pdf-parse@1.1.4: resolution: {integrity: sha512-XRIRcLgk6ZnUbsHsYXExMw+krrPE81hJ6FQPLdBNhhBefqIQKXu/WeTgNBGSwPrfU0v+UCEwn7AoAUOsVKHFvQ==} engines: {node: '>=6.8.1'} + dependencies: + node-ensure: 0.0.0 + dev: false - picocolors@1.1.1: + /picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + dev: true - pino-abstract-transport@2.0.0: + /pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + dependencies: + split2: 4.2.0 + dev: false - pino-std-serializers@7.1.0: + /pino-std-serializers@7.1.0: resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + dev: false - pino@9.14.0: + /pino@9.14.0: resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} hasBin: true + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + dev: false - postcss@8.5.6: + /postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true - process-warning@3.0.0: + /process-warning@3.0.0: resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + dev: false - process-warning@5.0.0: + /process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + dev: false - proxy-addr@2.0.7: + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: false - quick-format-unescaped@4.0.4: + /quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false - real-require@0.2.0: + /real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + dev: false - require-from-string@2.0.2: + /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + dev: false - resolve-pkg-maps@1.0.0: + /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true - ret@0.4.3: + /ret@0.4.3: resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==} engines: {node: '>=10'} + dev: false - reusify@1.1.0: + /reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: false - rfdc@1.4.1: + /rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + dev: false - rollup@4.57.1: + /rollup@4.57.1: resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 + fsevents: 2.3.3 + dev: true - safe-regex2@3.1.0: + /safe-regex2@3.1.0: resolution: {integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==} + dependencies: + ret: 0.4.3 + dev: false - safe-stable-stringify@2.5.0: + /safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} + dev: false - secure-json-parse@2.7.0: + /secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + /semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true + dev: false - set-cookie-parser@2.7.2: + /set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + dev: false - siginfo@2.0.0: + /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true - sonic-boom@4.2.0: + /sonic-boom@4.2.0: resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + dependencies: + atomic-sleep: 1.0.0 + dev: false - source-map-js@1.2.1: + /source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + dev: true - split2@4.2.0: + /split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + dev: false - stackback@0.0.2: + /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true - std-env@3.10.0: + /std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + dev: true - string-width@4.2.3: + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false - strip-ansi@6.0.1: + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false - thread-stream@3.1.0: + /thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + dependencies: + real-require: 0.2.0 + dev: false - tinybench@2.9.0: + /tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + dev: true - tinyexec@0.3.2: + /tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + dev: true - tinypool@1.1.1: + /tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} + dev: true - tinyrainbow@1.2.0: + /tinyrainbow@1.2.0: resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} engines: {node: '>=14.0.0'} + dev: true - tinyspy@3.0.2: + /tinyspy@3.0.2: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + dev: true - toad-cache@3.7.0: + /toad-cache@3.7.0: resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} engines: {node: '>=12'} + dev: false - tr46@0.0.3: + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false - tsx@4.21.0: + /tsx@4.21.0: resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true + dependencies: + esbuild: 0.27.3 + get-tsconfig: 4.13.6 + optionalDependencies: + fsevents: 2.3.3 + dev: true - typescript@5.9.3: + /typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true + dev: true - undici-types@5.26.5: + /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: false - undici-types@6.21.0: + /undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - uuid@10.0.0: + /uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true + dev: false - vite-node@2.1.9: + /vite-node@2.1.9(@types/node@20.19.32): resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21(@types/node@20.19.32) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + dev: true - vite@5.4.21: + /vite@5.4.21(@types/node@20.19.32): resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -1083,8 +1783,16 @@ packages: optional: true terser: optional: true + dependencies: + '@types/node': 20.19.32 + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.57.1 + optionalDependencies: + fsevents: 2.3.3 + dev: true - vitest@2.1.9: + /vitest@2.1.9(@types/node@20.19.32): resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -1108,943 +1816,74 @@ packages: optional: true jsdom: optional: true + dependencies: + '@types/node': 20.19.32 + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.21) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 1.1.2 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.21(@types/node@20.19.32) + vite-node: 2.1.9(@types/node@20.19.32) + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + dev: true - web-streams-polyfill@4.0.0-beta.3: + /web-streams-polyfill@4.0.0-beta.3: resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} engines: {node: '>= 14'} + dev: false - webidl-conversions@3.0.1: + /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false - whatwg-fetch@3.6.20: + /whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + dev: false - whatwg-url@5.0.0: + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false - why-is-node-running@2.3.0: + /why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true - wrap-ansi@7.0.0: + /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - -snapshots: - - '@esbuild/aix-ppc64@0.21.5': - optional: true - - '@esbuild/aix-ppc64@0.27.2': - optional: true - - '@esbuild/android-arm64@0.21.5': - optional: true - - '@esbuild/android-arm64@0.27.2': - optional: true - - '@esbuild/android-arm@0.21.5': - optional: true - - '@esbuild/android-arm@0.27.2': - optional: true - - '@esbuild/android-x64@0.21.5': - optional: true - - '@esbuild/android-x64@0.27.2': - optional: true - - '@esbuild/darwin-arm64@0.21.5': - optional: true - - '@esbuild/darwin-arm64@0.27.2': - optional: true - - '@esbuild/darwin-x64@0.21.5': - optional: true - - '@esbuild/darwin-x64@0.27.2': - optional: true - - '@esbuild/freebsd-arm64@0.21.5': - optional: true - - '@esbuild/freebsd-arm64@0.27.2': - optional: true - - '@esbuild/freebsd-x64@0.21.5': - optional: true - - '@esbuild/freebsd-x64@0.27.2': - optional: true - - '@esbuild/linux-arm64@0.21.5': - optional: true - - '@esbuild/linux-arm64@0.27.2': - optional: true - - '@esbuild/linux-arm@0.21.5': - optional: true - - '@esbuild/linux-arm@0.27.2': - optional: true - - '@esbuild/linux-ia32@0.21.5': - optional: true - - '@esbuild/linux-ia32@0.27.2': - optional: true - - '@esbuild/linux-loong64@0.21.5': - optional: true - - '@esbuild/linux-loong64@0.27.2': - optional: true - - '@esbuild/linux-mips64el@0.21.5': - optional: true - - '@esbuild/linux-mips64el@0.27.2': - optional: true - - '@esbuild/linux-ppc64@0.21.5': - optional: true - - '@esbuild/linux-ppc64@0.27.2': - optional: true - - '@esbuild/linux-riscv64@0.21.5': - optional: true - - '@esbuild/linux-riscv64@0.27.2': - optional: true - - '@esbuild/linux-s390x@0.21.5': - optional: true - - '@esbuild/linux-s390x@0.27.2': - optional: true - - '@esbuild/linux-x64@0.21.5': - optional: true - - '@esbuild/linux-x64@0.27.2': - optional: true - - '@esbuild/netbsd-arm64@0.27.2': - optional: true - - '@esbuild/netbsd-x64@0.21.5': - optional: true - - '@esbuild/netbsd-x64@0.27.2': - optional: true - - '@esbuild/openbsd-arm64@0.27.2': - optional: true - - '@esbuild/openbsd-x64@0.21.5': - optional: true - - '@esbuild/openbsd-x64@0.27.2': - optional: true - - '@esbuild/openharmony-arm64@0.27.2': - optional: true - - '@esbuild/sunos-x64@0.21.5': - optional: true - - '@esbuild/sunos-x64@0.27.2': - optional: true - - '@esbuild/win32-arm64@0.21.5': - optional: true - - '@esbuild/win32-arm64@0.27.2': - optional: true - - '@esbuild/win32-ia32@0.21.5': - optional: true - - '@esbuild/win32-ia32@0.27.2': - optional: true - - '@esbuild/win32-x64@0.21.5': - optional: true - - '@esbuild/win32-x64@0.27.2': - optional: true - - '@fastify/ajv-compiler@3.6.0': - dependencies: - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - fast-uri: 2.4.0 - - '@fastify/cors@9.0.1': - dependencies: - fastify-plugin: 4.5.1 - mnemonist: 0.39.6 - - '@fastify/error@3.4.1': {} - - '@fastify/fast-json-stringify-compiler@4.3.0': - dependencies: - fast-json-stringify: 5.16.1 - - '@fastify/merge-json-schemas@0.1.1': - dependencies: - fast-deep-equal: 3.1.3 - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@pinojs/redact@0.4.0': {} - - '@rollup/rollup-android-arm-eabi@4.57.1': - optional: true - - '@rollup/rollup-android-arm64@4.57.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.57.1': - optional: true - - '@rollup/rollup-darwin-x64@4.57.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.57.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.57.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.57.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.57.1': - optional: true - - '@rollup/rollup-openbsd-x64@4.57.1': - optional: true - - '@rollup/rollup-openharmony-arm64@4.57.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.57.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.57.1': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.57.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.57.1': - optional: true - - '@types/estree@1.0.8': {} - - '@types/node-fetch@2.6.13': - dependencies: - '@types/node': 20.19.30 - form-data: 4.0.5 - - '@types/node@18.19.130': - dependencies: - undici-types: 5.26.5 - - '@types/node@20.19.30': - dependencies: - undici-types: 6.21.0 - - '@types/pdf-parse@1.1.5': - dependencies: - '@types/node': 20.19.30 - - '@types/uuid@10.0.0': {} - - '@vitest/expect@2.1.9': - dependencies: - '@vitest/spy': 2.1.9 - '@vitest/utils': 2.1.9 - chai: 5.3.3 - tinyrainbow: 1.2.0 - - '@vitest/mocker@2.1.9(vite@5.4.21)': - dependencies: - '@vitest/spy': 2.1.9 - estree-walker: 3.0.3 - magic-string: 0.30.21 - vite: 5.4.21(@types/node@20.19.30) - - '@vitest/pretty-format@2.1.9': - dependencies: - tinyrainbow: 1.2.0 - - '@vitest/runner@2.1.9': - dependencies: - '@vitest/utils': 2.1.9 - pathe: 1.1.2 - - '@vitest/snapshot@2.1.9': - dependencies: - '@vitest/pretty-format': 2.1.9 - magic-string: 0.30.21 - pathe: 1.1.2 - - '@vitest/spy@2.1.9': - dependencies: - tinyspy: 3.0.2 - - '@vitest/utils@2.1.9': - dependencies: - '@vitest/pretty-format': 2.1.9 - loupe: 3.2.1 - tinyrainbow: 1.2.0 - - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - abstract-logging@2.0.1: {} - - agentkeepalive@4.6.0: - dependencies: - humanize-ms: 1.2.1 - - ajv-formats@2.1.1(ajv@8.17.1): - dependencies: - ajv: 8.17.1 - - ajv-formats@3.0.1(ajv@8.17.1): - dependencies: - ajv: 8.17.1 - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-regex@5.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - assertion-error@2.0.1: {} - - asynckit@0.4.0: {} - - atomic-sleep@1.0.0: {} - - avvio@8.4.0: - dependencies: - '@fastify/error': 3.4.1 - fastq: 1.20.1 - - cac@6.7.14: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - chai@5.3.3: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.3 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - - check-error@2.1.3: {} - - chromadb@1.10.5(openai@4.104.0): - dependencies: - cliui: 8.0.1 - isomorphic-fetch: 3.0.0 - openai: 4.104.0 - transitivePeerDependencies: - - encoding - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - cookie@0.7.2: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-eql@5.0.2: {} - - delayed-stream@1.0.0: {} - - dotenv@16.6.1: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - emoji-regex@8.0.0: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-module-lexer@1.7.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild@0.21.5: - optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 - - esbuild@0.27.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.2 - '@esbuild/android-arm': 0.27.2 - '@esbuild/android-arm64': 0.27.2 - '@esbuild/android-x64': 0.27.2 - '@esbuild/darwin-arm64': 0.27.2 - '@esbuild/darwin-x64': 0.27.2 - '@esbuild/freebsd-arm64': 0.27.2 - '@esbuild/freebsd-x64': 0.27.2 - '@esbuild/linux-arm': 0.27.2 - '@esbuild/linux-arm64': 0.27.2 - '@esbuild/linux-ia32': 0.27.2 - '@esbuild/linux-loong64': 0.27.2 - '@esbuild/linux-mips64el': 0.27.2 - '@esbuild/linux-ppc64': 0.27.2 - '@esbuild/linux-riscv64': 0.27.2 - '@esbuild/linux-s390x': 0.27.2 - '@esbuild/linux-x64': 0.27.2 - '@esbuild/netbsd-arm64': 0.27.2 - '@esbuild/netbsd-x64': 0.27.2 - '@esbuild/openbsd-arm64': 0.27.2 - '@esbuild/openbsd-x64': 0.27.2 - '@esbuild/openharmony-arm64': 0.27.2 - '@esbuild/sunos-x64': 0.27.2 - '@esbuild/win32-arm64': 0.27.2 - '@esbuild/win32-ia32': 0.27.2 - '@esbuild/win32-x64': 0.27.2 - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - event-target-shim@5.0.1: {} - - expect-type@1.3.0: {} - - fast-content-type-parse@1.1.0: {} - - fast-decode-uri-component@1.0.1: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stringify@5.16.1: - dependencies: - '@fastify/merge-json-schemas': 0.1.1 - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - fast-deep-equal: 3.1.3 - fast-uri: 2.4.0 - json-schema-ref-resolver: 1.0.1 - rfdc: 1.4.1 - - fast-querystring@1.1.2: - dependencies: - fast-decode-uri-component: 1.0.1 - - fast-uri@2.4.0: {} - - fast-uri@3.1.0: {} - - fastify-plugin@4.5.1: {} - - fastify@4.29.1: - dependencies: - '@fastify/ajv-compiler': 3.6.0 - '@fastify/error': 3.4.1 - '@fastify/fast-json-stringify-compiler': 4.3.0 - abstract-logging: 2.0.1 - avvio: 8.4.0 - fast-content-type-parse: 1.1.0 - fast-json-stringify: 5.16.1 - find-my-way: 8.2.2 - light-my-request: 5.14.0 - pino: 9.14.0 - process-warning: 3.0.0 - proxy-addr: 2.0.7 - rfdc: 1.4.1 - secure-json-parse: 2.7.0 - semver: 7.7.3 - toad-cache: 3.7.0 - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - find-my-way@8.2.2: - dependencies: - fast-deep-equal: 3.1.3 - fast-querystring: 1.1.2 - safe-regex2: 3.1.0 - - form-data-encoder@1.7.2: {} - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - formdata-node@4.4.1: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 4.0.0-beta.3 - - forwarded@0.2.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-tsconfig@4.13.0: - dependencies: - resolve-pkg-maps: 1.0.0 - - gopd@1.2.0: {} - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - - ipaddr.js@1.9.1: {} - - is-fullwidth-code-point@3.0.0: {} - - isomorphic-fetch@3.0.0: - dependencies: - node-fetch: 2.7.0 - whatwg-fetch: 3.6.20 - transitivePeerDependencies: - - encoding - - json-schema-ref-resolver@1.0.1: - dependencies: - fast-deep-equal: 3.1.3 - - json-schema-traverse@1.0.0: {} - - light-my-request@5.14.0: - dependencies: - cookie: 0.7.2 - process-warning: 3.0.0 - set-cookie-parser: 2.7.2 - - loupe@3.2.1: {} - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - math-intrinsics@1.1.0: {} - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mnemonist@0.39.6: - dependencies: - obliterator: 2.0.5 - - ms@2.1.3: {} - - nanoid@3.3.11: {} - - node-domexception@1.0.0: {} - - node-ensure@0.0.0: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - obliterator@2.0.5: {} - - on-exit-leak-free@2.1.2: {} - - openai@4.104.0: - dependencies: - '@types/node': 18.19.130 - '@types/node-fetch': 2.6.13 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - pathe@1.1.2: {} - - pathval@2.0.1: {} - - pdf-parse@1.1.4: - dependencies: - node-ensure: 0.0.0 - - picocolors@1.1.1: {} - - pino-abstract-transport@2.0.0: - dependencies: - split2: 4.2.0 - - pino-std-serializers@7.1.0: {} - - pino@9.14.0: - dependencies: - '@pinojs/redact': 0.4.0 - atomic-sleep: 1.0.0 - on-exit-leak-free: 2.1.2 - pino-abstract-transport: 2.0.0 - pino-std-serializers: 7.1.0 - process-warning: 5.0.0 - quick-format-unescaped: 4.0.4 - real-require: 0.2.0 - safe-stable-stringify: 2.5.0 - sonic-boom: 4.2.0 - thread-stream: 3.1.0 - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - process-warning@3.0.0: {} - - process-warning@5.0.0: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - quick-format-unescaped@4.0.4: {} - - real-require@0.2.0: {} - - require-from-string@2.0.2: {} - - resolve-pkg-maps@1.0.0: {} - - ret@0.4.3: {} - - reusify@1.1.0: {} - - rfdc@1.4.1: {} - - rollup@4.57.1: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.57.1 - '@rollup/rollup-android-arm64': 4.57.1 - '@rollup/rollup-darwin-arm64': 4.57.1 - '@rollup/rollup-darwin-x64': 4.57.1 - '@rollup/rollup-freebsd-arm64': 4.57.1 - '@rollup/rollup-freebsd-x64': 4.57.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 - '@rollup/rollup-linux-arm-musleabihf': 4.57.1 - '@rollup/rollup-linux-arm64-gnu': 4.57.1 - '@rollup/rollup-linux-arm64-musl': 4.57.1 - '@rollup/rollup-linux-loong64-gnu': 4.57.1 - '@rollup/rollup-linux-loong64-musl': 4.57.1 - '@rollup/rollup-linux-ppc64-gnu': 4.57.1 - '@rollup/rollup-linux-ppc64-musl': 4.57.1 - '@rollup/rollup-linux-riscv64-gnu': 4.57.1 - '@rollup/rollup-linux-riscv64-musl': 4.57.1 - '@rollup/rollup-linux-s390x-gnu': 4.57.1 - '@rollup/rollup-linux-x64-gnu': 4.57.1 - '@rollup/rollup-linux-x64-musl': 4.57.1 - '@rollup/rollup-openbsd-x64': 4.57.1 - '@rollup/rollup-openharmony-arm64': 4.57.1 - '@rollup/rollup-win32-arm64-msvc': 4.57.1 - '@rollup/rollup-win32-ia32-msvc': 4.57.1 - '@rollup/rollup-win32-x64-gnu': 4.57.1 - '@rollup/rollup-win32-x64-msvc': 4.57.1 - fsevents: 2.3.3 - - safe-regex2@3.1.0: - dependencies: - ret: 0.4.3 - - safe-stable-stringify@2.5.0: {} - - secure-json-parse@2.7.0: {} - - semver@7.7.3: {} - - set-cookie-parser@2.7.2: {} - - siginfo@2.0.0: {} - - sonic-boom@4.2.0: - dependencies: - atomic-sleep: 1.0.0 - - source-map-js@1.2.1: {} - - split2@4.2.0: {} - - stackback@0.0.2: {} - - std-env@3.10.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - thread-stream@3.1.0: - dependencies: - real-require: 0.2.0 - - tinybench@2.9.0: {} - - tinyexec@0.3.2: {} - - tinypool@1.1.1: {} - - tinyrainbow@1.2.0: {} - - tinyspy@3.0.2: {} - - toad-cache@3.7.0: {} - - tr46@0.0.3: {} - - tsx@4.21.0: - dependencies: - esbuild: 0.27.2 - get-tsconfig: 4.13.0 - optionalDependencies: - fsevents: 2.3.3 - - typescript@5.9.3: {} - - undici-types@5.26.5: {} - - undici-types@6.21.0: {} - - uuid@10.0.0: {} - - vite-node@2.1.9(@types/node@20.19.30): - dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 - pathe: 1.1.2 - vite: 5.4.21(@types/node@20.19.30) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vite@5.4.21(@types/node@20.19.30): - dependencies: - '@types/node': 20.19.30 - esbuild: 0.21.5 - postcss: 8.5.6 - rollup: 4.57.1 - optionalDependencies: - fsevents: 2.3.3 - - vitest@2.1.9(@types/node@20.19.30): - dependencies: - '@types/node': 20.19.30 - '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.21) - '@vitest/pretty-format': 2.1.9 - '@vitest/runner': 2.1.9 - '@vitest/snapshot': 2.1.9 - '@vitest/spy': 2.1.9 - '@vitest/utils': 2.1.9 - chai: 5.3.3 - debug: 4.4.3 - expect-type: 1.3.0 - magic-string: 0.30.21 - pathe: 1.1.2 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinypool: 1.1.1 - tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@20.19.30) - vite-node: 2.1.9(@types/node@20.19.30) - why-is-node-running: 2.3.0 - transitivePeerDependencies: - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - web-streams-polyfill@4.0.0-beta.3: {} - - webidl-conversions@3.0.1: {} - - whatwg-fetch@3.6.20: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: false diff --git a/railway-api.toml b/railway-api.toml index d6355af..92b3e0c 100644 --- a/railway-api.toml +++ b/railway-api.toml @@ -1,9 +1,9 @@ -[build] -builder = "DOCKERFILE" -dockerfilePath = "./Dockerfile" - -[deploy] -healthcheckPath = "/health" -healthcheckTimeout = 30 -restartPolicyType = "ON_FAILURE" -restartPolicyMaxRetries = 3 +[build] +builder = "DOCKERFILE" +dockerfilePath = "./Dockerfile" + +[deploy] +healthcheckPath = "/health" +healthcheckTimeout = 30 +restartPolicyType = "ON_FAILURE" +restartPolicyMaxRetries = 3 diff --git a/railway-web.toml b/railway-web.toml index 54a947c..5ac529a 100644 --- a/railway-web.toml +++ b/railway-web.toml @@ -1,9 +1,9 @@ -[build] -builder = "DOCKERFILE" -dockerfilePath = "./Dockerfile.web" - -[deploy] -healthcheckPath = "/" -healthcheckTimeout = 30 -restartPolicyType = "ON_FAILURE" -restartPolicyMaxRetries = 3 +[build] +builder = "DOCKERFILE" +dockerfilePath = "./Dockerfile.web" + +[deploy] +healthcheckPath = "/" +healthcheckTimeout = 30 +restartPolicyType = "ON_FAILURE" +restartPolicyMaxRetries = 3 diff --git a/src/api/chat.ts b/src/api/chat.ts index 5ef8aa6..f1a4648 100644 --- a/src/api/chat.ts +++ b/src/api/chat.ts @@ -1,294 +1,294 @@ -/** - * Chat API endpoint - * - * Exposes the RAG system through a REST API - */ - -import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; -import { query, queryStream, retrieve } from '../rag.js'; -import { getStats, isLocalMode, queryChunks } from '../retrieval/index.js'; -import { getPrograms, getProgramById, getUpcomingDeadlines } from '../resources/programs.js'; -import { generateEmbedding } from '../ingestion/index.js'; -import { ragConfig } from '../config.js'; -import type { ChatRequest, ChatResponse, ChatMessage, LegalMetadata, AidMetadata } from '../types.js'; - -interface ChatBody { - question: string; - history?: ChatMessage[]; - stream?: boolean; -} - -interface RetrieveBody { - question: string; -} - -/** - * Register chat routes - */ -export async function registerChatRoutes(app: FastifyInstance): Promise { - /** - * POST /chat - Main chat endpoint - */ - app.post<{ Body: ChatBody }>( - '/chat', - { - schema: { - body: { - type: 'object', - required: ['question'], - properties: { - question: { type: 'string', minLength: 1 }, - history: { - type: 'array', - items: { - type: 'object', - properties: { - role: { type: 'string', enum: ['user', 'assistant', 'system'] }, - content: { type: 'string' }, - }, - }, - }, - stream: { type: 'boolean', default: false }, - }, - }, - }, - }, - async (request: FastifyRequest<{ Body: ChatBody }>, reply: FastifyReply) => { - const { question, history, stream } = request.body; - - try { - if (stream) { - // Streaming response - reply.raw.writeHead(200, { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive', - }); - - const response = await queryStream( - question, - history, - (chunk) => { - reply.raw.write(`data: ${JSON.stringify({ chunk })}\n\n`); - } - ); - - // Send final response with metadata - reply.raw.write(`data: ${JSON.stringify({ done: true, response })}\n\n`); - reply.raw.end(); - } else { - // Regular response - const response = await query(question, history); - return response; - } - } catch (error) { - request.log.error(error, 'Chat query failed'); - reply.status(500).send({ - error: 'Internal server error', - message: error instanceof Error ? error.message : 'Unknown error', - }); - } - } - ); - - /** - * POST /retrieve - Get relevant chunks without generation (for debugging) - * Enhanced with embedding prefixes for diagnosis - */ - app.post<{ Body: RetrieveBody }>( - '/retrieve', - { - schema: { - body: { - type: 'object', - required: ['question'], - properties: { - question: { type: 'string', minLength: 1 }, - }, - }, - }, - }, - async (request: FastifyRequest<{ Body: RetrieveBody }>, reply: FastifyReply) => { - const { question } = request.body; - - try { - // Generate embedding for the question - const questionEmbedding = await generateEmbedding(question); - const results = await retrieve(question); - - return { - question, - queryEmbedding: questionEmbedding.slice(0, 10), // First 10 values for comparison - chunks: results.map(r => { - const meta = r.chunk.metadata; - // Handle both legal and aid chunks - if ('law' in meta) { - const legalMeta = meta as LegalMetadata; - return { - score: r.score, - type: 'legal', - article: legalMeta.article, - law: legalMeta.law, - title: legalMeta.articleTitle, - text: r.chunk.text.slice(0, 500) + '...', - embeddingPrefix: r.chunk.embedding?.slice(0, 10), // First 10 values - }; - } else { - const aidMeta = meta as AidMetadata; - return { - score: r.score, - type: 'aid', - program: aidMeta.programName, - section: aidMeta.section, - text: r.chunk.text.slice(0, 500) + '...', - embeddingPrefix: r.chunk.embedding?.slice(0, 10), // First 10 values - }; - } - }), - }; - } catch (error) { - request.log.error(error, 'Retrieve failed'); - reply.status(500).send({ - error: 'Internal server error', - message: error instanceof Error ? error.message : 'Unknown error', - }); - } - } - ); - - /** - * GET /health - Health check endpoint - */ - app.get('/health', async () => { - try { - const stats = await getStats(); - return { - status: 'healthy', - vectorStore: { - connected: true, - mode: isLocalMode() ? 'local' : 'chroma', - documentCount: stats.count, - }, - }; - } catch { - return { - status: 'degraded', - vectorStore: { - connected: false, - documentCount: 0, - }, - }; - } - }); - - /** - * GET /debug - Comprehensive debug information - * Shows version, config, and sample embeddings for prod/local comparison - */ - app.get('/debug', async (request, reply) => { - try { - const stats = await getStats(); - - // Get sample embeddings from a test query - const testEmbedding = await generateEmbedding('test'); - const sampleChunks = await queryChunks(testEmbedding, 3); - - return { - version: { - commit: process.env['RAILWAY_GIT_COMMIT_SHA'] || 'unknown', - buildTime: process.env['BUILD_TIME'] || 'unknown', - nodeVersion: process.version, - }, - config: { - chatModel: ragConfig.chatModel, - embeddingModel: ragConfig.embeddingModel, - temperature: 0.3, - maxChunks: ragConfig.maxChunks, - similarityThreshold: ragConfig.similarityThreshold, - }, - vectorStore: { - mode: isLocalMode() ? 'local' : 'chroma', - documentCount: stats.count, - sampleEmbeddings: sampleChunks.slice(0, 2).map(c => ({ - id: c.chunk.id, - type: 'programName' in c.chunk.metadata ? 'aid' : 'legal', - embeddingPrefix: c.chunk.embedding?.slice(0, 5), // First 5 values - })), - }, - environment: { - hasOpenAIKey: !!process.env['OPENAI_API_KEY'], - openAIKeyPrefix: process.env['OPENAI_API_KEY']?.slice(0, 10) || 'missing', - platform: process.platform, - }, - }; - } catch (error) { - request.log.error(error, 'Debug endpoint failed'); - reply.status(500).send({ - error: 'Debug failed', - message: error instanceof Error ? error.message : 'Unknown error', - }); - } - }); - - /** - * GET /stats - Get system statistics - */ - app.get('/stats', async () => { - const stats = await getStats(); - return { - documentCount: stats.count, - models: { - embedding: process.env['EMBEDDING_MODEL'] ?? 'text-embedding-3-small', - chat: process.env['CHAT_MODEL'] ?? 'gpt-4-turbo-preview', - }, - }; - }); - - // ============================================ - // Resources endpoints - // ============================================ - - /** - * GET /resources - List active housing programs - */ - app.get<{ - Querystring: { status?: string; region?: string }; - }>('/resources', async (request) => { - const { status, region } = request.query; - - const programs = getPrograms({ - status: status as 'open' | 'closed' | 'upcoming' | undefined, - region: region as 'catalunya' | 'barcelona' | 'spain' | undefined, - }); - - return { - count: programs.length, - programs, - }; - }); - - /** - * GET /resources/deadlines - Programs with upcoming deadlines - */ - app.get('/resources/deadlines', async () => { - const programs = getUpcomingDeadlines(); - return { - count: programs.length, - programs, - }; - }); - - /** - * GET /resources/:id - Get specific program - */ - app.get<{ Params: { id: string } }>('/resources/:id', async (request, reply) => { - const program = getProgramById(request.params.id); - - if (!program) { - reply.status(404).send({ error: 'Program not found' }); - return; - } - - return program; - }); -} +/** + * Chat API endpoint + * + * Exposes the RAG system through a REST API + */ + +import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; +import { query, queryStream, retrieve } from '../rag.js'; +import { getStats, isLocalMode, queryChunks } from '../retrieval/index.js'; +import { getPrograms, getProgramById, getUpcomingDeadlines } from '../resources/programs.js'; +import { generateEmbedding } from '../ingestion/index.js'; +import { ragConfig } from '../config.js'; +import type { ChatRequest, ChatResponse, ChatMessage, LegalMetadata, AidMetadata } from '../types.js'; + +interface ChatBody { + question: string; + history?: ChatMessage[]; + stream?: boolean; +} + +interface RetrieveBody { + question: string; +} + +/** + * Register chat routes + */ +export async function registerChatRoutes(app: FastifyInstance): Promise { + /** + * POST /chat - Main chat endpoint + */ + app.post<{ Body: ChatBody }>( + '/chat', + { + schema: { + body: { + type: 'object', + required: ['question'], + properties: { + question: { type: 'string', minLength: 1 }, + history: { + type: 'array', + items: { + type: 'object', + properties: { + role: { type: 'string', enum: ['user', 'assistant', 'system'] }, + content: { type: 'string' }, + }, + }, + }, + stream: { type: 'boolean', default: false }, + }, + }, + }, + }, + async (request: FastifyRequest<{ Body: ChatBody }>, reply: FastifyReply) => { + const { question, history, stream } = request.body; + + try { + if (stream) { + // Streaming response + reply.raw.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + }); + + const response = await queryStream( + question, + history, + (chunk) => { + reply.raw.write(`data: ${JSON.stringify({ chunk })}\n\n`); + } + ); + + // Send final response with metadata + reply.raw.write(`data: ${JSON.stringify({ done: true, response })}\n\n`); + reply.raw.end(); + } else { + // Regular response + const response = await query(question, history); + return response; + } + } catch (error) { + request.log.error(error, 'Chat query failed'); + reply.status(500).send({ + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error', + }); + } + } + ); + + /** + * POST /retrieve - Get relevant chunks without generation (for debugging) + * Enhanced with embedding prefixes for diagnosis + */ + app.post<{ Body: RetrieveBody }>( + '/retrieve', + { + schema: { + body: { + type: 'object', + required: ['question'], + properties: { + question: { type: 'string', minLength: 1 }, + }, + }, + }, + }, + async (request: FastifyRequest<{ Body: RetrieveBody }>, reply: FastifyReply) => { + const { question } = request.body; + + try { + // Generate embedding for the question + const questionEmbedding = await generateEmbedding(question); + const results = await retrieve(question); + + return { + question, + queryEmbedding: questionEmbedding.slice(0, 10), // First 10 values for comparison + chunks: results.map(r => { + const meta = r.chunk.metadata; + // Handle both legal and aid chunks + if ('law' in meta) { + const legalMeta = meta as LegalMetadata; + return { + score: r.score, + type: 'legal', + article: legalMeta.article, + law: legalMeta.law, + title: legalMeta.articleTitle, + text: r.chunk.text.slice(0, 500) + '...', + embeddingPrefix: r.chunk.embedding?.slice(0, 10), // First 10 values + }; + } else { + const aidMeta = meta as AidMetadata; + return { + score: r.score, + type: 'aid', + program: aidMeta.programName, + section: aidMeta.section, + text: r.chunk.text.slice(0, 500) + '...', + embeddingPrefix: r.chunk.embedding?.slice(0, 10), // First 10 values + }; + } + }), + }; + } catch (error) { + request.log.error(error, 'Retrieve failed'); + reply.status(500).send({ + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error', + }); + } + } + ); + + /** + * GET /health - Health check endpoint + */ + app.get('/health', async () => { + try { + const stats = await getStats(); + return { + status: 'healthy', + vectorStore: { + connected: true, + mode: isLocalMode() ? 'local' : 'chroma', + documentCount: stats.count, + }, + }; + } catch { + return { + status: 'degraded', + vectorStore: { + connected: false, + documentCount: 0, + }, + }; + } + }); + + /** + * GET /debug - Comprehensive debug information + * Shows version, config, and sample embeddings for prod/local comparison + */ + app.get('/debug', async (request, reply) => { + try { + const stats = await getStats(); + + // Get sample embeddings from a test query + const testEmbedding = await generateEmbedding('test'); + const sampleChunks = await queryChunks(testEmbedding, 3); + + return { + version: { + commit: process.env['RAILWAY_GIT_COMMIT_SHA'] || 'unknown', + buildTime: process.env['BUILD_TIME'] || 'unknown', + nodeVersion: process.version, + }, + config: { + chatModel: ragConfig.chatModel, + embeddingModel: ragConfig.embeddingModel, + temperature: 0.3, + maxChunks: ragConfig.maxChunks, + similarityThreshold: ragConfig.similarityThreshold, + }, + vectorStore: { + mode: isLocalMode() ? 'local' : 'chroma', + documentCount: stats.count, + sampleEmbeddings: sampleChunks.slice(0, 2).map(c => ({ + id: c.chunk.id, + type: 'programName' in c.chunk.metadata ? 'aid' : 'legal', + embeddingPrefix: c.chunk.embedding?.slice(0, 5), // First 5 values + })), + }, + environment: { + hasOpenAIKey: !!process.env['OPENAI_API_KEY'], + openAIKeyPrefix: process.env['OPENAI_API_KEY']?.slice(0, 10) || 'missing', + platform: process.platform, + }, + }; + } catch (error) { + request.log.error(error, 'Debug endpoint failed'); + reply.status(500).send({ + error: 'Debug failed', + message: error instanceof Error ? error.message : 'Unknown error', + }); + } + }); + + /** + * GET /stats - Get system statistics + */ + app.get('/stats', async () => { + const stats = await getStats(); + return { + documentCount: stats.count, + models: { + embedding: process.env['EMBEDDING_MODEL'] ?? 'text-embedding-3-small', + chat: process.env['CHAT_MODEL'] ?? 'gpt-4-turbo-preview', + }, + }; + }); + + // ============================================ + // Resources endpoints + // ============================================ + + /** + * GET /resources - List active housing programs + */ + app.get<{ + Querystring: { status?: string; region?: string }; + }>('/resources', async (request) => { + const { status, region } = request.query; + + const programs = getPrograms({ + status: status as 'open' | 'closed' | 'upcoming' | undefined, + region: region as 'catalunya' | 'barcelona' | 'spain' | undefined, + }); + + return { + count: programs.length, + programs, + }; + }); + + /** + * GET /resources/deadlines - Programs with upcoming deadlines + */ + app.get('/resources/deadlines', async () => { + const programs = getUpcomingDeadlines(); + return { + count: programs.length, + programs, + }; + }); + + /** + * GET /resources/:id - Get specific program + */ + app.get<{ Params: { id: string } }>('/resources/:id', async (request, reply) => { + const program = getProgramById(request.params.id); + + if (!program) { + reply.status(404).send({ error: 'Program not found' }); + return; + } + + return program; + }); +} diff --git a/src/retrieval/localVectorStore.ts b/src/retrieval/localVectorStore.ts index 98748d4..f1d96ab 100644 --- a/src/retrieval/localVectorStore.ts +++ b/src/retrieval/localVectorStore.ts @@ -1,197 +1,197 @@ -/** - * Local Vector Store - File-based storage for development without Docker - * - * Uses JSON file for persistence and in-memory cosine similarity search. - * Perfect for demos and development when Chroma server is not available. - */ - -import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; -import { dirname, resolve } from 'path'; -import { fileURLToPath } from 'url'; -import type { EmbeddedChunk, RetrievalResult, ContentMetadata } from '../types.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -interface StoredChunk { - id: string; - text: string; - embedding: number[]; - metadata: ContentMetadata; -} - -interface VectorStoreData { - chunks: StoredChunk[]; - version: number; -} - -const DEFAULT_STORE_PATH = resolve(__dirname, '../../data/vector_store.json'); - -let storeData: VectorStoreData = { chunks: [], version: 1 }; -let storePath = DEFAULT_STORE_PATH; -let initialized = false; - -/** - * Initialize the local vector store - */ -export async function initLocalVectorStore(path?: string): Promise { - storePath = path ?? DEFAULT_STORE_PATH; - - if (existsSync(storePath)) { - try { - const data = readFileSync(storePath, 'utf-8'); - storeData = JSON.parse(data); - console.log(`Local vector store loaded: ${storeData.chunks.length} chunks`); - } catch (error) { - console.error(`Failed to load vector store from ${storePath}:`, error); - console.log('Creating new local vector store'); - storeData = { chunks: [], version: 1 }; - } - } else { - console.log('Creating new local vector store'); - storeData = { chunks: [], version: 1 }; - } - - initialized = true; -} - -/** - * Save the store to disk - */ -function saveStore(): void { - const dir = dirname(storePath); - if (!existsSync(dir)) { - mkdirSync(dir, { recursive: true }); - } - writeFileSync(storePath, JSON.stringify(storeData, null, 2)); -} - -/** - * Add embedded chunks to the store - */ -export async function addChunksLocal(chunks: EmbeddedChunk[]): Promise { - if (!initialized) await initLocalVectorStore(); - - for (const chunk of chunks) { - // Remove existing chunk with same ID (upsert behavior) - const existingIndex = storeData.chunks.findIndex(c => c.id === chunk.id); - if (existingIndex >= 0) { - storeData.chunks.splice(existingIndex, 1); - } - - storeData.chunks.push({ - id: chunk.id, - text: chunk.text, - embedding: chunk.embedding, - metadata: chunk.metadata, - }); - } - - saveStore(); - console.log(`Added ${chunks.length} chunks to local vector store`); -} - -/** - * Calculate cosine similarity between two vectors - */ -function cosineSimilarity(a: number[], b: number[]): number { - if (a.length !== b.length) return 0; - - let dotProduct = 0; - let normA = 0; - let normB = 0; - - for (let i = 0; i < a.length; i++) { - const aVal = a[i] ?? 0; - const bVal = b[i] ?? 0; - dotProduct += aVal * bVal; - normA += aVal * aVal; - normB += bVal * bVal; - } - - const denominator = Math.sqrt(normA) * Math.sqrt(normB); - if (denominator === 0) return 0; - - return dotProduct / denominator; -} - -/** - * Query the store for similar chunks - */ -export async function queryChunksLocal( - queryEmbedding: number[], - topK: number = 5, - filter?: Record -): Promise { - if (!initialized) await initLocalVectorStore(); - - console.log(`[LocalStore] Querying ${storeData.chunks.length} chunks, topK=${topK}`); - - // Filter chunks if filter provided - let candidates = storeData.chunks; - if (filter) { - candidates = candidates.filter(chunk => { - for (const [key, value] of Object.entries(filter)) { - const metaValue = (chunk.metadata as unknown as Record)[key]; - if (metaValue !== value) return false; - } - return true; - }); - } - - // Calculate similarities - const scored: RetrievalResult[] = candidates.map(chunk => ({ - chunk: { - id: chunk.id, - text: chunk.text, - metadata: chunk.metadata, - } as RetrievalResult['chunk'], - score: cosineSimilarity(queryEmbedding, chunk.embedding), - })); - - // Sort by score descending and take top K - scored.sort((a, b) => b.score - a.score); - - const topResults = scored.slice(0, topK); - if (topResults.length > 0) { - console.log(`[LocalStore] Top scores: ${topResults.map(r => r.score.toFixed(3)).join(', ')}`); - } - - return topResults; -} - -/** - * Get store statistics - */ -export async function getStatsLocal(): Promise<{ count: number }> { - if (!initialized) await initLocalVectorStore(); - return { count: storeData.chunks.length }; -} - -/** - * Clear all data - */ -export async function clearStoreLocal(): Promise { - storeData = { chunks: [], version: 1 }; - saveStore(); - console.log('Local vector store cleared'); -} - -/** - * Delete chunks by law code (only affects legal chunks) - */ -export async function deleteByLawLocal(lawCode: string): Promise { - if (!initialized) await initLocalVectorStore(); - - const before = storeData.chunks.length; - storeData.chunks = storeData.chunks.filter(c => { - if ('law' in c.metadata) { - return c.metadata.law !== lawCode; - } - return true; // Keep aid chunks - }); - const deleted = before - storeData.chunks.length; - - saveStore(); - console.log(`Deleted ${deleted} chunks for law: ${lawCode}`); -} +/** + * Local Vector Store - File-based storage for development without Docker + * + * Uses JSON file for persistence and in-memory cosine similarity search. + * Perfect for demos and development when Chroma server is not available. + */ + +import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; +import type { EmbeddedChunk, RetrievalResult, ContentMetadata } from '../types.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +interface StoredChunk { + id: string; + text: string; + embedding: number[]; + metadata: ContentMetadata; +} + +interface VectorStoreData { + chunks: StoredChunk[]; + version: number; +} + +const DEFAULT_STORE_PATH = resolve(__dirname, '../../data/vector_store.json'); + +let storeData: VectorStoreData = { chunks: [], version: 1 }; +let storePath = DEFAULT_STORE_PATH; +let initialized = false; + +/** + * Initialize the local vector store + */ +export async function initLocalVectorStore(path?: string): Promise { + storePath = path ?? DEFAULT_STORE_PATH; + + if (existsSync(storePath)) { + try { + const data = readFileSync(storePath, 'utf-8'); + storeData = JSON.parse(data); + console.log(`Local vector store loaded: ${storeData.chunks.length} chunks`); + } catch (error) { + console.error(`Failed to load vector store from ${storePath}:`, error); + console.log('Creating new local vector store'); + storeData = { chunks: [], version: 1 }; + } + } else { + console.log('Creating new local vector store'); + storeData = { chunks: [], version: 1 }; + } + + initialized = true; +} + +/** + * Save the store to disk + */ +function saveStore(): void { + const dir = dirname(storePath); + if (!existsSync(dir)) { + mkdirSync(dir, { recursive: true }); + } + writeFileSync(storePath, JSON.stringify(storeData, null, 2)); +} + +/** + * Add embedded chunks to the store + */ +export async function addChunksLocal(chunks: EmbeddedChunk[]): Promise { + if (!initialized) await initLocalVectorStore(); + + for (const chunk of chunks) { + // Remove existing chunk with same ID (upsert behavior) + const existingIndex = storeData.chunks.findIndex(c => c.id === chunk.id); + if (existingIndex >= 0) { + storeData.chunks.splice(existingIndex, 1); + } + + storeData.chunks.push({ + id: chunk.id, + text: chunk.text, + embedding: chunk.embedding, + metadata: chunk.metadata, + }); + } + + saveStore(); + console.log(`Added ${chunks.length} chunks to local vector store`); +} + +/** + * Calculate cosine similarity between two vectors + */ +function cosineSimilarity(a: number[], b: number[]): number { + if (a.length !== b.length) return 0; + + let dotProduct = 0; + let normA = 0; + let normB = 0; + + for (let i = 0; i < a.length; i++) { + const aVal = a[i] ?? 0; + const bVal = b[i] ?? 0; + dotProduct += aVal * bVal; + normA += aVal * aVal; + normB += bVal * bVal; + } + + const denominator = Math.sqrt(normA) * Math.sqrt(normB); + if (denominator === 0) return 0; + + return dotProduct / denominator; +} + +/** + * Query the store for similar chunks + */ +export async function queryChunksLocal( + queryEmbedding: number[], + topK: number = 5, + filter?: Record +): Promise { + if (!initialized) await initLocalVectorStore(); + + console.log(`[LocalStore] Querying ${storeData.chunks.length} chunks, topK=${topK}`); + + // Filter chunks if filter provided + let candidates = storeData.chunks; + if (filter) { + candidates = candidates.filter(chunk => { + for (const [key, value] of Object.entries(filter)) { + const metaValue = (chunk.metadata as unknown as Record)[key]; + if (metaValue !== value) return false; + } + return true; + }); + } + + // Calculate similarities + const scored: RetrievalResult[] = candidates.map(chunk => ({ + chunk: { + id: chunk.id, + text: chunk.text, + metadata: chunk.metadata, + } as RetrievalResult['chunk'], + score: cosineSimilarity(queryEmbedding, chunk.embedding), + })); + + // Sort by score descending and take top K + scored.sort((a, b) => b.score - a.score); + + const topResults = scored.slice(0, topK); + if (topResults.length > 0) { + console.log(`[LocalStore] Top scores: ${topResults.map(r => r.score.toFixed(3)).join(', ')}`); + } + + return topResults; +} + +/** + * Get store statistics + */ +export async function getStatsLocal(): Promise<{ count: number }> { + if (!initialized) await initLocalVectorStore(); + return { count: storeData.chunks.length }; +} + +/** + * Clear all data + */ +export async function clearStoreLocal(): Promise { + storeData = { chunks: [], version: 1 }; + saveStore(); + console.log('Local vector store cleared'); +} + +/** + * Delete chunks by law code (only affects legal chunks) + */ +export async function deleteByLawLocal(lawCode: string): Promise { + if (!initialized) await initLocalVectorStore(); + + const before = storeData.chunks.length; + storeData.chunks = storeData.chunks.filter(c => { + if ('law' in c.metadata) { + return c.metadata.law !== lawCode; + } + return true; // Keep aid chunks + }); + const deleted = before - storeData.chunks.length; + + saveStore(); + console.log(`Deleted ${deleted} chunks for law: ${lawCode}`); +} diff --git a/src/retrieval/vectorStore.ts b/src/retrieval/vectorStore.ts index 2f27216..123a68f 100644 --- a/src/retrieval/vectorStore.ts +++ b/src/retrieval/vectorStore.ts @@ -1,251 +1,251 @@ -/** - * Vector Store - Chroma integration for storing and retrieving embeddings - * - * Supports two modes: - * 1. Server mode: Connects to Chroma server (production) - * 2. Local mode: JSON file storage (development/demo without Docker) - */ - -import { ChromaClient, Collection, IncludeEnum } from 'chromadb'; -import { chromaConfig } from '../config.js'; -import type { EmbeddedChunk, RetrievalResult, LegalMetadata, AidMetadata, ContentMetadata } from '../types.js'; -import { - initLocalVectorStore, - addChunksLocal, - queryChunksLocal, - getStatsLocal, - clearStoreLocal, - deleteByLawLocal, -} from './localVectorStore.js'; - -let client: ChromaClient | null = null; -let collection: Collection | null = null; -let useLocalStore = false; - -/** - * Initialize the Chroma client and collection - * Falls back to local JSON store if server is unavailable - */ -export async function initVectorStore(): Promise { - // Try Chroma server first - try { - client = new ChromaClient({ - path: `http://${chromaConfig.host}:${chromaConfig.port}`, - }); - - // Test connection - await client.heartbeat(); - - collection = await client.getOrCreateCollection({ - name: chromaConfig.collection, - metadata: { - description: 'Spanish real estate legal documents', - 'hnsw:space': 'cosine', - }, - }); - - useLocalStore = false; - console.log(`Vector store initialized (Chroma): "${chromaConfig.collection}"`); - } catch (error) { - // Fall back to local JSON store - console.log(`Chroma not available (${String(error)}), using local JSON store`); - useLocalStore = true; - await initLocalVectorStore(); - const stats = await getStatsLocal(); - console.log(`Local store ready: ${stats.count} chunks loaded`); - } -} - -/** - * Check if using local store (no Chroma) - */ -export function isLocalMode(): boolean { - return useLocalStore; -} - -/** - * Get the current collection (initialize if needed) - */ -async function getCollection(): Promise { - if (!collection) { - await initVectorStore(); - } - if (!collection) { - throw new Error('Failed to initialize vector store'); - } - return collection; -} - -/** - * Add embedded chunks to the vector store - */ -export async function addChunks(chunks: EmbeddedChunk[]): Promise { - if (useLocalStore) { - return addChunksLocal(chunks); - } - - const coll = await getCollection(); - - const ids = chunks.map(c => c.id); - const embeddings = chunks.map(c => c.embedding); - const documents = chunks.map(c => c.text); - const metadatas = chunks.map(c => { - const meta = c.metadata; - // Handle both legal and aid metadata - // Chroma requires all values to be string | number | boolean - if ('law' in meta) { - const legalMeta = meta as LegalMetadata; - return { - type: 'legal', - law: legalMeta.law, - lawFullName: legalMeta.lawFullName, - title: legalMeta.title ?? '', - chapter: legalMeta.chapter ?? '', - article: legalMeta.article, - articleTitle: legalMeta.articleTitle, - sourceFile: legalMeta.sourceFile, - }; - } else { - const aidMeta = meta as AidMetadata; - return { - type: 'aid', - programName: aidMeta.programName, - section: aidMeta.section, - deadline: aidMeta.deadline ?? '', - amount: aidMeta.amount ?? '', - sourceFile: aidMeta.sourceFile, - sourceUrl: aidMeta.sourceUrl ?? '', - }; - } - }) as unknown as Record[]; - - // Upsert to handle duplicates - await coll.upsert({ - ids, - embeddings, - documents, - metadatas, - }); - - console.log(`Added ${chunks.length} chunks to vector store`); -} - -/** - * Query the vector store for similar chunks - */ -export async function queryChunks( - queryEmbedding: number[], - topK: number = 5, - filter?: Record -): Promise { - if (useLocalStore) { - return queryChunksLocal(queryEmbedding, topK, filter); - } - - const coll = await getCollection(); - - const results = await coll.query({ - queryEmbeddings: [queryEmbedding], - nResults: topK, - where: filter, - include: [IncludeEnum.Documents, IncludeEnum.Metadatas, IncludeEnum.Distances], - }); - - const retrievalResults: RetrievalResult[] = []; - - const documents = results.documents?.[0] ?? []; - const metadatas = results.metadatas?.[0] ?? []; - const distances = results.distances?.[0] ?? []; - const ids = results.ids?.[0] ?? []; - - for (let i = 0; i < documents.length; i++) { - const doc = documents[i]; - const meta = metadatas[i]; - const distance = distances[i]; - const id = ids[i]; - - if (doc && meta && distance !== undefined && id) { - // Convert distance to similarity (Chroma uses L2 distance by default) - // For cosine space: similarity = 1 - distance - const score = 1 - distance; - - // Reconstruct metadata based on type - let metadata: ContentMetadata; - if (meta['type'] === 'aid' || meta['programName']) { - metadata = { - programName: String(meta['programName'] ?? ''), - section: String(meta['section'] ?? ''), - deadline: meta['deadline'] ? String(meta['deadline']) : undefined, - amount: meta['amount'] ? String(meta['amount']) : undefined, - sourceFile: String(meta['sourceFile'] ?? ''), - sourceUrl: meta['sourceUrl'] ? String(meta['sourceUrl']) : undefined, - } as AidMetadata; - } else { - metadata = { - law: String(meta['law'] ?? ''), - lawFullName: String(meta['lawFullName'] ?? ''), - title: meta['title'] ? String(meta['title']) : undefined, - chapter: meta['chapter'] ? String(meta['chapter']) : undefined, - article: String(meta['article'] ?? ''), - articleTitle: String(meta['articleTitle'] ?? ''), - sourceFile: String(meta['sourceFile'] ?? ''), - } as LegalMetadata; - } - - retrievalResults.push({ - chunk: { id, text: doc, metadata } as RetrievalResult['chunk'], - score, - }); - } - } - - return retrievalResults; -} - -/** - * Delete all chunks from a specific law - */ -export async function deleteByLaw(lawCode: string): Promise { - if (useLocalStore) { - return deleteByLawLocal(lawCode); - } - - const coll = await getCollection(); - - await coll.delete({ - where: { law: lawCode }, - }); - - console.log(`Deleted all chunks for law: ${lawCode}`); -} - -/** - * Get collection statistics - */ -export async function getStats(): Promise<{ count: number }> { - if (useLocalStore) { - return getStatsLocal(); - } - - const coll = await getCollection(); - const count = await coll.count(); - return { count }; -} - -/** - * Clear all data from the collection - */ -export async function clearCollection(): Promise { - if (useLocalStore) { - return clearStoreLocal(); - } - - if (!client) { - await initVectorStore(); - } - if (client) { - await client.deleteCollection({ name: chromaConfig.collection }); - collection = null; - console.log('Collection cleared'); - } -} +/** + * Vector Store - Chroma integration for storing and retrieving embeddings + * + * Supports two modes: + * 1. Server mode: Connects to Chroma server (production) + * 2. Local mode: JSON file storage (development/demo without Docker) + */ + +import { ChromaClient, Collection, IncludeEnum } from 'chromadb'; +import { chromaConfig } from '../config.js'; +import type { EmbeddedChunk, RetrievalResult, LegalMetadata, AidMetadata, ContentMetadata } from '../types.js'; +import { + initLocalVectorStore, + addChunksLocal, + queryChunksLocal, + getStatsLocal, + clearStoreLocal, + deleteByLawLocal, +} from './localVectorStore.js'; + +let client: ChromaClient | null = null; +let collection: Collection | null = null; +let useLocalStore = false; + +/** + * Initialize the Chroma client and collection + * Falls back to local JSON store if server is unavailable + */ +export async function initVectorStore(): Promise { + // Try Chroma server first + try { + client = new ChromaClient({ + path: `http://${chromaConfig.host}:${chromaConfig.port}`, + }); + + // Test connection + await client.heartbeat(); + + collection = await client.getOrCreateCollection({ + name: chromaConfig.collection, + metadata: { + description: 'Spanish real estate legal documents', + 'hnsw:space': 'cosine', + }, + }); + + useLocalStore = false; + console.log(`Vector store initialized (Chroma): "${chromaConfig.collection}"`); + } catch (error) { + // Fall back to local JSON store + console.log(`Chroma not available (${String(error)}), using local JSON store`); + useLocalStore = true; + await initLocalVectorStore(); + const stats = await getStatsLocal(); + console.log(`Local store ready: ${stats.count} chunks loaded`); + } +} + +/** + * Check if using local store (no Chroma) + */ +export function isLocalMode(): boolean { + return useLocalStore; +} + +/** + * Get the current collection (initialize if needed) + */ +async function getCollection(): Promise { + if (!collection) { + await initVectorStore(); + } + if (!collection) { + throw new Error('Failed to initialize vector store'); + } + return collection; +} + +/** + * Add embedded chunks to the vector store + */ +export async function addChunks(chunks: EmbeddedChunk[]): Promise { + if (useLocalStore) { + return addChunksLocal(chunks); + } + + const coll = await getCollection(); + + const ids = chunks.map(c => c.id); + const embeddings = chunks.map(c => c.embedding); + const documents = chunks.map(c => c.text); + const metadatas = chunks.map(c => { + const meta = c.metadata; + // Handle both legal and aid metadata + // Chroma requires all values to be string | number | boolean + if ('law' in meta) { + const legalMeta = meta as LegalMetadata; + return { + type: 'legal', + law: legalMeta.law, + lawFullName: legalMeta.lawFullName, + title: legalMeta.title ?? '', + chapter: legalMeta.chapter ?? '', + article: legalMeta.article, + articleTitle: legalMeta.articleTitle, + sourceFile: legalMeta.sourceFile, + }; + } else { + const aidMeta = meta as AidMetadata; + return { + type: 'aid', + programName: aidMeta.programName, + section: aidMeta.section, + deadline: aidMeta.deadline ?? '', + amount: aidMeta.amount ?? '', + sourceFile: aidMeta.sourceFile, + sourceUrl: aidMeta.sourceUrl ?? '', + }; + } + }) as unknown as Record[]; + + // Upsert to handle duplicates + await coll.upsert({ + ids, + embeddings, + documents, + metadatas, + }); + + console.log(`Added ${chunks.length} chunks to vector store`); +} + +/** + * Query the vector store for similar chunks + */ +export async function queryChunks( + queryEmbedding: number[], + topK: number = 5, + filter?: Record +): Promise { + if (useLocalStore) { + return queryChunksLocal(queryEmbedding, topK, filter); + } + + const coll = await getCollection(); + + const results = await coll.query({ + queryEmbeddings: [queryEmbedding], + nResults: topK, + where: filter, + include: [IncludeEnum.Documents, IncludeEnum.Metadatas, IncludeEnum.Distances], + }); + + const retrievalResults: RetrievalResult[] = []; + + const documents = results.documents?.[0] ?? []; + const metadatas = results.metadatas?.[0] ?? []; + const distances = results.distances?.[0] ?? []; + const ids = results.ids?.[0] ?? []; + + for (let i = 0; i < documents.length; i++) { + const doc = documents[i]; + const meta = metadatas[i]; + const distance = distances[i]; + const id = ids[i]; + + if (doc && meta && distance !== undefined && id) { + // Convert distance to similarity (Chroma uses L2 distance by default) + // For cosine space: similarity = 1 - distance + const score = 1 - distance; + + // Reconstruct metadata based on type + let metadata: ContentMetadata; + if (meta['type'] === 'aid' || meta['programName']) { + metadata = { + programName: String(meta['programName'] ?? ''), + section: String(meta['section'] ?? ''), + deadline: meta['deadline'] ? String(meta['deadline']) : undefined, + amount: meta['amount'] ? String(meta['amount']) : undefined, + sourceFile: String(meta['sourceFile'] ?? ''), + sourceUrl: meta['sourceUrl'] ? String(meta['sourceUrl']) : undefined, + } as AidMetadata; + } else { + metadata = { + law: String(meta['law'] ?? ''), + lawFullName: String(meta['lawFullName'] ?? ''), + title: meta['title'] ? String(meta['title']) : undefined, + chapter: meta['chapter'] ? String(meta['chapter']) : undefined, + article: String(meta['article'] ?? ''), + articleTitle: String(meta['articleTitle'] ?? ''), + sourceFile: String(meta['sourceFile'] ?? ''), + } as LegalMetadata; + } + + retrievalResults.push({ + chunk: { id, text: doc, metadata } as RetrievalResult['chunk'], + score, + }); + } + } + + return retrievalResults; +} + +/** + * Delete all chunks from a specific law + */ +export async function deleteByLaw(lawCode: string): Promise { + if (useLocalStore) { + return deleteByLawLocal(lawCode); + } + + const coll = await getCollection(); + + await coll.delete({ + where: { law: lawCode }, + }); + + console.log(`Deleted all chunks for law: ${lawCode}`); +} + +/** + * Get collection statistics + */ +export async function getStats(): Promise<{ count: number }> { + if (useLocalStore) { + return getStatsLocal(); + } + + const coll = await getCollection(); + const count = await coll.count(); + return { count }; +} + +/** + * Clear all data from the collection + */ +export async function clearCollection(): Promise { + if (useLocalStore) { + return clearStoreLocal(); + } + + if (!client) { + await initVectorStore(); + } + if (client) { + await client.deleteCollection({ name: chromaConfig.collection }); + collection = null; + console.log('Collection cleared'); + } +} diff --git a/src/scripts/ingest.ts b/src/scripts/ingest.ts index 076fc5e..f7aeb63 100644 --- a/src/scripts/ingest.ts +++ b/src/scripts/ingest.ts @@ -1,191 +1,191 @@ -/** - * Ingestion Script - LlarJove - * - * Processes both legal documents and aid program documents. - * - data/laws/ → Legal documents (LAU, etc.) → chunkLegalDocument - * - data/ajudes/ → Aid programs (Bono Joven, etc.) → chunkAidDocument - * - * Usage: pnpm ingest [--clear] - */ - -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { existsSync, readdirSync, readFileSync } from 'fs'; -import { - loadDocumentsFromDirectory, - detectLawInfo, - chunkLegalDocument, - chunkAidDocument, - addOverlapContext, - embedChunks, -} from '../ingestion/index.js'; -import { initVectorStore, addChunks, getStats, clearCollection } from '../retrieval/index.js'; -import type { ContentChunk } from '../types.js'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const DATA_DIR = resolve(__dirname, '../../data'); -const LAWS_DIR = resolve(DATA_DIR, 'laws'); -const AIDS_DIR = resolve(DATA_DIR, 'ajudes'); - -// Aid program registry - maps filenames to program info (more specific keys first) -const AID_REGISTRY: Record = { - 'bono-alquiler-joven': { - programName: 'Bono Alquiler Joven 2025', - sourceUrl: 'https://tramits.gencat.cat/es/tramits/tramits-temes/22866_Bo_lloguer_joves', - }, - 'ajudes-lloguer-generalitat': { - programName: 'Ajudes al lloguer Generalitat 2025', - sourceUrl: 'https://habitatge.gencat.cat/ca/ambits/ajuts/subvencionslloguer/joves/', - }, - 'ajudes-generalitat': { - programName: 'Ajudes al lloguer Generalitat', - sourceUrl: 'https://habitatge.gencat.cat', - }, - 'borsa-jove': { - programName: 'Borsa Jove d\'Habitatge', - sourceUrl: 'https://habitatge.gencat.cat', - }, - 'drets-basics-inquili': { - programName: 'Guia de drets basics de l\'inquili', - sourceUrl: 'https://www.boe.es/buscar/act.php?id=BOE-A-1994-26003', - }, - 'llei-habitatge-2023': { - programName: 'Llei 12/2023 - Zones de mercat residencial tensat', - sourceUrl: 'https://habitatge.gencat.cat/ca/ambits/preus-ingressos-i-zones/limit-preu-lloguer/llistat-municipis-zmrt/', - }, -}; - -function detectAidInfo(filename: string): { programName: string; sourceUrl?: string } { - const baseName = filename.toLowerCase().replace(/\.(txt|md|pdf)$/, ''); - - for (const [key, info] of Object.entries(AID_REGISTRY)) { - if (baseName.includes(key)) { - return info; - } - } - - // Default: use filename as program name - return { programName: baseName.replace(/-/g, ' ') }; -} - -async function processLegalDocuments(): Promise { - if (!existsSync(LAWS_DIR)) { - console.log(' No laws directory found, skipping...'); - return []; - } - - const documents = await loadDocumentsFromDirectory(LAWS_DIR); - if (documents.length === 0) return []; - - console.log(` Found ${documents.length} legal document(s)`); - - let allChunks: ContentChunk[] = []; - - for (const doc of documents) { - console.log(` Processing: ${doc.filename}`); - const lawInfo = detectLawInfo(doc.filename, doc.content); - console.log(` → ${lawInfo.code} - ${lawInfo.fullName}`); - - let chunks = chunkLegalDocument(doc.content, lawInfo, doc.filename); - chunks = addOverlapContext(chunks, 150); - console.log(` → ${chunks.length} chunks`); - - allChunks = allChunks.concat(chunks); - } - - return allChunks; -} - -async function processAidDocuments(): Promise { - if (!existsSync(AIDS_DIR)) { - console.log(' No ajudes directory found, skipping...'); - return []; - } - - const files = readdirSync(AIDS_DIR).filter(f => - f.endsWith('.txt') || f.endsWith('.md') - ); - - if (files.length === 0) return []; - - console.log(` Found ${files.length} aid document(s)`); - - let allChunks: ContentChunk[] = []; - - for (const filename of files) { - console.log(` Processing: ${filename}`); - const filepath = resolve(AIDS_DIR, filename); - const content = readFileSync(filepath, 'utf-8'); - - const aidInfo = detectAidInfo(filename); - console.log(` → ${aidInfo.programName}`); - - const chunks = chunkAidDocument(content, aidInfo, filename); - console.log(` → ${chunks.length} chunks`); - - allChunks = allChunks.concat(chunks); - } - - return allChunks; -} - -async function main(): Promise { - console.log('═══════════════════════════════════════════════════'); - console.log(' LlarJove - Document Ingestion '); - console.log('═══════════════════════════════════════════════════\n'); - - const shouldClear = process.argv.includes('--clear'); - - // Initialize vector store - console.log('1. Initializing vector store...'); - await initVectorStore(); - - if (shouldClear) { - console.log(' Clearing existing collection...'); - await clearCollection(); - await initVectorStore(); - } - - // Process legal documents - console.log('\n2. Processing legal documents (data/laws/)...'); - const legalChunks = await processLegalDocuments(); - - // Process aid documents - console.log('\n3. Processing aid documents (data/ajudes/)...'); - const aidChunks = await processAidDocuments(); - - // Combine all chunks - const allChunks = [...legalChunks, ...aidChunks]; - - if (allChunks.length === 0) { - console.log('\n No documents found!'); - console.log(' Add files to:'); - console.log(' - data/laws/ (legal documents like LAU.txt)'); - console.log(' - data/ajudes/ (aid programs like bono-alquiler-joven.txt)'); - process.exit(1); - } - - // Generate embeddings - console.log('\n4. Generating embeddings...'); - const embeddedChunks = await embedChunks(allChunks); - - // Store in vector database - console.log('\n5. Storing in vector database...'); - await addChunks(embeddedChunks); - - // Final stats - const stats = await getStats(); - console.log('\n═══════════════════════════════════════════════════'); - console.log(' Summary '); - console.log('═══════════════════════════════════════════════════'); - console.log(` Legal chunks: ${legalChunks.length}`); - console.log(` Aid chunks: ${aidChunks.length}`); - console.log(` Total stored: ${stats.count}`); - console.log('\n Ready! Run: pnpm dev'); - console.log('═══════════════════════════════════════════════════\n'); -} - -main().catch((error) => { - console.error('Ingestion failed:', error); - process.exit(1); -}); +/** + * Ingestion Script - LlarJove + * + * Processes both legal documents and aid program documents. + * - data/laws/ → Legal documents (LAU, etc.) → chunkLegalDocument + * - data/ajudes/ → Aid programs (Bono Joven, etc.) → chunkAidDocument + * + * Usage: pnpm ingest [--clear] + */ + +import { resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; +import { existsSync, readdirSync, readFileSync } from 'fs'; +import { + loadDocumentsFromDirectory, + detectLawInfo, + chunkLegalDocument, + chunkAidDocument, + addOverlapContext, + embedChunks, +} from '../ingestion/index.js'; +import { initVectorStore, addChunks, getStats, clearCollection } from '../retrieval/index.js'; +import type { ContentChunk } from '../types.js'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const DATA_DIR = resolve(__dirname, '../../data'); +const LAWS_DIR = resolve(DATA_DIR, 'laws'); +const AIDS_DIR = resolve(DATA_DIR, 'ajudes'); + +// Aid program registry - maps filenames to program info (more specific keys first) +const AID_REGISTRY: Record = { + 'bono-alquiler-joven': { + programName: 'Bono Alquiler Joven 2025', + sourceUrl: 'https://tramits.gencat.cat/es/tramits/tramits-temes/22866_Bo_lloguer_joves', + }, + 'ajudes-lloguer-generalitat': { + programName: 'Ajudes al lloguer Generalitat 2025', + sourceUrl: 'https://habitatge.gencat.cat/ca/ambits/ajuts/subvencionslloguer/joves/', + }, + 'ajudes-generalitat': { + programName: 'Ajudes al lloguer Generalitat', + sourceUrl: 'https://habitatge.gencat.cat', + }, + 'borsa-jove': { + programName: 'Borsa Jove d\'Habitatge', + sourceUrl: 'https://habitatge.gencat.cat', + }, + 'drets-basics-inquili': { + programName: 'Guia de drets basics de l\'inquili', + sourceUrl: 'https://www.boe.es/buscar/act.php?id=BOE-A-1994-26003', + }, + 'llei-habitatge-2023': { + programName: 'Llei 12/2023 - Zones de mercat residencial tensat', + sourceUrl: 'https://habitatge.gencat.cat/ca/ambits/preus-ingressos-i-zones/limit-preu-lloguer/llistat-municipis-zmrt/', + }, +}; + +function detectAidInfo(filename: string): { programName: string; sourceUrl?: string } { + const baseName = filename.toLowerCase().replace(/\.(txt|md|pdf)$/, ''); + + for (const [key, info] of Object.entries(AID_REGISTRY)) { + if (baseName.includes(key)) { + return info; + } + } + + // Default: use filename as program name + return { programName: baseName.replace(/-/g, ' ') }; +} + +async function processLegalDocuments(): Promise { + if (!existsSync(LAWS_DIR)) { + console.log(' No laws directory found, skipping...'); + return []; + } + + const documents = await loadDocumentsFromDirectory(LAWS_DIR); + if (documents.length === 0) return []; + + console.log(` Found ${documents.length} legal document(s)`); + + let allChunks: ContentChunk[] = []; + + for (const doc of documents) { + console.log(` Processing: ${doc.filename}`); + const lawInfo = detectLawInfo(doc.filename, doc.content); + console.log(` → ${lawInfo.code} - ${lawInfo.fullName}`); + + let chunks = chunkLegalDocument(doc.content, lawInfo, doc.filename); + chunks = addOverlapContext(chunks, 150); + console.log(` → ${chunks.length} chunks`); + + allChunks = allChunks.concat(chunks); + } + + return allChunks; +} + +async function processAidDocuments(): Promise { + if (!existsSync(AIDS_DIR)) { + console.log(' No ajudes directory found, skipping...'); + return []; + } + + const files = readdirSync(AIDS_DIR).filter(f => + f.endsWith('.txt') || f.endsWith('.md') + ); + + if (files.length === 0) return []; + + console.log(` Found ${files.length} aid document(s)`); + + let allChunks: ContentChunk[] = []; + + for (const filename of files) { + console.log(` Processing: ${filename}`); + const filepath = resolve(AIDS_DIR, filename); + const content = readFileSync(filepath, 'utf-8'); + + const aidInfo = detectAidInfo(filename); + console.log(` → ${aidInfo.programName}`); + + const chunks = chunkAidDocument(content, aidInfo, filename); + console.log(` → ${chunks.length} chunks`); + + allChunks = allChunks.concat(chunks); + } + + return allChunks; +} + +async function main(): Promise { + console.log('═══════════════════════════════════════════════════'); + console.log(' LlarJove - Document Ingestion '); + console.log('═══════════════════════════════════════════════════\n'); + + const shouldClear = process.argv.includes('--clear'); + + // Initialize vector store + console.log('1. Initializing vector store...'); + await initVectorStore(); + + if (shouldClear) { + console.log(' Clearing existing collection...'); + await clearCollection(); + await initVectorStore(); + } + + // Process legal documents + console.log('\n2. Processing legal documents (data/laws/)...'); + const legalChunks = await processLegalDocuments(); + + // Process aid documents + console.log('\n3. Processing aid documents (data/ajudes/)...'); + const aidChunks = await processAidDocuments(); + + // Combine all chunks + const allChunks = [...legalChunks, ...aidChunks]; + + if (allChunks.length === 0) { + console.log('\n No documents found!'); + console.log(' Add files to:'); + console.log(' - data/laws/ (legal documents like LAU.txt)'); + console.log(' - data/ajudes/ (aid programs like bono-alquiler-joven.txt)'); + process.exit(1); + } + + // Generate embeddings + console.log('\n4. Generating embeddings...'); + const embeddedChunks = await embedChunks(allChunks); + + // Store in vector database + console.log('\n5. Storing in vector database...'); + await addChunks(embeddedChunks); + + // Final stats + const stats = await getStats(); + console.log('\n═══════════════════════════════════════════════════'); + console.log(' Summary '); + console.log('═══════════════════════════════════════════════════'); + console.log(` Legal chunks: ${legalChunks.length}`); + console.log(` Aid chunks: ${aidChunks.length}`); + console.log(` Total stored: ${stats.count}`); + console.log('\n Ready! Run: pnpm dev'); + console.log('═══════════════════════════════════════════════════\n'); +} + +main().catch((error) => { + console.error('Ingestion failed:', error); + process.exit(1); +}); diff --git a/tests/aidChunker.test.ts b/tests/aidChunker.test.ts index ca8b37f..c6776e0 100644 --- a/tests/aidChunker.test.ts +++ b/tests/aidChunker.test.ts @@ -1,121 +1,121 @@ -/** - * Tests for the aid program document chunker - */ - -import { describe, it, expect } from 'vitest'; -import { chunkAidDocument, extractDeadline } from '../src/ingestion/aidChunker.js'; - -const defaultAidInfo = { programName: 'Test Program', sourceUrl: 'https://example.com' }; - -describe('chunkAidDocument', () => { - const multiSectionDoc = `# Bono Alquiler Joven 2025 - -## Què és? - -El Bono Alquiler Joven és una ajuda econòmica. - -## Requisits - -### Edat -- Tenir entre 18 i 35 anys. - -### Ingressos -- Ingressos ≤ 25.200€ bruts. - -## Terminis de sol·licitud 2025 - -- INICI: 30 de juny de 2025 -- FI: 11 de juliol de 2025 a les 14:00h - -## Quantia - -Fins a 250€/mes durant 24 mesos.`; - - it('should split a multi-section ## document correctly', () => { - const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); - - expect(chunks.length).toBeGreaterThanOrEqual(4); - const titles = chunks.map(c => c.metadata.section); - expect(titles).toContain('Què és?'); - expect(titles).toContain('Requisits'); - expect(titles).toContain('Terminis de sol·licitud 2025'); - expect(titles).toContain('Quantia'); - }); - - it('should preserve section content and program name', () => { - const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); - const quèEs = chunks.find(c => c.metadata.section === 'Què és?'); - - expect(quèEs).toBeDefined(); - expect(quèEs?.text).toContain('Bono Alquiler Joven'); - expect(quèEs?.text).toContain('ajuda econòmica'); - expect(quèEs?.metadata.programName).toBe('Test Program'); - expect(quèEs?.metadata.sourceFile).toBe('bono.txt'); - }); - - it('should keep ### subsections inside ## sections', () => { - const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); - const requisits = chunks.find(c => c.metadata.section === 'Requisits'); - - expect(requisits).toBeDefined(); - expect(requisits?.text).toContain('Edat'); - expect(requisits?.text).toContain('Ingressos'); - expect(requisits?.text).toContain('18 i 35 anys'); - expect(requisits?.text).toContain('25.200€'); - }); - - it('should extract deadline metadata from Terminis sections', () => { - const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); - const terminis = chunks.find(c => c.metadata.section === 'Terminis de sol·licitud 2025'); - - expect(terminis).toBeDefined(); - expect(terminis?.metadata.deadline).toBe('11-07-2025'); - }); - - it('should extract amount metadata', () => { - const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); - const quantia = chunks.find(c => c.metadata.section === 'Quantia'); - - expect(quantia).toBeDefined(); - expect(quantia?.metadata.amount).toBeDefined(); - expect(quantia?.metadata.amount).toMatch(/\d+€/); - }); - - it('should fall back to single chunk when no ## headers exist', () => { - const plainText = 'Just a paragraph.\n\nAnother paragraph. No markdown headers.'; - const chunks = chunkAidDocument(plainText, defaultAidInfo, 'plain.txt'); - - expect(chunks.length).toBe(1); - expect(chunks[0]?.metadata.section).toBe('Informació general'); - expect(chunks[0]?.text).toContain('Just a paragraph'); - expect(chunks[0]?.text).toContain('Another paragraph'); - }); - - it('should handle empty text', () => { - const chunks = chunkAidDocument('', defaultAidInfo, 'empty.txt'); - expect(chunks.length).toBe(0); - }); - - it('should generate unique IDs', () => { - const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); - const ids = chunks.map(c => c.id); - const uniqueIds = new Set(ids); - expect(uniqueIds.size).toBe(ids.length); - }); -}); - -describe('extractDeadline', () => { - it('should extract end date when FI: is present', () => { - const text = 'INICI: 30 de juny de 2025. FI: 11 de juliol de 2025 a les 14:00h'; - expect(extractDeadline(text)).toBe('11-07-2025'); - }); - - it('should return last date when no FI marker', () => { - const text = 'Del 1 de gener de 2025 al 31 de desembre de 2025'; - expect(extractDeadline(text)).toBe('31-12-2025'); - }); - - it('should return undefined when no date pattern', () => { - expect(extractDeadline('No dates here')).toBeUndefined(); - }); -}); +/** + * Tests for the aid program document chunker + */ + +import { describe, it, expect } from 'vitest'; +import { chunkAidDocument, extractDeadline } from '../src/ingestion/aidChunker.js'; + +const defaultAidInfo = { programName: 'Test Program', sourceUrl: 'https://example.com' }; + +describe('chunkAidDocument', () => { + const multiSectionDoc = `# Bono Alquiler Joven 2025 + +## Què és? + +El Bono Alquiler Joven és una ajuda econòmica. + +## Requisits + +### Edat +- Tenir entre 18 i 35 anys. + +### Ingressos +- Ingressos ≤ 25.200€ bruts. + +## Terminis de sol·licitud 2025 + +- INICI: 30 de juny de 2025 +- FI: 11 de juliol de 2025 a les 14:00h + +## Quantia + +Fins a 250€/mes durant 24 mesos.`; + + it('should split a multi-section ## document correctly', () => { + const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); + + expect(chunks.length).toBeGreaterThanOrEqual(4); + const titles = chunks.map(c => c.metadata.section); + expect(titles).toContain('Què és?'); + expect(titles).toContain('Requisits'); + expect(titles).toContain('Terminis de sol·licitud 2025'); + expect(titles).toContain('Quantia'); + }); + + it('should preserve section content and program name', () => { + const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); + const quèEs = chunks.find(c => c.metadata.section === 'Què és?'); + + expect(quèEs).toBeDefined(); + expect(quèEs?.text).toContain('Bono Alquiler Joven'); + expect(quèEs?.text).toContain('ajuda econòmica'); + expect(quèEs?.metadata.programName).toBe('Test Program'); + expect(quèEs?.metadata.sourceFile).toBe('bono.txt'); + }); + + it('should keep ### subsections inside ## sections', () => { + const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); + const requisits = chunks.find(c => c.metadata.section === 'Requisits'); + + expect(requisits).toBeDefined(); + expect(requisits?.text).toContain('Edat'); + expect(requisits?.text).toContain('Ingressos'); + expect(requisits?.text).toContain('18 i 35 anys'); + expect(requisits?.text).toContain('25.200€'); + }); + + it('should extract deadline metadata from Terminis sections', () => { + const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); + const terminis = chunks.find(c => c.metadata.section === 'Terminis de sol·licitud 2025'); + + expect(terminis).toBeDefined(); + expect(terminis?.metadata.deadline).toBe('11-07-2025'); + }); + + it('should extract amount metadata', () => { + const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); + const quantia = chunks.find(c => c.metadata.section === 'Quantia'); + + expect(quantia).toBeDefined(); + expect(quantia?.metadata.amount).toBeDefined(); + expect(quantia?.metadata.amount).toMatch(/\d+€/); + }); + + it('should fall back to single chunk when no ## headers exist', () => { + const plainText = 'Just a paragraph.\n\nAnother paragraph. No markdown headers.'; + const chunks = chunkAidDocument(plainText, defaultAidInfo, 'plain.txt'); + + expect(chunks.length).toBe(1); + expect(chunks[0]?.metadata.section).toBe('Informació general'); + expect(chunks[0]?.text).toContain('Just a paragraph'); + expect(chunks[0]?.text).toContain('Another paragraph'); + }); + + it('should handle empty text', () => { + const chunks = chunkAidDocument('', defaultAidInfo, 'empty.txt'); + expect(chunks.length).toBe(0); + }); + + it('should generate unique IDs', () => { + const chunks = chunkAidDocument(multiSectionDoc, defaultAidInfo, 'bono.txt'); + const ids = chunks.map(c => c.id); + const uniqueIds = new Set(ids); + expect(uniqueIds.size).toBe(ids.length); + }); +}); + +describe('extractDeadline', () => { + it('should extract end date when FI: is present', () => { + const text = 'INICI: 30 de juny de 2025. FI: 11 de juliol de 2025 a les 14:00h'; + expect(extractDeadline(text)).toBe('11-07-2025'); + }); + + it('should return last date when no FI marker', () => { + const text = 'Del 1 de gener de 2025 al 31 de desembre de 2025'; + expect(extractDeadline(text)).toBe('31-12-2025'); + }); + + it('should return undefined when no date pattern', () => { + expect(extractDeadline('No dates here')).toBeUndefined(); + }); +}); diff --git a/web/.env.development b/web/.env.development index 93e6647..d403d44 100644 --- a/web/.env.development +++ b/web/.env.development @@ -1 +1 @@ -NEXT_PUBLIC_API_URL=http://localhost:3000 +NEXT_PUBLIC_API_URL=http://localhost:3000 diff --git a/web/next-env.d.ts b/web/next-env.d.ts index 830fb59..2a4d166 100644 --- a/web/next-env.d.ts +++ b/web/next-env.d.ts @@ -1,6 +1,6 @@ -/// -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/web/next.config.ts b/web/next.config.ts index f5cdd46..1d918c2 100644 --- a/web/next.config.ts +++ b/web/next.config.ts @@ -1,9 +1,9 @@ -import type { NextConfig } from 'next'; - -const nextConfig: NextConfig = { - output: 'standalone', - typescript: { ignoreBuildErrors: true }, - outputFileTracingRoot: __dirname, -}; - -export default nextConfig; +import type { NextConfig } from 'next'; + +const nextConfig: NextConfig = { + output: 'standalone', + typescript: { ignoreBuildErrors: true }, + outputFileTracingRoot: __dirname, +}; + +export default nextConfig; diff --git a/web/package.json b/web/package.json index 3db4dfd..767a0a2 100644 --- a/web/package.json +++ b/web/package.json @@ -1,34 +1,34 @@ -{ - "name": "llarjove-web", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "dev": "next dev --turbopack --port 3001", - "build": "next build", - "start": "next start", - "test": "vitest run", - "test:watch": "vitest" - }, - "dependencies": { - "clsx": "^2.1.1", - "geist": "^1.7.0", - "next": "^15.1.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "tailwind-merge": "^3.4.0" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4.1.18", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", - "@types/react": "^19.2.13", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^4.3.4", - "jsdom": "25", - "tailwindcss": "^4.1.18", - "typescript": "~5.6.2", - "vitest": "^4.0.18" - } -} +{ + "name": "llarjove-web", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "next dev --turbopack --port 3001", + "build": "next build", + "start": "next start", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "clsx": "^2.1.1", + "geist": "^1.7.0", + "next": "^15.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwind-merge": "^3.4.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.1.18", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^4.3.4", + "jsdom": "25", + "tailwindcss": "^4.1.18", + "typescript": "~5.6.2", + "vitest": "^4.0.18" + } +} diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index c5deeaf..3d305b3 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -1,2842 +1,2842 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - clsx: - specifier: ^2.1.1 - version: 2.1.1 - geist: - specifier: ^1.7.0 - version: 1.7.0(next@15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - next: - specifier: ^15.1.0 - version: 15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: - specifier: ^19.0.0 - version: 19.2.4 - react-dom: - specifier: ^19.0.0 - version: 19.2.4(react@19.2.4) - tailwind-merge: - specifier: ^3.4.0 - version: 3.4.0 - devDependencies: - '@tailwindcss/postcss': - specifier: ^4.1.18 - version: 4.1.18 - '@testing-library/jest-dom': - specifier: ^6.9.1 - version: 6.9.1 - '@testing-library/react': - specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@testing-library/user-event': - specifier: ^14.6.1 - version: 14.6.1(@testing-library/dom@10.4.1) - '@types/react': - specifier: ^19.2.13 - version: 19.2.13 - '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.13) - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.7.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)) - jsdom: - specifier: '25' - version: 25.0.1 - tailwindcss: - specifier: ^4.1.18 - version: 4.1.18 - typescript: - specifier: ~5.6.2 - version: 5.6.3 - vitest: - specifier: ^4.0.18 - version: 4.0.18(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.30.2) - -packages: - - '@adobe/css-tools@4.4.4': - resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - - '@asamuzakjp/css-color@3.2.0': - resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@csstools/color-helpers@5.1.0': - resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} - engines: {node: '>=18'} - - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-color-parser@3.1.0': - resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} - - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} - - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@img/colour@1.0.0': - resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} - engines: {node: '>=18'} - - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} - cpu: [arm64] - os: [darwin] - - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} - cpu: [arm64] - os: [linux] - - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} - cpu: [arm] - os: [linux] - - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} - cpu: [ppc64] - os: [linux] - - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} - cpu: [riscv64] - os: [linux] - - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} - cpu: [s390x] - os: [linux] - - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} - cpu: [x64] - os: [linux] - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} - cpu: [arm64] - os: [linux] - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} - cpu: [x64] - os: [linux] - - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ppc64] - os: [linux] - - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [riscv64] - os: [linux] - - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] - - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [win32] - - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ia32] - os: [win32] - - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@next/env@15.5.12': - resolution: {integrity: sha512-pUvdJN1on574wQHjaBfNGDt9Mz5utDSZFsIIQkMzPgNS8ZvT4H2mwOrOIClwsQOb6EGx5M76/CZr6G8i6pSpLg==} - - '@next/swc-darwin-arm64@15.5.12': - resolution: {integrity: sha512-RnRjBtH8S8eXCpUNkQ+543DUc7ys8y15VxmFU9HRqlo9BG3CcBUiwNtF8SNoi2xvGCVJq1vl2yYq+3oISBS0Zg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@15.5.12': - resolution: {integrity: sha512-nqa9/7iQlboF1EFtNhWxQA0rQstmYRSBGxSM6g3GxvxHxcoeqVXfGNr9stJOme674m2V7r4E3+jEhhGvSQhJRA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@15.5.12': - resolution: {integrity: sha512-dCzAjqhDHwmoB2M4eYfVKqXs99QdQxNQVpftvP1eGVppamXh/OkDAwV737Zr0KPXEqRUMN4uCjh6mjO+XtF3Mw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@15.5.12': - resolution: {integrity: sha512-+fpGWvQiITgf7PUtbWY1H7qUSnBZsPPLyyq03QuAKpVoTy/QUx1JptEDTQMVvQhvizCEuNLEeghrQUyXQOekuw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@15.5.12': - resolution: {integrity: sha512-jSLvgdRRL/hrFAPqEjJf1fFguC719kmcptjNVDJl26BnJIpjL3KH5h6mzR4mAweociLQaqvt4UyzfbFjgAdDcw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@15.5.12': - resolution: {integrity: sha512-/uaF0WfmYqQgLfPmN6BvULwxY0dufI2mlN2JbOKqqceZh1G4hjREyi7pg03zjfyS6eqNemHAZPSoP84x17vo6w==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@15.5.12': - resolution: {integrity: sha512-xhsL1OvQSfGmlL5RbOmU+FV120urrgFpYLq+6U8C6KIym32gZT6XF/SDE92jKzzlPWskkbjOKCpqk5m4i8PEfg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-x64-msvc@15.5.12': - resolution: {integrity: sha512-Z1Dh6lhFkxvBDH1FoW6OU/L6prYwPSlwjLiZkExIAh8fbP6iI/M7iGTQAJPYJ9YFlWobCZ1PHbchFhFYb2ADkw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/rollup-android-arm-eabi@4.57.1': - resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.57.1': - resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.57.1': - resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.57.1': - resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.57.1': - resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.57.1': - resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': - resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.57.1': - resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.57.1': - resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.57.1': - resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.57.1': - resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.57.1': - resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.57.1': - resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.57.1': - resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.57.1': - resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.57.1': - resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.57.1': - resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.57.1': - resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.57.1': - resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.57.1': - resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.57.1': - resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.57.1': - resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.57.1': - resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.57.1': - resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.57.1': - resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} - cpu: [x64] - os: [win32] - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} - - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} - - '@tailwindcss/postcss@4.1.18': - resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} - - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} - engines: {node: '>=18'} - - '@testing-library/jest-dom@6.9.1': - resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} - engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - - '@testing-library/react@16.3.2': - resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} - engines: {node: '>=18'} - peerDependencies: - '@testing-library/dom': ^10.0.0 - '@types/react': ^18.0.0 || ^19.0.0 - '@types/react-dom': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@testing-library/user-event@14.6.1': - resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} - engines: {node: '>=12', npm: '>=6'} - peerDependencies: - '@testing-library/dom': '>=7.21.4' - - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.13': - resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} - - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - baseline-browser-mapping@2.9.19: - resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} - hasBin: true - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - caniuse-lite@1.0.30001769: - resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} - - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} - - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - css.escape@1.5.1: - resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - - cssstyle@4.6.0: - resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} - engines: {node: '>=18'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - - dom-accessibility-api@0.6.3: - resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - electron-to-chromium@1.5.286: - resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} - - enhanced-resolve@5.19.0: - resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} - engines: {node: '>=10.13.0'} - - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - geist@1.7.0: - resolution: {integrity: sha512-ZaoiZwkSf0DwwB1ncdLKp+ggAldqxl5L1+SXaNIBGkPAqcu+xjVJLxlf3/S8vLt9UHx1xu5fz3lbzKCj5iOVdQ==} - peerDependencies: - next: '>=13.2.0' - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - jsdom@25.0.1: - resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} - engines: {node: '>=18'} - peerDependencies: - canvas: ^2.11.2 - peerDependenciesMeta: - canvas: - optional: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} - engines: {node: '>= 12.0.0'} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - next@15.5.12: - resolution: {integrity: sha512-Fi/wQ4Etlrn60rz78bebG1i1SR20QxvV8tVp6iJspjLUSHcZoeUXCt+vmWoEcza85ElZzExK/jJ/F6SvtGktjA==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - - nwsapi@2.2.23: - resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} - peerDependencies: - react: ^19.2.4 - - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} - engines: {node: '>=0.10.0'} - - redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} - - rollup@4.57.1: - resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - rrweb-cssom@0.7.1: - resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} - - rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - - styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - 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 - - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - - tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} - - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} - - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} - engines: {node: '>=18'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} - engines: {node: '>=14.0.0'} - - tldts-core@6.1.86: - resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - - tldts@6.1.86: - resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} - hasBin: true - - tough-cookie@5.1.2: - resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} - engines: {node: '>=16'} - - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} - engines: {node: '>=14.17'} - hasBin: true - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - -snapshots: - - '@adobe/css-tools@4.4.4': {} - - '@alloc/quick-lru@5.2.0': {} - - '@asamuzakjp/css-color@3.2.0': - dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 10.4.3 - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.0': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.6': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.0': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/runtime@7.28.6': {} - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@csstools/color-helpers@5.1.0': {} - - '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/color-helpers': 5.1.0 - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-tokenizer@3.0.4': {} - - '@emnapi/runtime@1.8.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@esbuild/aix-ppc64@0.27.3': - optional: true - - '@esbuild/android-arm64@0.27.3': - optional: true - - '@esbuild/android-arm@0.27.3': - optional: true - - '@esbuild/android-x64@0.27.3': - optional: true - - '@esbuild/darwin-arm64@0.27.3': - optional: true - - '@esbuild/darwin-x64@0.27.3': - optional: true - - '@esbuild/freebsd-arm64@0.27.3': - optional: true - - '@esbuild/freebsd-x64@0.27.3': - optional: true - - '@esbuild/linux-arm64@0.27.3': - optional: true - - '@esbuild/linux-arm@0.27.3': - optional: true - - '@esbuild/linux-ia32@0.27.3': - optional: true - - '@esbuild/linux-loong64@0.27.3': - optional: true - - '@esbuild/linux-mips64el@0.27.3': - optional: true - - '@esbuild/linux-ppc64@0.27.3': - optional: true - - '@esbuild/linux-riscv64@0.27.3': - optional: true - - '@esbuild/linux-s390x@0.27.3': - optional: true - - '@esbuild/linux-x64@0.27.3': - optional: true - - '@esbuild/netbsd-arm64@0.27.3': - optional: true - - '@esbuild/netbsd-x64@0.27.3': - optional: true - - '@esbuild/openbsd-arm64@0.27.3': - optional: true - - '@esbuild/openbsd-x64@0.27.3': - optional: true - - '@esbuild/openharmony-arm64@0.27.3': - optional: true - - '@esbuild/sunos-x64@0.27.3': - optional: true - - '@esbuild/win32-arm64@0.27.3': - optional: true - - '@esbuild/win32-ia32@0.27.3': - optional: true - - '@esbuild/win32-x64@0.27.3': - optional: true - - '@img/colour@1.0.0': - optional: true - - '@img/sharp-darwin-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 - optional: true - - '@img/sharp-darwin-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 - optional: true - - '@img/sharp-libvips-darwin-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-darwin-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm@1.2.4': - optional: true - - '@img/sharp-libvips-linux-ppc64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-riscv64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-s390x@1.2.4': - optional: true - - '@img/sharp-libvips-linux-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - optional: true - - '@img/sharp-linux-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 - optional: true - - '@img/sharp-linux-arm@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 - optional: true - - '@img/sharp-linux-ppc64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 - optional: true - - '@img/sharp-linux-riscv64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 - optional: true - - '@img/sharp-linux-s390x@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 - optional: true - - '@img/sharp-linux-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - optional: true - - '@img/sharp-wasm32@0.34.5': - dependencies: - '@emnapi/runtime': 1.8.1 - optional: true - - '@img/sharp-win32-arm64@0.34.5': - optional: true - - '@img/sharp-win32-ia32@0.34.5': - optional: true - - '@img/sharp-win32-x64@0.34.5': - optional: true - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@next/env@15.5.12': {} - - '@next/swc-darwin-arm64@15.5.12': - optional: true - - '@next/swc-darwin-x64@15.5.12': - optional: true - - '@next/swc-linux-arm64-gnu@15.5.12': - optional: true - - '@next/swc-linux-arm64-musl@15.5.12': - optional: true - - '@next/swc-linux-x64-gnu@15.5.12': - optional: true - - '@next/swc-linux-x64-musl@15.5.12': - optional: true - - '@next/swc-win32-arm64-msvc@15.5.12': - optional: true - - '@next/swc-win32-x64-msvc@15.5.12': - optional: true - - '@rolldown/pluginutils@1.0.0-beta.27': {} - - '@rollup/rollup-android-arm-eabi@4.57.1': - optional: true - - '@rollup/rollup-android-arm64@4.57.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.57.1': - optional: true - - '@rollup/rollup-darwin-x64@4.57.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.57.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.57.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.57.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.57.1': - optional: true - - '@rollup/rollup-openbsd-x64@4.57.1': - optional: true - - '@rollup/rollup-openharmony-arm64@4.57.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.57.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.57.1': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.57.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.57.1': - optional: true - - '@standard-schema/spec@1.1.0': {} - - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 - - '@tailwindcss/node@4.1.18': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.19.0 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.18 - - '@tailwindcss/oxide-android-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide@4.1.18': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - - '@tailwindcss/postcss@4.1.18': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - postcss: 8.5.6 - tailwindcss: 4.1.18 - - '@testing-library/dom@10.4.1': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.6 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - picocolors: 1.1.1 - pretty-format: 27.5.1 - - '@testing-library/jest-dom@6.9.1': - dependencies: - '@adobe/css-tools': 4.4.4 - aria-query: 5.3.2 - css.escape: 1.5.1 - dom-accessibility-api: 0.6.3 - picocolors: 1.1.1 - redent: 3.0.0 - - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@babel/runtime': 7.28.6 - '@testing-library/dom': 10.4.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.13 - '@types/react-dom': 19.2.3(@types/react@19.2.13) - - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': - dependencies: - '@testing-library/dom': 10.4.1 - - '@types/aria-query@5.0.4': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/deep-eql@4.0.2': {} - - '@types/estree@1.0.8': {} - - '@types/react-dom@19.2.3(@types/react@19.2.13)': - dependencies: - '@types/react': 19.2.13 - - '@types/react@19.2.13': - dependencies: - csstype: 3.2.3 - - '@vitejs/plugin-react@4.7.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2) - transitivePeerDependencies: - - supports-color - - '@vitest/expect@4.0.18': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - chai: 6.2.2 - tinyrainbow: 3.0.3 - - '@vitest/mocker@4.0.18(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2) - - '@vitest/pretty-format@4.0.18': - dependencies: - tinyrainbow: 3.0.3 - - '@vitest/runner@4.0.18': - dependencies: - '@vitest/utils': 4.0.18 - pathe: 2.0.3 - - '@vitest/snapshot@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.0.18': {} - - '@vitest/utils@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 - - agent-base@7.1.4: {} - - ansi-regex@5.0.1: {} - - ansi-styles@5.2.0: {} - - aria-query@5.3.0: - dependencies: - dequal: 2.0.3 - - aria-query@5.3.2: {} - - assertion-error@2.0.1: {} - - asynckit@0.4.0: {} - - baseline-browser-mapping@2.9.19: {} - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.9.19 - caniuse-lite: 1.0.30001769 - electron-to-chromium: 1.5.286 - node-releases: 2.0.27 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - caniuse-lite@1.0.30001769: {} - - chai@6.2.2: {} - - client-only@0.0.1: {} - - clsx@2.1.1: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - convert-source-map@2.0.0: {} - - css.escape@1.5.1: {} - - cssstyle@4.6.0: - dependencies: - '@asamuzakjp/css-color': 3.2.0 - rrweb-cssom: 0.8.0 - - csstype@3.2.3: {} - - data-urls@5.0.0: - dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decimal.js@10.6.0: {} - - delayed-stream@1.0.0: {} - - dequal@2.0.3: {} - - detect-libc@2.1.2: {} - - dom-accessibility-api@0.5.16: {} - - dom-accessibility-api@0.6.3: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - electron-to-chromium@1.5.286: {} - - enhanced-resolve@5.19.0: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - - entities@6.0.1: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-module-lexer@1.7.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild@0.27.3: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 - - escalade@3.2.0: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - expect-type@1.3.0: {} - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - geist@1.7.0(next@15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): - dependencies: - next: 15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - - gensync@1.0.0-beta.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - html-encoding-sniffer@4.0.0: - dependencies: - whatwg-encoding: 3.1.1 - - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - indent-string@4.0.0: {} - - is-potential-custom-element-name@1.0.1: {} - - jiti@2.6.1: {} - - js-tokens@4.0.0: {} - - jsdom@25.0.1: - dependencies: - cssstyle: 4.6.0 - data-urls: 5.0.0 - decimal.js: 10.6.0 - form-data: 4.0.5 - html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.23 - parse5: 7.3.0 - rrweb-cssom: 0.7.1 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 5.1.2 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 - ws: 8.19.0 - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - jsesc@3.1.0: {} - - json5@2.2.3: {} - - lightningcss-android-arm64@1.30.2: - optional: true - - lightningcss-darwin-arm64@1.30.2: - optional: true - - lightningcss-darwin-x64@1.30.2: - optional: true - - lightningcss-freebsd-x64@1.30.2: - optional: true - - lightningcss-linux-arm-gnueabihf@1.30.2: - optional: true - - lightningcss-linux-arm64-gnu@1.30.2: - optional: true - - lightningcss-linux-arm64-musl@1.30.2: - optional: true - - lightningcss-linux-x64-gnu@1.30.2: - optional: true - - lightningcss-linux-x64-musl@1.30.2: - optional: true - - lightningcss-win32-arm64-msvc@1.30.2: - optional: true - - lightningcss-win32-x64-msvc@1.30.2: - optional: true - - lightningcss@1.30.2: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - - lru-cache@10.4.3: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lz-string@1.5.0: {} - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - math-intrinsics@1.1.0: {} - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - min-indent@1.0.1: {} - - ms@2.1.3: {} - - nanoid@3.3.11: {} - - next@15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): - dependencies: - '@next/env': 15.5.12 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001769 - postcss: 8.4.31 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) - optionalDependencies: - '@next/swc-darwin-arm64': 15.5.12 - '@next/swc-darwin-x64': 15.5.12 - '@next/swc-linux-arm64-gnu': 15.5.12 - '@next/swc-linux-arm64-musl': 15.5.12 - '@next/swc-linux-x64-gnu': 15.5.12 - '@next/swc-linux-x64-musl': 15.5.12 - '@next/swc-win32-arm64-msvc': 15.5.12 - '@next/swc-win32-x64-msvc': 15.5.12 - sharp: 0.34.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - node-releases@2.0.27: {} - - nwsapi@2.2.23: {} - - obug@2.1.1: {} - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - pathe@2.0.3: {} - - picocolors@1.1.1: {} - - picomatch@4.0.3: {} - - postcss@8.4.31: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - - punycode@2.3.1: {} - - react-dom@19.2.4(react@19.2.4): - dependencies: - react: 19.2.4 - scheduler: 0.27.0 - - react-is@17.0.2: {} - - react-refresh@0.17.0: {} - - react@19.2.4: {} - - redent@3.0.0: - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - - rollup@4.57.1: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.57.1 - '@rollup/rollup-android-arm64': 4.57.1 - '@rollup/rollup-darwin-arm64': 4.57.1 - '@rollup/rollup-darwin-x64': 4.57.1 - '@rollup/rollup-freebsd-arm64': 4.57.1 - '@rollup/rollup-freebsd-x64': 4.57.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 - '@rollup/rollup-linux-arm-musleabihf': 4.57.1 - '@rollup/rollup-linux-arm64-gnu': 4.57.1 - '@rollup/rollup-linux-arm64-musl': 4.57.1 - '@rollup/rollup-linux-loong64-gnu': 4.57.1 - '@rollup/rollup-linux-loong64-musl': 4.57.1 - '@rollup/rollup-linux-ppc64-gnu': 4.57.1 - '@rollup/rollup-linux-ppc64-musl': 4.57.1 - '@rollup/rollup-linux-riscv64-gnu': 4.57.1 - '@rollup/rollup-linux-riscv64-musl': 4.57.1 - '@rollup/rollup-linux-s390x-gnu': 4.57.1 - '@rollup/rollup-linux-x64-gnu': 4.57.1 - '@rollup/rollup-linux-x64-musl': 4.57.1 - '@rollup/rollup-openbsd-x64': 4.57.1 - '@rollup/rollup-openharmony-arm64': 4.57.1 - '@rollup/rollup-win32-arm64-msvc': 4.57.1 - '@rollup/rollup-win32-ia32-msvc': 4.57.1 - '@rollup/rollup-win32-x64-gnu': 4.57.1 - '@rollup/rollup-win32-x64-msvc': 4.57.1 - fsevents: 2.3.3 - - rrweb-cssom@0.7.1: {} - - rrweb-cssom@0.8.0: {} - - safer-buffer@2.1.2: {} - - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 - - scheduler@0.27.0: {} - - semver@6.3.1: {} - - semver@7.7.4: - optional: true - - sharp@0.34.5: - dependencies: - '@img/colour': 1.0.0 - detect-libc: 2.1.2 - semver: 7.7.4 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 - optional: true - - siginfo@2.0.0: {} - - source-map-js@1.2.1: {} - - stackback@0.0.2: {} - - std-env@3.10.0: {} - - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - - styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.4): - dependencies: - client-only: 0.0.1 - react: 19.2.4 - optionalDependencies: - '@babel/core': 7.29.0 - - symbol-tree@3.2.4: {} - - tailwind-merge@3.4.0: {} - - tailwindcss@4.1.18: {} - - tapable@2.3.0: {} - - tinybench@2.9.0: {} - - tinyexec@1.0.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - tinyrainbow@3.0.3: {} - - tldts-core@6.1.86: {} - - tldts@6.1.86: - dependencies: - tldts-core: 6.1.86 - - tough-cookie@5.1.2: - dependencies: - tldts: 6.1.86 - - tr46@5.1.1: - dependencies: - punycode: 2.3.1 - - tslib@2.8.1: {} - - typescript@5.6.3: {} - - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2): - dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 - tinyglobby: 0.2.15 - optionalDependencies: - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - - vitest@4.0.18(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.30.2): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2) - why-is-node-running: 2.3.0 - optionalDependencies: - jsdom: 25.0.1 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - - webidl-conversions@7.0.0: {} - - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - - whatwg-mimetype@4.0.0: {} - - whatwg-url@14.2.0: - dependencies: - tr46: 5.1.1 - webidl-conversions: 7.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - ws@8.19.0: {} - - xml-name-validator@5.0.0: {} - - xmlchars@2.2.0: {} - - yallist@3.1.1: {} +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + clsx: + specifier: ^2.1.1 + version: 2.1.1 + geist: + specifier: ^1.7.0 + version: 1.7.0(next@15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + next: + specifier: ^15.1.0 + version: 15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: + specifier: ^19.0.0 + version: 19.2.4 + react-dom: + specifier: ^19.0.0 + version: 19.2.4(react@19.2.4) + tailwind-merge: + specifier: ^3.4.0 + version: 3.4.0 + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.1.18 + version: 4.1.18 + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@testing-library/user-event': + specifier: ^14.6.1 + version: 14.6.1(@testing-library/dom@10.4.1) + '@types/react': + specifier: ^19.2.13 + version: 19.2.13 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.13) + '@vitejs/plugin-react': + specifier: ^4.3.4 + version: 4.7.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)) + jsdom: + specifier: '25' + version: 25.0.1 + tailwindcss: + specifier: ^4.1.18 + version: 4.1.18 + typescript: + specifier: ~5.6.2 + version: 5.6.3 + vitest: + specifier: ^4.0.18 + version: 4.0.18(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.30.2) + +packages: + + '@adobe/css-tools@4.4.4': + resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@asamuzakjp/css-color@3.2.0': + resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} + + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@next/env@15.5.12': + resolution: {integrity: sha512-pUvdJN1on574wQHjaBfNGDt9Mz5utDSZFsIIQkMzPgNS8ZvT4H2mwOrOIClwsQOb6EGx5M76/CZr6G8i6pSpLg==} + + '@next/swc-darwin-arm64@15.5.12': + resolution: {integrity: sha512-RnRjBtH8S8eXCpUNkQ+543DUc7ys8y15VxmFU9HRqlo9BG3CcBUiwNtF8SNoi2xvGCVJq1vl2yYq+3oISBS0Zg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.12': + resolution: {integrity: sha512-nqa9/7iQlboF1EFtNhWxQA0rQstmYRSBGxSM6g3GxvxHxcoeqVXfGNr9stJOme674m2V7r4E3+jEhhGvSQhJRA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.12': + resolution: {integrity: sha512-dCzAjqhDHwmoB2M4eYfVKqXs99QdQxNQVpftvP1eGVppamXh/OkDAwV737Zr0KPXEqRUMN4uCjh6mjO+XtF3Mw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.5.12': + resolution: {integrity: sha512-+fpGWvQiITgf7PUtbWY1H7qUSnBZsPPLyyq03QuAKpVoTy/QUx1JptEDTQMVvQhvizCEuNLEeghrQUyXQOekuw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.5.12': + resolution: {integrity: sha512-jSLvgdRRL/hrFAPqEjJf1fFguC719kmcptjNVDJl26BnJIpjL3KH5h6mzR4mAweociLQaqvt4UyzfbFjgAdDcw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.5.12': + resolution: {integrity: sha512-/uaF0WfmYqQgLfPmN6BvULwxY0dufI2mlN2JbOKqqceZh1G4hjREyi7pg03zjfyS6eqNemHAZPSoP84x17vo6w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.5.12': + resolution: {integrity: sha512-xhsL1OvQSfGmlL5RbOmU+FV120urrgFpYLq+6U8C6KIym32gZT6XF/SDE92jKzzlPWskkbjOKCpqk5m4i8PEfg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.12': + resolution: {integrity: sha512-Z1Dh6lhFkxvBDH1FoW6OU/L6prYwPSlwjLiZkExIAh8fbP6iI/M7iGTQAJPYJ9YFlWobCZ1PHbchFhFYb2ADkw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/rollup-android-arm-eabi@4.57.1': + resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.57.1': + resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.57.1': + resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.57.1': + resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.57.1': + resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.57.1': + resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.57.1': + resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.57.1': + resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.57.1': + resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.57.1': + resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.57.1': + resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.57.1': + resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.57.1': + resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.57.1': + resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} + cpu: [x64] + os: [win32] + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.18': + resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.13': + resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} + + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@vitest/expect@4.0.18': + resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + + '@vitest/mocker@4.0.18': + resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.0.18': + resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + + '@vitest/runner@4.0.18': + resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + + '@vitest/snapshot@4.0.18': + resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + + '@vitest/spy@4.0.18': + resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + + '@vitest/utils@4.0.18': + resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} + hasBin: true + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + caniuse-lite@1.0.30001769: + resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + cssstyle@4.6.0: + resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} + engines: {node: '>=18'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.286: + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} + engines: {node: '>=10.13.0'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + geist@1.7.0: + resolution: {integrity: sha512-ZaoiZwkSf0DwwB1ncdLKp+ggAldqxl5L1+SXaNIBGkPAqcu+xjVJLxlf3/S8vLt9UHx1xu5fz3lbzKCj5iOVdQ==} + peerDependencies: + next: '>=13.2.0' + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsdom@25.0.1: + resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + next@15.5.12: + resolution: {integrity: sha512-Fi/wQ4Etlrn60rz78bebG1i1SR20QxvV8tVp6iJspjLUSHcZoeUXCt+vmWoEcza85ElZzExK/jJ/F6SvtGktjA==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + nwsapi@2.2.23: + resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + rollup@4.57.1: + resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + 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 + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + + tldts-core@6.1.86: + resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + + tldts@6.1.86: + resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} + hasBin: true + + tough-cookie@5.1.2: + resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + engines: {node: '>=16'} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.0.18: + resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.18 + '@vitest/browser-preview': 4.0.18 + '@vitest/browser-webdriverio': 4.0.18 + '@vitest/ui': 4.0.18 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + +snapshots: + + '@adobe/css-tools@4.4.4': {} + + '@alloc/quick-lru@5.2.0': {} + + '@asamuzakjp/css-color@3.2.0': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 10.4.3 + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/runtime@7.28.6': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@csstools/color-helpers@5.1.0': {} + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-tokenizer@3.0.4': {} + + '@emnapi/runtime@1.8.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.8.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@next/env@15.5.12': {} + + '@next/swc-darwin-arm64@15.5.12': + optional: true + + '@next/swc-darwin-x64@15.5.12': + optional: true + + '@next/swc-linux-arm64-gnu@15.5.12': + optional: true + + '@next/swc-linux-arm64-musl@15.5.12': + optional: true + + '@next/swc-linux-x64-gnu@15.5.12': + optional: true + + '@next/swc-linux-x64-musl@15.5.12': + optional: true + + '@next/swc-win32-arm64-msvc@15.5.12': + optional: true + + '@next/swc-win32-x64-msvc@15.5.12': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/rollup-android-arm-eabi@4.57.1': + optional: true + + '@rollup/rollup-android-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-x64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.57.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.57.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.57.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.57.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.57.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.57.1': + optional: true + + '@standard-schema/spec@1.1.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.1.18': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.19.0 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.18 + + '@tailwindcss/oxide-android-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide@4.1.18': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + + '@tailwindcss/postcss@4.1.18': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + postcss: 8.5.6 + tailwindcss: 4.1.18 + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.28.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.4.4 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + dependencies: + '@testing-library/dom': 10.4.1 + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/react-dom@19.2.3(@types/react@19.2.13)': + dependencies: + '@types/react': 19.2.13 + + '@types/react@19.2.13': + dependencies: + csstype: 3.2.3 + + '@vitejs/plugin-react@4.7.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@4.0.18': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 + chai: 6.2.2 + tinyrainbow: 3.0.3 + + '@vitest/mocker@4.0.18(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@vitest/spy': 4.0.18 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2) + + '@vitest/pretty-format@4.0.18': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.18': + dependencies: + '@vitest/utils': 4.0.18 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.18': + dependencies: + '@vitest/pretty-format': 4.0.18 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.0.18': {} + + '@vitest/utils@4.0.18': + dependencies: + '@vitest/pretty-format': 4.0.18 + tinyrainbow: 3.0.3 + + agent-base@7.1.4: {} + + ansi-regex@5.0.1: {} + + ansi-styles@5.2.0: {} + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + + baseline-browser-mapping@2.9.19: {} + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001769 + electron-to-chromium: 1.5.286 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + caniuse-lite@1.0.30001769: {} + + chai@6.2.2: {} + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + convert-source-map@2.0.0: {} + + css.escape@1.5.1: {} + + cssstyle@4.6.0: + dependencies: + '@asamuzakjp/css-color': 3.2.0 + rrweb-cssom: 0.8.0 + + csstype@3.2.3: {} + + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js@10.6.0: {} + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.286: {} + + enhanced-resolve@5.19.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@6.0.1: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + + escalade@3.2.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + expect-type@1.3.0: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + geist@1.7.0(next@15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): + dependencies: + next: 15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + indent-string@4.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + jiti@2.6.1: {} + + js-tokens@4.0.0: {} + + jsdom@25.0.1: + dependencies: + cssstyle: 4.6.0 + data-urls: 5.0.0 + decimal.js: 10.6.0 + form-data: 4.0.5 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.23 + parse5: 7.3.0 + rrweb-cssom: 0.7.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.1.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + ws: 8.19.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lz-string@1.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + min-indent@1.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + next@15.5.12(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@next/env': 15.5.12 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001769 + postcss: 8.4.31 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.12 + '@next/swc-darwin-x64': 15.5.12 + '@next/swc-linux-arm64-gnu': 15.5.12 + '@next/swc-linux-arm64-musl': 15.5.12 + '@next/swc-linux-x64-gnu': 15.5.12 + '@next/swc-linux-x64-musl': 15.5.12 + '@next/swc-win32-arm64-msvc': 15.5.12 + '@next/swc-win32-x64-msvc': 15.5.12 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-releases@2.0.27: {} + + nwsapi@2.2.23: {} + + obug@2.1.1: {} + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + punycode@2.3.1: {} + + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react-is@17.0.2: {} + + react-refresh@0.17.0: {} + + react@19.2.4: {} + + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + rollup@4.57.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 + fsevents: 2.3.3 + + rrweb-cssom@0.7.1: {} + + rrweb-cssom@0.8.0: {} + + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.7.4: + optional: true + + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.4): + dependencies: + client-only: 0.0.1 + react: 19.2.4 + optionalDependencies: + '@babel/core': 7.29.0 + + symbol-tree@3.2.4: {} + + tailwind-merge@3.4.0: {} + + tailwindcss@4.1.18: {} + + tapable@2.3.0: {} + + tinybench@2.9.0: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyrainbow@3.0.3: {} + + tldts-core@6.1.86: {} + + tldts@6.1.86: + dependencies: + tldts-core: 6.1.86 + + tough-cookie@5.1.2: + dependencies: + tldts: 6.1.86 + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + tslib@2.8.1: {} + + typescript@5.6.3: {} + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.57.1 + tinyglobby: 0.2.15 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + + vitest@4.0.18(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.30.2): + dependencies: + '@vitest/expect': 4.0.18 + '@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)) + '@vitest/pretty-format': 4.0.18 + '@vitest/runner': 4.0.18 + '@vitest/snapshot': 4.0.18 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2) + why-is-node-running: 2.3.0 + optionalDependencies: + jsdom: 25.0.1 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.19.0: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + + yallist@3.1.1: {} diff --git a/web/postcss.config.mjs b/web/postcss.config.mjs index a34a3d5..a292996 100644 --- a/web/postcss.config.mjs +++ b/web/postcss.config.mjs @@ -1,5 +1,5 @@ -export default { - plugins: { - '@tailwindcss/postcss': {}, - }, -}; +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; diff --git a/web/src/app/WaitlistForm.tsx b/web/src/app/WaitlistForm.tsx index 87ccded..f8afda9 100644 --- a/web/src/app/WaitlistForm.tsx +++ b/web/src/app/WaitlistForm.tsx @@ -1,71 +1,71 @@ -'use client'; - -import { Button, Input } from '@/components/ui'; -import { cn } from '@/lib/cn'; - -const selectClassName = cn( - 'flex h-11 min-h-[44px] w-full rounded-md border border-input bg-transparent px-4 py-3 text-sm', - 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', -); - -export function WaitlistForm() { - return ( -
e.preventDefault()} - > - - - - - - - - - - -

- Te avisamos cuando abramos la beta. Sin spam. -

-

- Consejo: para dudas urgentes (desahucio, amenazas, etc.), busca ayuda - profesional y canales oficiales. -

-
- ); -} +'use client'; + +import { Button, Input } from '@/components/ui'; +import { cn } from '@/lib/cn'; + +const selectClassName = cn( + 'flex h-11 min-h-[44px] w-full rounded-md border border-input bg-transparent px-4 py-3 text-sm', + 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', +); + +export function WaitlistForm() { + return ( +
e.preventDefault()} + > + + + + + + + + + + +

+ Te avisamos cuando abramos la beta. Sin spam. +

+

+ Consejo: para dudas urgentes (desahucio, amenazas, etc.), busca ayuda + profesional y canales oficiales. +

+
+ ); +} diff --git a/web/src/app/chat/route.ts b/web/src/app/chat/route.ts index f849ce1..342ad9b 100644 --- a/web/src/app/chat/route.ts +++ b/web/src/app/chat/route.ts @@ -1,14 +1,14 @@ -import { NextResponse, type NextRequest } from 'next/server'; - -// CHAT_REDIRECT_URL is read at runtime (set in Railway). Fallback: NEXT_PUBLIC_API_URL. -export function GET(request: NextRequest) { - const apiUrl = - process.env.CHAT_REDIRECT_URL ?? process.env.NEXT_PUBLIC_API_URL; - if (apiUrl) { - return NextResponse.redirect(apiUrl, 307); - } - const host = request.headers.get('x-forwarded-host') ?? request.headers.get('host') ?? 'localhost'; - const proto = request.headers.get('x-forwarded-proto') ?? 'https'; - const base = `${proto}://${host}`; - return NextResponse.redirect(new URL('/', base), 307); -} +import { NextResponse, type NextRequest } from 'next/server'; + +// CHAT_REDIRECT_URL is read at runtime (set in Railway). Fallback: NEXT_PUBLIC_API_URL. +export function GET(request: NextRequest) { + const apiUrl = + process.env.CHAT_REDIRECT_URL ?? process.env.NEXT_PUBLIC_API_URL; + if (apiUrl) { + return NextResponse.redirect(apiUrl, 307); + } + const host = request.headers.get('x-forwarded-host') ?? request.headers.get('host') ?? 'localhost'; + const proto = request.headers.get('x-forwarded-proto') ?? 'https'; + const base = `${proto}://${host}`; + return NextResponse.redirect(new URL('/', base), 307); +} diff --git a/web/src/app/layout.tsx b/web/src/app/layout.tsx index e13337c..feb6276 100644 --- a/web/src/app/layout.tsx +++ b/web/src/app/layout.tsx @@ -1,26 +1,26 @@ -import type { Metadata } from 'next'; -import { GeistSans } from 'geist/font/sans'; -import '@/index.css'; - -export const metadata: Metadata = { - title: 'LlarJove — Habitatge, sense perdre\'t', - description: - 'Te guiamos paso a paso para encontrar vivienda en Cataluña y entender ayudas y derechos, con información verificable y con fuentes.', - openGraph: { - title: 'LlarJove — Habitatge, sense perdre\'t', - description: - 'Te guiamos paso a paso para encontrar vivienda en Cataluña y entender ayudas y derechos, con información verificable y con fuentes.', - }, -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - {children} - - ); -} +import type { Metadata } from 'next'; +import { GeistSans } from 'geist/font/sans'; +import '@/index.css'; + +export const metadata: Metadata = { + title: 'LlarJove — Habitatge, sense perdre\'t', + description: + 'Te guiamos paso a paso para encontrar vivienda en Cataluña y entender ayudas y derechos, con información verificable y con fuentes.', + openGraph: { + title: 'LlarJove — Habitatge, sense perdre\'t', + description: + 'Te guiamos paso a paso para encontrar vivienda en Cataluña y entender ayudas y derechos, con información verificable y con fuentes.', + }, +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + {children} + + ); +} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 9700246..37b03c1 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -1,452 +1,452 @@ -import { Badge, Card, Link } from '@/components/ui'; - -const Check = ({ className = 'w-5 h-5' }: { className?: string }) => ( - - - -); - -const Arrow = ({ className = 'w-5 h-5' }: { className?: string }) => ( - - - -); - -function SectionTitle({ - kicker, - title, - subtitle, -}: { - kicker?: string; - title: string; - subtitle?: string; -}) { - return ( -
- {kicker ? ( -

- {kicker} -

- ) : null} -

- {title} -

- {subtitle ? ( -

{subtitle}

- ) : null} -
- ); -} - -function FAQItem({ q, a }: { q: string; a: string }) { - return ( -
- - {q} - - - - -

{a}

-
- ); -} - -import { WaitlistForm } from './WaitlistForm'; - -export default function Page() { - return ( -
- {/* Top bar */} -
-
-
-
- LJ -
-
-

LlarJove

-

- Habitatge clar, amb fonts -

-
-
- - - -
- - Probar el chat - - - Únete a la lista - -
-
-
- - {/* Hero */} -
-
-
-
- Fuentes oficiales + fecha - Privacidad por defecto - Sin burocratés -
- -

- Habitatge, sense perdre't. -

- -

- Te guiamos paso a paso para encontrar vivienda en Cataluña y - entender ayudas y derechos, con información verificable y con - fuentes. -

- -
- - Probar el asistente - - - Únete a la lista - - - Ver cómo funciona{' '} - - - - -
- -

- Información orientativa; no es asesoramiento legal. Para - decisiones importantes, verifica en la fuente oficial. -

-
- -
- {/* Chat mockup: colores 100% del tema (secondary=usuario, accent=LlarJove, primary=énfasis) */} - -

Ejemplo

-
-
-

-

- "Tengo 24 años, busco piso en Barcelona. ¿Qué ayudas y - trámites necesito?" -

-
-
-

LlarJove

-
    -
  • - Opciones de - ayuda al alquiler (según requisitos) -
  • -
  • - Checklist de - documentación y pasos -
  • -
  • - Fuentes - citadas y fecha de actualización -
  • -
-

- "Fuente: Agència de l'Habitatge (oficial) · - Actualizado: DD/MM/AAAA" -

-
-
-
- -
-
-
-
-
- - {/* How it works */} -
- - -
- -

Paso 1

-

- Cuéntanos tu situación -

-

- Zona, presupuesto, si estudias o trabajas, y qué necesitas. -

-
- -

Paso 2

-

- Te damos opciones y pasos -

-

- Ayudas, recursos locales y trámites en un plan accionable. -

-
- -

Paso 3

-

- Te mostramos fuentes -

-

- Marcamos si la fuente es oficial y la fecha de la info. -

-
-
-
- - {/* Benefits */} -
- -
- {[ - { - t: 'Ajudes al lloguer (explicadas claro)', - d: 'Qué existe, cómo encaja contigo y qué preparar.', - }, - { - t: 'Derechos básicos', - d: 'Fianza, contrato, subidas, reparaciones: lo esencial sin drama.', - }, - { - t: 'Trámites y documentación', - d: 'Listas y pasos para no quedarte a medias.', - }, - { - t: 'Recursos locales', - d: 'Oficines d\'habitatge, bolsas y servicios por zona.', - }, - { - t: 'Plantillas y checklists', - d: 'Mensajes al propietario, lista de visita, documentos.', - }, - { - t: 'Privacidad por defecto', - d: 'Minimizamos datos y te damos control.', - }, - ].map((x) => ( - -

{x.t}

-

{x.d}

-
- ))} -
-
- - {/* Sources */} -
- -
- -

✅ Oficial

-

- Generalitat / Agència de l'Habitatge, ajuntaments, oficinas - de vivienda, normativa oficial. -

-
    -
  • - Requisitos y plazos -
  • -
  • - Procedimientos y formularios -
  • -
  • - Enlaces directos -
  • -
-
- -

ℹ️ Orientativo

-

- Entidades y guías prácticas reputadas. Útil para contexto, pero - no sustituye lo oficial. -

-
    -
  • - Consejos y acompañamiento -
  • -
  • - Recursos comunitarios -
  • -
  • - Señalamos posibles sesgos -
  • -
-
-
-

- Siempre marcamos si una fuente es oficial y la fecha. -

-
- - {/* Privacy */} -
- -
- -

Minimización

-

- Solo preguntamos lo necesario para darte pasos útiles. -

-
- -

Sin cuenta (opcional)

-

- Puedes probarlo sin registrarte; la lista es solo para avisarte. -

-
- -

Borrado fácil

-

- Control claro sobre lo que guardas y lo que no. -

-
-
-
- - {/* FAQ */} -
- -
- - - - - - -
-
- - {/* Waitlist */} -
- - - - - -
- - {/* Footer */} -
-
-

- © {new Date().getFullYear()} LlarJove -

-
- - Fuentes - - - Privacidad - - - Contacto - -
-
-
-
- ); -} +import { Badge, Card, Link } from '@/components/ui'; + +const Check = ({ className = 'w-5 h-5' }: { className?: string }) => ( + + + +); + +const Arrow = ({ className = 'w-5 h-5' }: { className?: string }) => ( + + + +); + +function SectionTitle({ + kicker, + title, + subtitle, +}: { + kicker?: string; + title: string; + subtitle?: string; +}) { + return ( +
+ {kicker ? ( +

+ {kicker} +

+ ) : null} +

+ {title} +

+ {subtitle ? ( +

{subtitle}

+ ) : null} +
+ ); +} + +function FAQItem({ q, a }: { q: string; a: string }) { + return ( +
+ + {q} + + + + +

{a}

+
+ ); +} + +import { WaitlistForm } from './WaitlistForm'; + +export default function Page() { + return ( +
+ {/* Top bar */} +
+
+
+
+ LJ +
+
+

LlarJove

+

+ Habitatge clar, amb fonts +

+
+
+ + + +
+ + Probar el chat + + + Únete a la lista + +
+
+
+ + {/* Hero */} +
+
+
+
+ Fuentes oficiales + fecha + Privacidad por defecto + Sin burocratés +
+ +

+ Habitatge, sense perdre't. +

+ +

+ Te guiamos paso a paso para encontrar vivienda en Cataluña y + entender ayudas y derechos, con información verificable y con + fuentes. +

+ +
+ + Probar el asistente + + + Únete a la lista + + + Ver cómo funciona{' '} + + + + +
+ +

+ Información orientativa; no es asesoramiento legal. Para + decisiones importantes, verifica en la fuente oficial. +

+
+ +
+ {/* Chat mockup: colores 100% del tema (secondary=usuario, accent=LlarJove, primary=énfasis) */} + +

Ejemplo

+
+
+

+

+ "Tengo 24 años, busco piso en Barcelona. ¿Qué ayudas y + trámites necesito?" +

+
+
+

LlarJove

+
    +
  • + Opciones de + ayuda al alquiler (según requisitos) +
  • +
  • + Checklist de + documentación y pasos +
  • +
  • + Fuentes + citadas y fecha de actualización +
  • +
+

+ "Fuente: Agència de l'Habitatge (oficial) · + Actualizado: DD/MM/AAAA" +

+
+
+
+ +
+
+
+
+
+ + {/* How it works */} +
+ + +
+ +

Paso 1

+

+ Cuéntanos tu situación +

+

+ Zona, presupuesto, si estudias o trabajas, y qué necesitas. +

+
+ +

Paso 2

+

+ Te damos opciones y pasos +

+

+ Ayudas, recursos locales y trámites en un plan accionable. +

+
+ +

Paso 3

+

+ Te mostramos fuentes +

+

+ Marcamos si la fuente es oficial y la fecha de la info. +

+
+
+
+ + {/* Benefits */} +
+ +
+ {[ + { + t: 'Ajudes al lloguer (explicadas claro)', + d: 'Qué existe, cómo encaja contigo y qué preparar.', + }, + { + t: 'Derechos básicos', + d: 'Fianza, contrato, subidas, reparaciones: lo esencial sin drama.', + }, + { + t: 'Trámites y documentación', + d: 'Listas y pasos para no quedarte a medias.', + }, + { + t: 'Recursos locales', + d: 'Oficines d\'habitatge, bolsas y servicios por zona.', + }, + { + t: 'Plantillas y checklists', + d: 'Mensajes al propietario, lista de visita, documentos.', + }, + { + t: 'Privacidad por defecto', + d: 'Minimizamos datos y te damos control.', + }, + ].map((x) => ( + +

{x.t}

+

{x.d}

+
+ ))} +
+
+ + {/* Sources */} +
+ +
+ +

✅ Oficial

+

+ Generalitat / Agència de l'Habitatge, ajuntaments, oficinas + de vivienda, normativa oficial. +

+
    +
  • + Requisitos y plazos +
  • +
  • + Procedimientos y formularios +
  • +
  • + Enlaces directos +
  • +
+
+ +

ℹ️ Orientativo

+

+ Entidades y guías prácticas reputadas. Útil para contexto, pero + no sustituye lo oficial. +

+
    +
  • + Consejos y acompañamiento +
  • +
  • + Recursos comunitarios +
  • +
  • + Señalamos posibles sesgos +
  • +
+
+
+

+ Siempre marcamos si una fuente es oficial y la fecha. +

+
+ + {/* Privacy */} +
+ +
+ +

Minimización

+

+ Solo preguntamos lo necesario para darte pasos útiles. +

+
+ +

Sin cuenta (opcional)

+

+ Puedes probarlo sin registrarte; la lista es solo para avisarte. +

+
+ +

Borrado fácil

+

+ Control claro sobre lo que guardas y lo que no. +

+
+
+
+ + {/* FAQ */} +
+ +
+ + + + + + +
+
+ + {/* Waitlist */} +
+ + + + + +
+ + {/* Footer */} + +
+ ); +}