diff --git a/.gitignore b/.gitignore index ea3e830..c42bf1a 100644 --- a/.gitignore +++ b/.gitignore @@ -104,11 +104,10 @@ docker-compose.override.yml .claude/ .gemini/ .cursor/ -CLAUDE.md -AGENTS.md QWEN.md -claude.md -agents.md +AGENTS.md +# === Backups locais === +/backup/ # === Backups e Temporários === *.bak diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0ade71b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,318 @@ +# CLAUDE.md - OpenMonetis + +> Self-hosted personal finance app (Next.js 16, React 19, PostgreSQL, Drizzle ORM, Better Auth, Tailwind 4, shadcn/ui). +> Portuguese UI, English folders/imports. Linter: Biome 2.x. Package manager: pnpm. + +## Related Projects + +- **OpenMonetis Companion** (`~/github/openmonetis-companion`): Android app que captura notificacoes de apps bancarios e envia para o OpenMonetis via API. Os itens chegam na feature `inbox` para revisao. + +--- + +## Critical Rules + +1. **Sempre filtrar por `userId`** em queries. +2. **Usar `getAdminPayerId(userId)`** de `src/shared/lib/payers/get-admin-id.ts` ao inves de JOIN com `payers` para descobrir o admin. +3. **Periods** usam formato `YYYY-MM` (ex: `"2025-11"`). Utils em `src/shared/utils/period/`. +4. **Moeda**: R$ com 2 decimais. DB: `numeric(12, 2)`. Utils em `src/shared/utils/currency.ts`. +5. **Revalidation**: usar `revalidateForEntity("entity")` de `src/shared/lib/actions/helpers.ts` apos mutations. +6. **Versionamento**: registrar mudancas no `CHANGELOG.md` seguindo Keep a Changelog. +7. **Comunicacao**: responder em portugues clara e direta com o time. + +--- + +## Architecture + +### Feature-First + +- `src/app/`: roteamento, layouts, loading states e paginas finas +- `src/features/`: codigo de dominio por feature +- `src/shared/`: tudo que e genuinamente reutilizado entre features +- `src/db/`: schema do banco + +### Regra Feature vs Shared + +Use esta pergunta: + +> Se eu deletar esta feature, este arquivo deveria sumir junto? + +- Sim: vai para `src/features//` +- Nao: vai para `src/shared/` + +### Features nao importam outras features + +Se um contrato cruza dominios, ele deve morar em `src/shared/`. + +Exemplos comuns: + +- auth: `src/shared/lib/auth/*` +- db: `src/shared/lib/db.ts` +- revalidation helpers: `src/shared/lib/actions/*` +- payers cross-domain helpers: `src/shared/lib/payers/*` +- period/currency/date: `src/shared/utils/*` +- shadcn/ui: `src/shared/components/ui/*` + +--- + +## Directory Structure + +```text +src/ +├── app/ +│ ├── (auth)/ +│ │ ├── login/page.tsx +│ │ └── signup/page.tsx +│ ├── (dashboard)/ +│ │ ├── dashboard/ +│ │ ├── transactions/ +│ │ ├── cards/ +│ │ │ └── [cardId]/invoice/ +│ │ ├── accounts/ +│ │ │ └── [accountId]/statement/ +│ │ ├── categories/ +│ │ │ ├── [categoryId]/ +│ │ │ └── history/ +│ │ ├── budgets/ +│ │ ├── payers/ +│ │ │ └── [payerId]/ +│ │ ├── notes/ +│ │ ├── insights/ +│ │ ├── calendar/ +│ │ ├── inbox/ +│ │ ├── changelog/ +│ │ ├── reports/ +│ │ │ ├── category-trends/ +│ │ │ ├── card-usage/ +│ │ │ ├── installment-analysis/ +│ │ │ └── establishments/ +│ │ └── settings/ +│ ├── (landing-page)/ +│ ├── api/ +│ ├── globals.css +│ └── layout.tsx +├── features/ +│ ├── auth/ +│ ├── landing/ +│ ├── dashboard/ +│ ├── transactions/ +│ ├── cards/ +│ ├── invoices/ +│ ├── accounts/ +│ ├── categories/ +│ ├── budgets/ +│ ├── payers/ +│ ├── notes/ +│ ├── insights/ +│ ├── calendar/ +│ ├── inbox/ +│ ├── reports/ +│ └── settings/ +├── shared/ +│ ├── components/ +│ │ ├── ui/ +│ │ ├── navigation/ +│ │ ├── providers/ +│ │ ├── month-picker/ +│ │ ├── logo-picker/ +│ │ ├── calculator/ +│ │ ├── entity-avatar/ +│ │ └── skeletons/ +│ ├── hooks/ +│ ├── lib/ +│ │ ├── actions/ +│ │ ├── auth/ +│ │ ├── accounts/ +│ │ ├── cards/ +│ │ ├── calculator/ +│ │ ├── categories/ +│ │ ├── email/ +│ │ ├── installments/ +│ │ ├── invoices/ +│ │ ├── logo/ +│ │ ├── payers/ +│ │ ├── schemas/ +│ │ ├── transfers/ +│ │ ├── types/ +│ │ └── db.ts +│ └── utils/ +│ ├── period/ +│ ├── currency.ts +│ ├── date.ts +│ ├── financial-dates.ts +│ ├── percentage.ts +│ ├── category-colors.ts +│ ├── calendar.ts +│ ├── math.ts +│ ├── number.ts +│ ├── string.ts +│ ├── initials.ts +│ ├── icons.tsx +│ ├── export-branding.ts +│ ├── ui.ts +│ └── calculator.ts +└── db/ + └── schema.ts +``` + +--- + +## Import Patterns + +### Preferidos + +```ts +import { getUser } from "@/shared/lib/auth/server"; +import { revalidateForEntity } from "@/shared/lib/actions/helpers"; +import { parsePeriodParam } from "@/shared/utils/period"; +import { TransactionsPage } from "@/features/transactions/components/page/transactions-page"; +import { fetchLancamentos } from "@/features/transactions/queries"; +``` + +### Evitar + +```ts +import { Something } from "@/components/..."; +import { Something } from "@/lib/..."; +import { something } from "@/app/(dashboard)/..."; +``` + +--- + +## App Router Pattern + +Paginas em `src/app/` devem ser finas: + +```ts +import { getUser } from "@/shared/lib/auth/server"; +import { TransactionsPage } from "@/features/transactions/components/page/transactions-page"; +import { fetchLancamentos } from "@/features/transactions/queries"; + +export default async function Page() { + const user = await getUser(); + const data = await fetchLancamentos([/* filters */]); + return ; +} +``` + +Layouts, `loading.tsx` e metadata continuam em `src/app/`. + +--- + +## Naming + +### Routes / folders + +| Portugues | English | +|---|---| +| `lancamentos` | `transactions` | +| `cartoes` | `cards` | +| `contas` | `accounts` | +| `categorias` | `categories` | +| `orcamentos` | `budgets` | +| `pagadores` | `payers` | +| `anotacoes` | `notes` | +| `calendario` | `calendar` | +| `ajustes` | `settings` | +| `pre-lancamentos` | `inbox` | +| `relatorios/tendencias` | `reports/category-trends` | +| `relatorios/uso-cartoes` | `reports/card-usage` | +| `relatorios/analise-parcelas` | `reports/installment-analysis` | +| `relatorios/estabelecimentos` | `reports/establishments` | +| `contas/[contaId]/extrato` | `accounts/[accountId]/statement` | +| `cartoes/[cartaoId]/fatura` | `cards/[cardId]/invoice` | +| `categorias/historico` | `categories/history` | +| `changelog` | `settings/changelog` | + +### Files + +- preferir `kebab-case` +- preferir nomes em ingles +- manter nomes internos de tipos/funcoes somente quando a troca aumentar risco sem ganho real + +--- + +## Commands + +```bash +pnpm run dev +pnpm run build +pnpm run lint +pnpm run lint:fix +pnpm exec next typegen +pnpm exec tsc --noEmit +pnpm run db:generate +pnpm run db:push +pnpm run db:studio +pnpm run docker:up:db +``` + +--- + +## Revalidation + +Arquivo: `src/shared/lib/actions/helpers.ts` + +- atualizar sempre os paths em ingles +- lembrar de manter a tag `"dashboard"` para invalidacoes financeiras + +--- + +## Auth + +- `getUser()` / `getUserId()` em `src/shared/lib/auth/server.ts` +- sessao deduplicada por request com `React.cache()` + +--- + +## Dashboard Fetcher + +Padrao recomendado: + +```ts +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; + +export async function fetchData(userId: string, period: string) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) return []; + + return db.query.transactions.findMany({ + where: /* sempre com userId + adminPayerId + period */, + }); +} +``` + +--- + +## New Feature Checklist + +1. Criar a rota fina em `src/app/(dashboard)//page.tsx` +2. Criar a feature em `src/features//` +3. Separar: + - `components/` + - `queries.ts` + - `actions.ts` + - `types.ts` ou `schemas.ts` quando fizer sentido +4. Extrair para `src/shared/` tudo que for reutilizavel +5. Atualizar navegacao e `revalidateForEntity()` se a feature tiver CRUD +6. Rodar: + - `pnpm exec next typegen` + - `pnpm exec tsc --noEmit` + - `pnpm run lint` + +--- + +## Response Style + +Quando o time pedir avaliacao de plano ou feature: + +1. Responder em portugues simples. +2. Listar 3-5 problemas principais. +3. Fechar com decisao pratica: + - aprova agora + - nao aprova agora + - o que ajustar antes de comecar codigo + +Exemplo: + +- "Nao aprovaria para comecar codigo imediatamente." +- "Primeiro ajustaria o doc com estes 5 pontos." diff --git a/README.md b/README.md index 4a46049..ee9b5e9 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,9 @@ Projeto pessoal de gestão financeira. Self-hosted, manual e open source.

-> **📢 Este projeto foi renomeado de OpenSheets para OpenMonetis.** Se você conhecia o projeto pelo nome anterior, é o mesmo — só mudou o nome! - > **⚠️ Não há versão online hospedada.** Você precisa clonar o repositório e rodar localmente ou no seu próprio servidor. +[![Version](https://img.shields.io/badge/version-2.0.0-blue?style=flat-square)](CHANGELOG.md) [![Next.js](https://img.shields.io/badge/Next.js-black?style=flat-square&logo=next.js)](https://nextjs.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/) [![PostgreSQL](https://img.shields.io/badge/PostgreSQL-blue?style=flat-square&logo=postgresql)](https://www.postgresql.org/) @@ -29,7 +28,8 @@ ## 📖 Índice - [Sobre o Projeto](#-sobre-o-projeto) -- [Início Rápido](#-início-rápido) +- [Instalação via Script](#-instalação-via-script) +- [Início Rápido (manual)](#-início-rápido) - [Scripts Disponíveis](#-scripts-disponíveis) - [Docker](#-docker) - [Variáveis de Ambiente](#-variáveis-de-ambiente) @@ -60,7 +60,7 @@ A ideia é simples: ter um lugar onde consigo ver todas as minhas contas, cartõ 💰 **Contas e transações** — Contas bancárias, cartões, dinheiro. Receitas, despesas e transferências. Categorização, extratos detalhados e importação em massa. -📊 **Dashboard e relatórios** — 20+ widgets interativos, gráficos de evolução, comparativos por categoria, tendências, uso de cartões, top estabelecimentos. Exportação em PDF e Excel. +📊 **Dashboard e relatórios** — Widgets interativos de métricas, gráficos de evolução, comparativos por categoria, tendências, uso de cartões, top estabelecimentos. Exportação em PDF e Excel. 💳 **Faturas de cartão** — Acompanhe faturas por período, controle limites e vencimentos. @@ -78,13 +78,13 @@ A ideia é simples: ter um lugar onde consigo ver todas as minhas contas, cartõ 📲 **OpenMonetis Companion** — App Android que captura notificações bancárias (Nubank, Itaú, Bradesco, Inter, C6 e outros) e envia como pré-lançamentos para revisão. [Repositório](https://github.com/felipegcoutinho/openmonetis-companion). -⚙️ **Personalização** — Tema dark/light, modo privacidade e preferências por usuário. +⚙️ **Personalização** — Tema dark/light e modo privacidade. ### Stack técnica - **Next.js** (App Router, Turbopack) + **React** + **TypeScript** - **PostgreSQL** + **Drizzle ORM** -- **Better Auth** (email/senha + OAuth) +- **Better Auth** (email/senha, OAuth, Passkeys/WebAuthn) - **shadcn/ui** (Radix UI) + **Tailwind CSS** - **Docker** (multi-stage build) - **Biome** (linting + formatting) @@ -92,7 +92,30 @@ A ideia é simples: ter um lugar onde consigo ver todas as minhas contas, cartõ --- -## 🚀 Início Rápido +## ⚡ Instalação via Script + +A forma mais rápida de instalar. O script verifica dependências, configura o `.env` interativamente e sobe o banco automaticamente. + +**Pré-requisito:** Node.js 22+ + +```bash +# Mac / Linux / WSL +curl -fsSL https://raw.githubusercontent.com/felipegcoutinho/openmonetis/main/setup.mjs -o setup.mjs && node setup.mjs + +# Windows (PowerShell) +curl -o setup.mjs https://raw.githubusercontent.com/felipegcoutinho/openmonetis/main/setup.mjs ; node setup.mjs +``` + +O script irá: +- Verificar Node, pnpm, Git e Docker +- Perguntar se quer banco local (Docker) ou remoto (Supabase, Neon, etc.) +- Gerar o `BETTER_AUTH_SECRET` automaticamente +- Configurar opcionais: Google OAuth, e-mail, IA, domínio público +- Clonar o repositório, instalar dependências e aplicar o schema + +--- + +## 🚀 Início Rápido (manual) ### Pré-requisitos @@ -251,32 +274,49 @@ OPENROUTER_API_KEY= ## 🏗️ Arquitetura +O projeto segue arquitetura **feature-first** dentro de `src/`: + ``` openmonetis/ -├── app/ # Next.js App Router -│ ├── api/ # API Routes (auth, health, inbox) -│ ├── (auth)/ # Login e cadastro -│ ├── (dashboard)/ # Rotas protegidas -│ └── (landing-page)/ # Página inicial pública +├── src/ +│ ├── app/ # Next.js App Router (rotas finas) +│ │ ├── api/ # API Routes (auth, health, inbox) +│ │ ├── (auth)/ # Login e cadastro +│ │ ├── (dashboard)/ # Rotas protegidas (transactions, cards, accounts, etc.) +│ │ └── (landing-page)/ # Página inicial pública +│ │ +│ ├── features/ # Código de domínio por feature +│ │ ├── dashboard/ # Widgets, queries e métricas +│ │ ├── transactions/ # Lançamentos, ações em lote, exportação +│ │ ├── cards/ # Cartões de crédito +│ │ ├── invoices/ # Faturas +│ │ ├── accounts/ # Contas bancárias +│ │ ├── categories/ # Categorias e histórico +│ │ ├── budgets/ # Orçamentos +│ │ ├── payers/ # Pagadores e compartilhamento +│ │ ├── inbox/ # Pré-lançamentos do Companion +│ │ ├── insights/ # Análises com IA +│ │ ├── reports/ # Relatórios e exportações +│ │ ├── notes/ # Anotações +│ │ ├── calendar/ # Calendário financeiro +│ │ ├── settings/ # Ajustes do usuário +│ │ ├── landing/ # Landing page +│ │ └── auth/ # Formulários de autenticação +│ │ +│ ├── shared/ # Código reutilizado entre features +│ │ ├── components/ # UI compartilhada (shadcn/ui, navigation, skeletons...) +│ │ ├── hooks/ # React hooks globais +│ │ ├── lib/ # Helpers de domínio (auth, db, payers, schemas, email...) +│ │ └── utils/ # Utilitários (currency, date, period, math, string...) +│ │ +│ └── db/ +│ └── schema.ts # Drizzle schema (fonte única de verdade) │ -├── components/ # React Components (~200 arquivos) -│ ├── ui/ # shadcn/ui (40+ componentes) -│ ├── dashboard/ # Widgets do dashboard (20+) -│ └── [feature]/ # Componentes por feature -│ -├── lib/ # Lógica de negócio -│ ├── auth/ # Auth helpers -│ ├── dashboard/ # Fetchers do dashboard -│ ├── actions/ # Server Actions helpers -│ ├── schemas/ # Zod schemas -│ └── utils/ # Currency, date, period utils -│ -├── db/schema.ts # Drizzle schema -├── hooks/ # React hooks customizados -├── public/ # Assets estáticos -├── scripts/ # Scripts utilitários -├── Dockerfile # Multi-stage build -├── docker-compose.yml # Orquestração +├── public/ # Assets estáticos (imagens, logos, fontes) +├── drizzle/ # Migrations geradas +├── scripts/ # Scripts utilitários (migrations, dev) +├── Dockerfile # Multi-stage build (~200MB, non-root) +├── docker-compose.yml # Orquestração app + PostgreSQL └── proxy.ts # Middleware (auth + multi-domínio) ``` @@ -291,7 +331,7 @@ openmonetis/ 5. **Push:** `git push origin feature/minha-feature` 6. Abra um **Pull Request** -Use TypeScript, commits semânticos e documente features novas. +Antes de começar, leia o [`CLAUDE.md`](CLAUDE.md) — ele documenta a arquitetura, convenções de nomenclatura, regras de queries e o checklist para novas features. Use TypeScript, commits semânticos e mantenha o `CHANGELOG.md` atualizado. --- diff --git a/biome.json b/biome.json index a10f1ba..964a8c5 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.6/schema.json", + "$schema": "https://biomejs.dev/schemas/2.4.7/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/next.config.ts b/next.config.ts index f360909..ca11612 100644 --- a/next.config.ts +++ b/next.config.ts @@ -10,9 +10,6 @@ const nextConfig: NextConfig = { turbopackFileSystemCacheForDev: true, }, reactCompiler: true, - typescript: { - ignoreBuildErrors: true, - }, images: { remotePatterns: [new URL("https://lh3.googleusercontent.com/**")], }, diff --git a/package.json b/package.json index 71cc313..0ab7e7a 100644 --- a/package.json +++ b/package.json @@ -24,17 +24,18 @@ "docker:logs:app": "docker compose logs -f app", "docker:logs:db": "docker compose logs -f db", "docker:restart": "docker compose restart", - "docker:rebuild": "docker compose up --build --force-recreate" + "docker:rebuild": "docker compose up --build --force-recreate", + "backup": "bash scripts/backup.sh" }, "dependencies": { - "@ai-sdk/anthropic": "^3.0.60", + "@ai-sdk/anthropic": "^3.0.62", "@ai-sdk/google": "^3.0.51", - "@ai-sdk/openai": "^3.0.45", + "@ai-sdk/openai": "^3.0.46", "@better-auth/passkey": "^1.5.5", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@openrouter/ai-sdk-provider": "^2.3.1", + "@openrouter/ai-sdk-provider": "^2.3.3", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-avatar": "1.1.11", "@radix-ui/react-checkbox": "1.3.3", @@ -66,9 +67,9 @@ "cmdk": "^1.1.1", "date-fns": "^4.1.0", "drizzle-orm": "0.45.1", - "jspdf": "^4.2.0", + "jspdf": "^4.2.1", "jspdf-autotable": "^5.0.7", - "next": "16.1.6", + "next": "16.1.7", "next-themes": "0.4.6", "pg": "8.20.0", "radix-ui": "^1.4.3", @@ -76,7 +77,7 @@ "react-day-picker": "^9.14.0", "react-dom": "19.2.4", "recharts": "3.8.0", - "resend": "^6.9.3", + "resend": "^6.9.4", "sonner": "2.0.7", "tailwind-merge": "3.5.0", "vaul": "1.1.2", @@ -84,15 +85,15 @@ "zod": "4.3.6" }, "devDependencies": { - "@biomejs/biome": "2.4.7", - "@tailwindcss/postcss": "4.2.1", + "@biomejs/biome": "2.4.8", + "@tailwindcss/postcss": "4.2.2", "@types/canvas-confetti": "^1.9.0", "@types/node": "25.5.0", "@types/pg": "^8.18.0", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "dotenv": "^17.3.1", - "drizzle-kit": "0.31.9", + "drizzle-kit": "0.31.10", "tailwindcss": "4.2.1", "tsx": "4.21.0", "typescript": "5.9.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d6bbbd..2cab76f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,17 +9,17 @@ importers: .: dependencies: '@ai-sdk/anthropic': - specifier: ^3.0.60 - version: 3.0.60(zod@4.3.6) + specifier: ^3.0.62 + version: 3.0.62(zod@4.3.6) '@ai-sdk/google': specifier: ^3.0.51 version: 3.0.51(zod@4.3.6) '@ai-sdk/openai': - specifier: ^3.0.45 - version: 3.0.45(zod@4.3.6) + specifier: ^3.0.46 + version: 3.0.46(zod@4.3.6) '@better-auth/passkey': specifier: ^1.5.5 - version: 1.5.5(c3ea9172df57720a1551ed5bee07c69e) + version: 1.5.5(933ec2e58dee4f4ee115209e94e4bc6e) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -30,8 +30,8 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.4) '@openrouter/ai-sdk-provider': - specifier: ^2.3.1 - version: 2.3.1(ai@6.0.127(zod@4.3.6))(zod@4.3.6) + specifier: ^2.3.3 + version: 2.3.3(ai@6.0.129(zod@4.3.6))(zod@4.3.6) '@radix-ui/react-alert-dialog': specifier: 1.1.15 version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -97,16 +97,16 @@ importers: version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@vercel/analytics': specifier: ^2.0.1 - version: 2.0.1(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + version: 2.0.1(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) '@vercel/speed-insights': specifier: ^2.0.0 - version: 2.0.0(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + version: 2.0.0(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) ai: specifier: ^6.0.127 - version: 6.0.127(zod@4.3.6) + version: 6.0.129(zod@4.3.6) better-auth: specifier: 1.5.5 - version: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) canvas-confetti: specifier: ^1.9.4 version: 1.9.4 @@ -126,14 +126,14 @@ importers: specifier: 0.45.1 version: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) jspdf: - specifier: ^4.2.0 - version: 4.2.0 + specifier: ^4.2.1 + version: 4.2.1 jspdf-autotable: specifier: ^5.0.7 - version: 5.0.7(jspdf@4.2.0) + version: 5.0.7(jspdf@4.2.1) next: - specifier: 16.1.6 - version: 16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 16.1.7 + version: 16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -156,8 +156,8 @@ importers: specifier: 3.8.0 version: 3.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@16.13.1)(react@19.2.4)(redux@5.0.1) resend: - specifier: ^6.9.3 - version: 6.9.3 + specifier: ^6.9.4 + version: 6.9.4 sonner: specifier: 2.0.7 version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -175,11 +175,11 @@ importers: version: 4.3.6 devDependencies: '@biomejs/biome': - specifier: 2.4.7 - version: 2.4.7 + specifier: 2.4.8 + version: 2.4.8 '@tailwindcss/postcss': - specifier: 4.2.1 - version: 4.2.1 + specifier: 4.2.2 + version: 4.2.2 '@types/canvas-confetti': specifier: ^1.9.0 version: 1.9.0 @@ -199,8 +199,8 @@ importers: specifier: ^17.3.1 version: 17.3.1 drizzle-kit: - specifier: 0.31.9 - version: 0.31.9 + specifier: 0.31.10 + version: 0.31.10 tailwindcss: specifier: 4.2.1 version: 4.2.1 @@ -213,14 +213,14 @@ importers: packages: - '@ai-sdk/anthropic@3.0.60': - resolution: {integrity: sha512-CoSexBeEEkdMVxUbikH4mqIzC3hhxZr2TcisaCmVqozsh+cNmMa0d3J2wJxDw2onBQU33t3YGW1n/RhN83Yk4g==} + '@ai-sdk/anthropic@3.0.62': + resolution: {integrity: sha512-CkShXR8tmNO7QQnvpKbSMe2Vr1zUUcpqlp69iR+DYrbHm+tDJO9u6zZsjEHjcoRU9/e9z++p0W6NiuLC3aZ4Bg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@3.0.73': - resolution: {integrity: sha512-i8eSbEjmYSb8SPUW28DGRKjvxrzI4RVauISvFfbQUlNf4a4tu6gMXmuGcOZWhs1AvAIswP1nPFTltmJXrxPFcA==} + '@ai-sdk/gateway@3.0.75': + resolution: {integrity: sha512-7Hwa0VdH+l85NFS7zqZhRRaiwZMStDxEwUoTPxPNEH6V0Vgw9wi9OGopIsYdywmfSOPfSAsPL8XXPAuaSLGchw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -231,8 +231,8 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@3.0.45': - resolution: {integrity: sha512-bHOw3E73pxo4D/dZUXk7zwmlofq2nURYlK1dSAy/CI+t6btVhr/BXbElAR7yst6P8Ukqy5GfFlFfsru5p6YSig==} + '@ai-sdk/openai@3.0.46': + resolution: {integrity: sha512-8grBb4sAMU0MAC6uOOD/wP/+SyX/3MMS/Lf+ToGgeUzoF9oWU9dWBLkvgjXpn7Ro81bPDeycW2GCCT63V/Vnvg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -345,59 +345,59 @@ packages: '@better-fetch/fetch@1.1.21': resolution: {integrity: sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==} - '@biomejs/biome@2.4.7': - resolution: {integrity: sha512-vXrgcmNGZ4lpdwZSpMf1hWw1aWS6B+SyeSYKTLrNsiUsAdSRN0J4d/7mF3ogJFbIwFFSOL3wT92Zzxia/d5/ng==} + '@biomejs/biome@2.4.8': + resolution: {integrity: sha512-ponn0oKOky1oRXBV+rlSaUlixUxf1aZvWC19Z41zBfUOUesthrQqL3OtiAlSB1EjFjyWpn98Q64DHelhA6jNlA==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.4.7': - resolution: {integrity: sha512-Oo0cF5mHzmvDmTXw8XSjhCia8K6YrZnk7aCS54+/HxyMdZMruMO3nfpDsrlar/EQWe41r1qrwKiCa2QDYHDzWA==} + '@biomejs/cli-darwin-arm64@2.4.8': + resolution: {integrity: sha512-ARx0tECE8I7S2C2yjnWYLNbBdDoPdq3oyNLhMglmuctThwUsuzFWRKrHmIGwIRWKz0Mat9DuzLEDp52hGnrxGQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.4.7': - resolution: {integrity: sha512-I+cOG3sd/7HdFtvDSnF9QQPrWguUH7zrkIMMykM3PtfWU9soTcS2yRb9Myq6MHmzbeCT08D1UmY+BaiMl5CcoQ==} + '@biomejs/cli-darwin-x64@2.4.8': + resolution: {integrity: sha512-Jg9/PsB9vDCJlANE8uhG7qDhb5w0Ix69D7XIIc8IfZPUoiPrbLm33k2Ig3NOJ/7nb3UbesFz3D1aDKm9DvzjhQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.4.7': - resolution: {integrity: sha512-I2NvM9KPb09jWml93O2/5WMfNR7Lee5Latag1JThDRMURVhPX74p9UDnyTw3Ae6cE1DgXfw7sqQgX7rkvpc0vw==} + '@biomejs/cli-linux-arm64-musl@2.4.8': + resolution: {integrity: sha512-Zo9OhBQDJ3IBGPlqHiTISloo5H0+FBIpemqIJdW/0edJ+gEcLR+MZeZozcUyz3o1nXkVA7++DdRKQT0599j9jA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [musl] - '@biomejs/cli-linux-arm64@2.4.7': - resolution: {integrity: sha512-om6FugwmibzfP/6ALj5WRDVSND4H2G9X0nkI1HZpp2ySf9lW2j0X68oQSaHEnls6666oy4KDsc5RFjT4m0kV0w==} + '@biomejs/cli-linux-arm64@2.4.8': + resolution: {integrity: sha512-5CdrsJct76XG2hpKFwXnEtlT1p+4g4yV+XvvwBpzKsTNLO9c6iLlAxwcae2BJ7ekPGWjNGw9j09T5KGPKKxQig==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [glibc] - '@biomejs/cli-linux-x64-musl@2.4.7': - resolution: {integrity: sha512-00kx4YrBMU8374zd2wHuRV5wseh0rom5HqRND+vDldJPrWwQw+mzd/d8byI9hPx926CG+vWzq6AeiT7Yi5y59g==} + '@biomejs/cli-linux-x64-musl@2.4.8': + resolution: {integrity: sha512-Gi8quv8MEuDdKaPFtS2XjEnMqODPsRg6POT6KhoP+VrkNb+T2ywunVB+TvOU0LX1jAZzfBr+3V1mIbBhzAMKvw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [musl] - '@biomejs/cli-linux-x64@2.4.7': - resolution: {integrity: sha512-bV8/uo2Tj+gumnk4sUdkerWyCPRabaZdv88IpbmDWARQQoA/Q0YaqPz1a+LSEDIL7OfrnPi9Hq1Llz4ZIGyIQQ==} + '@biomejs/cli-linux-x64@2.4.8': + resolution: {integrity: sha512-PdKXspVEaMCQLjtZCn6vfSck/li4KX9KGwSDbZdgIqlrizJ2MnMcE3TvHa2tVfXNmbjMikzcfJpuPWH695yJrw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [glibc] - '@biomejs/cli-win32-arm64@2.4.7': - resolution: {integrity: sha512-hOUHBMlFCvDhu3WCq6vaBoG0dp0LkWxSEnEEsxxXvOa9TfT6ZBnbh72A/xBM7CBYB7WgwqboetzFEVDnMxelyw==} + '@biomejs/cli-win32-arm64@2.4.8': + resolution: {integrity: sha512-LoFatS0tnHv6KkCVpIy3qZCih+MxUMvdYiPWLHRri7mhi2vyOOs8OrbZBcLTUEWCS+ktO72nZMy4F96oMhkOHQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.4.7': - resolution: {integrity: sha512-qEpGjSkPC3qX4ycbMUthXvi9CkRq7kZpkqMY1OyhmYlYLnANnooDQ7hDerM8+0NJ+DZKVnsIc07h30XOpt7LtQ==} + '@biomejs/cli-win32-x64@2.4.8': + resolution: {integrity: sha512-vAn7iXDoUbqFXqVocuq1sMYAd33p8+mmurqJkWl6CtIhobd/O6moe4rY5AJvzbunn/qZCdiDVcveqtkFh1e7Hg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -1114,57 +1114,57 @@ packages: resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==} engines: {node: '>=16'} - '@next/env@16.1.6': - resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + '@next/env@16.1.7': + resolution: {integrity: sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==} - '@next/swc-darwin-arm64@16.1.6': - resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + '@next/swc-darwin-arm64@16.1.7': + resolution: {integrity: sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.1.6': - resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + '@next/swc-darwin-x64@16.1.7': + resolution: {integrity: sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.1.6': - resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + '@next/swc-linux-arm64-gnu@16.1.7': + resolution: {integrity: sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@16.1.6': - resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + '@next/swc-linux-arm64-musl@16.1.7': + resolution: {integrity: sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@16.1.6': - resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + '@next/swc-linux-x64-gnu@16.1.7': + resolution: {integrity: sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@16.1.6': - resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + '@next/swc-linux-x64-musl@16.1.7': + resolution: {integrity: sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@16.1.6': - resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + '@next/swc-win32-arm64-msvc@16.1.7': + resolution: {integrity: sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.1.6': - resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + '@next/swc-win32-x64-msvc@16.1.7': + resolution: {integrity: sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1177,8 +1177,8 @@ packages: resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} engines: {node: '>= 20.19.0'} - '@openrouter/ai-sdk-provider@2.3.1': - resolution: {integrity: sha512-RkOUMSetrbS1i8kW1wIkfuq0RpXtiJOiFCx/AfEjGNZA8xOjdAosqPiImo2805Q6Px/9k1LUxu8NUmlSnrWrqg==} + '@openrouter/ai-sdk-provider@2.3.3': + resolution: {integrity: sha512-4fVteGkVedc7fGoA9+qJs4tpYwALezMq14m2Sjub3KmyRlksCbK+WJf67NPdGem8+NZrV2tAN42A1NU3+SiV3w==} engines: {node: '>=18'} peerDependencies: ai: ^6.0.0 @@ -2089,69 +2089,69 @@ packages: resolution: {integrity: sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==} engines: {node: '>=16.0.0'} - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -2162,24 +2162,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} engines: {node: '>= 20'} - '@tailwindcss/postcss@4.2.1': - resolution: {integrity: sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==} + '@tailwindcss/postcss@4.2.2': + resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} '@tanstack/react-table@8.21.3': resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} @@ -2317,8 +2317,8 @@ packages: resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} engines: {node: '>=0.8'} - ai@6.0.127: - resolution: {integrity: sha512-DKl0MJRuf3DUg+YHThbPXx9Jhd4vTZ6xAKXhVpy+WUrxSC2MgwA+V80ftx89JHGSTD1RVc0d3yIpKPNU4VKsAg==} + ai@6.0.129: + resolution: {integrity: sha512-5nGckqbzwUBZD7wV9jsA8qaoYRwGpU9LVMtXD+ZrxSi2H6QNjpbrhsuuEBKS9xcMYevCviVNoFzpmSUWzn45Hw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -2554,15 +2554,6 @@ packages: date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} @@ -2599,8 +2590,8 @@ packages: resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} engines: {node: '>=12'} - drizzle-kit@0.31.9: - resolution: {integrity: sha512-GViD3IgsXn7trFyBUUHyTFBpH/FsHTxYJ66qdbVggxef4UBPHRYxQaRzYLTuekYnk9i5FIEL9pbBIwMqX/Uwrg==} + drizzle-kit@0.31.10: + resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} hasBin: true drizzle-orm@0.45.1: @@ -2709,11 +2700,6 @@ packages: es-toolkit@1.45.1: resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} - peerDependencies: - esbuild: '>=0.12 <1' - esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -2840,85 +2826,85 @@ packages: peerDependencies: jspdf: ^2 || ^3 || ^4 - jspdf@4.2.0: - resolution: {integrity: sha512-hR/hnRevAXXlrjeqU5oahOE+Ln9ORJUB5brLHHqH67A+RBQZuFr5GkbI9XQI8OUFSEezKegsi45QRpc4bGj75Q==} + jspdf@4.2.1: + resolution: {integrity: sha512-YyAXyvnmjTbR4bHQRLzex3CuINCDlQnBqoSYyjJwTP2x9jDLuKDzy7aKUl0hgx3uhcl7xzg32agn5vlie6HIlQ==} kysely@0.28.11: resolution: {integrity: sha512-zpGIFg0HuoC893rIjYX1BETkVWdDnzTzF5e0kWXJFg5lE0k1/LfNWBejrcnOFu8Q2Rfq/hTDTU7XLUM8QOrpzg==} engines: {node: '>=20.0.0'} - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} lilconfig@2.1.0: @@ -2972,9 +2958,6 @@ packages: socks: optional: true - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mysql2@3.15.3: resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} engines: {node: '>= 8.0'} @@ -2998,8 +2981,8 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@16.1.6: - resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + next@16.1.7: + resolution: {integrity: sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -3261,8 +3244,8 @@ packages: reselect@5.1.1: resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} - resend@6.9.3: - resolution: {integrity: sha512-GRXjH9XZBJA+daH7bBVDuTShr22iWCxXA8P7t495G4dM/RC+d+3gHBK/6bz9K6Vpcq11zRQKmD+B+jECwQlyGQ==} + resend@6.9.4: + resolution: {integrity: sha512-/M3dsJzu5OgozqVsA4Psd/1L7EdePgOIIxClas453GOQYFG3VHc2ZyCHZFlvqsc9aZCCd2BJRRqZgWC8D9c7/g==} engines: {node: '>=20'} peerDependencies: '@react-email/render': '*' @@ -3379,8 +3362,8 @@ packages: resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==} engines: {node: '>=12.0.0'} - svix@1.84.1: - resolution: {integrity: sha512-K8DPPSZaW/XqXiz1kEyzSHYgmGLnhB43nQCMeKjWGCUpLIpAMMM8kx3rVVOSm6Bo6EHyK1RQLPT4R06skM/MlQ==} + svix@1.86.0: + resolution: {integrity: sha512-/HTvXwjLJe1l/MsLXAO1ddCYxElJk4eNR4DzOjDOEmGrPN/3BtBE8perGwMAaJ2sT5T172VkBYzmHcjUfM1JRQ==} tailwind-merge@3.5.0: resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} @@ -3388,6 +3371,9 @@ packages: tailwindcss@4.2.1: resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} @@ -3516,13 +3502,13 @@ packages: snapshots: - '@ai-sdk/anthropic@3.0.60(zod@4.3.6)': + '@ai-sdk/anthropic@3.0.62(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/gateway@3.0.73(zod@4.3.6)': + '@ai-sdk/gateway@3.0.75(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) @@ -3535,7 +3521,7 @@ snapshots: '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/openai@3.0.45(zod@4.3.6)': + '@ai-sdk/openai@3.0.46(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) @@ -3603,14 +3589,14 @@ snapshots: '@better-auth/utils': 0.3.1 mongodb: 7.1.0 - '@better-auth/passkey@1.5.5(c3ea9172df57720a1551ed5bee07c69e)': + '@better-auth/passkey@1.5.5(933ec2e58dee4f4ee115209e94e4bc6e)': dependencies: '@better-auth/core': 1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 '@simplewebauthn/browser': 13.2.2 '@simplewebauthn/server': 13.2.3 - better-auth: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + better-auth: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) better-call: 1.3.2(zod@4.3.6) nanostores: 1.1.1 zod: 4.3.6 @@ -3633,39 +3619,39 @@ snapshots: '@better-fetch/fetch@1.1.21': {} - '@biomejs/biome@2.4.7': + '@biomejs/biome@2.4.8': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.7 - '@biomejs/cli-darwin-x64': 2.4.7 - '@biomejs/cli-linux-arm64': 2.4.7 - '@biomejs/cli-linux-arm64-musl': 2.4.7 - '@biomejs/cli-linux-x64': 2.4.7 - '@biomejs/cli-linux-x64-musl': 2.4.7 - '@biomejs/cli-win32-arm64': 2.4.7 - '@biomejs/cli-win32-x64': 2.4.7 + '@biomejs/cli-darwin-arm64': 2.4.8 + '@biomejs/cli-darwin-x64': 2.4.8 + '@biomejs/cli-linux-arm64': 2.4.8 + '@biomejs/cli-linux-arm64-musl': 2.4.8 + '@biomejs/cli-linux-x64': 2.4.8 + '@biomejs/cli-linux-x64-musl': 2.4.8 + '@biomejs/cli-win32-arm64': 2.4.8 + '@biomejs/cli-win32-x64': 2.4.8 - '@biomejs/cli-darwin-arm64@2.4.7': + '@biomejs/cli-darwin-arm64@2.4.8': optional: true - '@biomejs/cli-darwin-x64@2.4.7': + '@biomejs/cli-darwin-x64@2.4.8': optional: true - '@biomejs/cli-linux-arm64-musl@2.4.7': + '@biomejs/cli-linux-arm64-musl@2.4.8': optional: true - '@biomejs/cli-linux-arm64@2.4.7': + '@biomejs/cli-linux-arm64@2.4.8': optional: true - '@biomejs/cli-linux-x64-musl@2.4.7': + '@biomejs/cli-linux-x64-musl@2.4.8': optional: true - '@biomejs/cli-linux-x64@2.4.7': + '@biomejs/cli-linux-x64@2.4.8': optional: true - '@biomejs/cli-win32-arm64@2.4.7': + '@biomejs/cli-win32-arm64@2.4.8': optional: true - '@biomejs/cli-win32-x64@2.4.7': + '@biomejs/cli-win32-x64@2.4.8': optional: true '@chevrotain/cst-dts-gen@10.5.0': @@ -4118,39 +4104,39 @@ snapshots: lilconfig: 2.1.0 optional: true - '@next/env@16.1.6': {} + '@next/env@16.1.7': {} - '@next/swc-darwin-arm64@16.1.6': + '@next/swc-darwin-arm64@16.1.7': optional: true - '@next/swc-darwin-x64@16.1.6': + '@next/swc-darwin-x64@16.1.7': optional: true - '@next/swc-linux-arm64-gnu@16.1.6': + '@next/swc-linux-arm64-gnu@16.1.7': optional: true - '@next/swc-linux-arm64-musl@16.1.6': + '@next/swc-linux-arm64-musl@16.1.7': optional: true - '@next/swc-linux-x64-gnu@16.1.6': + '@next/swc-linux-x64-gnu@16.1.7': optional: true - '@next/swc-linux-x64-musl@16.1.6': + '@next/swc-linux-x64-musl@16.1.7': optional: true - '@next/swc-win32-arm64-msvc@16.1.6': + '@next/swc-win32-arm64-msvc@16.1.7': optional: true - '@next/swc-win32-x64-msvc@16.1.6': + '@next/swc-win32-x64-msvc@16.1.7': optional: true '@noble/ciphers@2.1.1': {} '@noble/hashes@2.0.1': {} - '@openrouter/ai-sdk-provider@2.3.1(ai@6.0.127(zod@4.3.6))(zod@4.3.6)': + '@openrouter/ai-sdk-provider@2.3.3(ai@6.0.129(zod@4.3.6))(zod@4.3.6)': dependencies: - ai: 6.0.127(zod@4.3.6) + ai: 6.0.129(zod@4.3.6) zod: 4.3.6 '@opentelemetry/api@1.9.0': {} @@ -5190,74 +5176,74 @@ snapshots: '@tabby_ai/hijri-converter@1.0.5': {} - '@tailwindcss/node@4.2.1': + '@tailwindcss/node@4.2.2': dependencies: '@jridgewell/remapping': 2.3.5 enhanced-resolve: 5.20.0 jiti: 2.6.1 - lightningcss: 1.31.1 + lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.1 + tailwindcss: 4.2.2 - '@tailwindcss/oxide-android-arm64@4.2.1': + '@tailwindcss/oxide-android-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.1': + '@tailwindcss/oxide-darwin-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.1': + '@tailwindcss/oxide-darwin-x64@4.2.2': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.1': + '@tailwindcss/oxide-freebsd-x64@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.1': + '@tailwindcss/oxide-linux-x64-musl@4.2.2': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.1': + '@tailwindcss/oxide-wasm32-wasi@4.2.2': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': optional: true - '@tailwindcss/oxide@4.2.1': + '@tailwindcss/oxide@4.2.2': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - '@tailwindcss/postcss@4.2.1': + '@tailwindcss/postcss@4.2.2': dependencies: '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 postcss: 8.5.8 - tailwindcss: 4.2.1 + tailwindcss: 4.2.2 '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: @@ -5327,23 +5313,23 @@ snapshots: dependencies: '@types/webidl-conversions': 7.0.3 - '@vercel/analytics@2.0.1(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + '@vercel/analytics@2.0.1(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': optionalDependencies: - next: 16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: 16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 '@vercel/oidc@3.1.0': {} - '@vercel/speed-insights@2.0.0(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + '@vercel/speed-insights@2.0.0(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': optionalDependencies: - next: 16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: 16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 adler-32@1.3.1: {} - ai@6.0.127(zod@4.3.6): + ai@6.0.129(zod@4.3.6): dependencies: - '@ai-sdk/gateway': 3.0.73(zod@4.3.6) + '@ai-sdk/gateway': 3.0.75(zod@4.3.6) '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) '@opentelemetry/api': 1.9.0 @@ -5372,7 +5358,7 @@ snapshots: baseline-browser-mapping@2.10.0: {} - better-auth@1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + better-auth@1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@better-auth/core': 1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/drizzle-adapter': 1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))) @@ -5393,11 +5379,11 @@ snapshots: zod: 4.3.6 optionalDependencies: '@prisma/client': 7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) - drizzle-kit: 0.31.9 + drizzle-kit: 0.31.10 drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) mongodb: 7.1.0 mysql2: 3.15.3 - next: 16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: 16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) pg: 8.20.0 prisma: 7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react: 19.2.4 @@ -5567,10 +5553,6 @@ snapshots: date-fns@4.1.0: {} - debug@4.4.3: - dependencies: - ms: 2.1.3 - decimal.js-light@2.5.1: {} deepmerge-ts@7.1.5: @@ -5598,14 +5580,12 @@ snapshots: dotenv@17.3.1: {} - drizzle-kit@0.31.9: + drizzle-kit@0.31.10: dependencies: '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 esbuild: 0.25.12 - esbuild-register: 3.6.0(esbuild@0.25.12) - transitivePeerDependencies: - - supports-color + tsx: 4.21.0 drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)): optionalDependencies: @@ -5635,13 +5615,6 @@ snapshots: es-toolkit@1.45.1: {} - esbuild-register@3.6.0(esbuild@0.25.12): - dependencies: - debug: 4.4.3 - esbuild: 0.25.12 - transitivePeerDependencies: - - supports-color - esbuild@0.18.20: optionalDependencies: '@esbuild/android-arm': 0.18.20 @@ -5827,11 +5800,11 @@ snapshots: json-schema@0.4.0: {} - jspdf-autotable@5.0.7(jspdf@4.2.0): + jspdf-autotable@5.0.7(jspdf@4.2.1): dependencies: - jspdf: 4.2.0 + jspdf: 4.2.1 - jspdf@4.2.0: + jspdf@4.2.1: dependencies: '@babel/runtime': 7.28.6 fast-png: 6.4.0 @@ -5844,54 +5817,54 @@ snapshots: kysely@0.28.11: {} - lightningcss-android-arm64@1.31.1: + lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.31.1: + lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.31.1: + lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.31.1: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.31.1: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.31.1: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.31.1: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.31.1: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.31.1: + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.31.1: + lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.31.1: + lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.31.1: + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 lilconfig@2.1.0: optional: true @@ -5922,8 +5895,6 @@ snapshots: bson: 7.2.0 mongodb-connection-string-url: 7.0.1 - ms@2.1.3: {} - mysql2@3.15.3: dependencies: aws-ssl-profiles: 1.1.2 @@ -5951,9 +5922,9 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - '@next/env': 16.1.6 + '@next/env': 16.1.7 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.0 caniuse-lite: 1.0.30001777 @@ -5962,14 +5933,14 @@ snapshots: react-dom: 19.2.4(react@19.2.4) styled-jsx: 5.1.6(react@19.2.4) optionalDependencies: - '@next/swc-darwin-arm64': 16.1.6 - '@next/swc-darwin-x64': 16.1.6 - '@next/swc-linux-arm64-gnu': 16.1.6 - '@next/swc-linux-arm64-musl': 16.1.6 - '@next/swc-linux-x64-gnu': 16.1.6 - '@next/swc-linux-x64-musl': 16.1.6 - '@next/swc-win32-arm64-msvc': 16.1.6 - '@next/swc-win32-x64-msvc': 16.1.6 + '@next/swc-darwin-arm64': 16.1.7 + '@next/swc-darwin-x64': 16.1.7 + '@next/swc-linux-arm64-gnu': 16.1.7 + '@next/swc-linux-arm64-musl': 16.1.7 + '@next/swc-linux-x64-gnu': 16.1.7 + '@next/swc-linux-x64-musl': 16.1.7 + '@next/swc-win32-arm64-msvc': 16.1.7 + '@next/swc-win32-x64-msvc': 16.1.7 '@opentelemetry/api': 1.9.0 babel-plugin-react-compiler: 1.0.0 sharp: 0.34.5 @@ -6279,10 +6250,10 @@ snapshots: reselect@5.1.1: {} - resend@6.9.3: + resend@6.9.4: dependencies: postal-mime: 2.7.3 - svix: 1.84.1 + svix: 1.86.0 resolve-pkg-maps@1.0.0: {} @@ -6399,7 +6370,7 @@ snapshots: svg-pathdata@6.0.3: optional: true - svix@1.84.1: + svix@1.86.0: dependencies: standardwebhooks: 1.0.0 uuid: 10.0.0 @@ -6408,6 +6379,8 @@ snapshots: tailwindcss@4.2.1: {} + tailwindcss@4.2.2: {} + tapable@2.3.0: {} text-segmentation@1.0.3: diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100755 index 0000000..097cfb0 --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,105 @@ +#!/bin/bash +# ============================================================== +# openmonetis-backup.sh +# Backup automático do PostgreSQL para Google Drive via rclone +# Suporta: banco remoto (Supabase/etc) ou Docker local +# ============================================================== +set -euo pipefail +export TZ="America/Sao_Paulo" + +# Raiz do projeto (um nível acima de scripts/) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +if [[ -f "$PROJECT_DIR/.env" ]]; then + set -a + # shellcheck disable=SC1091 + source "$PROJECT_DIR/.env" + set +a +else + echo "ERRO: .env não encontrado em $PROJECT_DIR" >&2 + exit 1 +fi + +# ============================================================ +# CONFIGURAÇÃO — ajuste aqui +# ============================================================ + +# Modo de conexão: "remote" (Supabase/URL) ou "docker" (container local) +DB_MODE="remote" + +# --- Modo remote --- +# Usa DATABASE_URL do .env (porta 6543 funciona com --no-owner --no-privileges) +REMOTE_DB_URL="${DATABASE_URL}" + +# --- Modo docker --- +DOCKER_CONTAINER="openmonetis_postgres" +DOCKER_DB_NAME="openmonetis_db" +DOCKER_DB_USER="openmonetis" + +# --- Destino e retenção --- +BACKUP_DIR="$PROJECT_DIR/backup" +GDRIVE_REMOTE="gdrive:BACKUP OPENMONETIS" +RETENTION_LOCAL_DAYS=7 +RETENTION_REMOTE_DAYS=30 + +# ============================================================ +# SCRIPT — não alterar abaixo +# ============================================================ + +TIMESTAMP=$(date +"%Y-%m-%d_%H-%M") +LOG_PREFIX="[$(date '+%Y-%m-%d %H:%M:%S')]" + +log() { echo "$LOG_PREFIX $*"; } + +mkdir -p "$BACKUP_DIR" + +DUMP_FILE="$BACKUP_DIR/openmonetis_${TIMESTAMP}.dump" +SQL_FILE="$BACKUP_DIR/openmonetis_${TIMESTAMP}.sql.gz" + +log "Iniciando backup (modo: $DB_MODE)..." + +# --- Dump --- +if [[ "$DB_MODE" == "remote" ]]; then + # --no-owner --no-privileges: necessário no Supabase (roles gerenciados internamente) + pg_dump --format=custom --no-owner --no-privileges \ + "$REMOTE_DB_URL" > "$DUMP_FILE" + + pg_dump --no-owner --no-privileges \ + "$REMOTE_DB_URL" | gzip > "$SQL_FILE" + +elif [[ "$DB_MODE" == "docker" ]]; then + docker exec "$DOCKER_CONTAINER" pg_dump \ + -U "$DOCKER_DB_USER" -Fc "$DOCKER_DB_NAME" > "$DUMP_FILE" + + docker exec "$DOCKER_CONTAINER" pg_dump \ + -U "$DOCKER_DB_USER" "$DOCKER_DB_NAME" | gzip > "$SQL_FILE" + +else + log "ERRO: DB_MODE inválido ('$DB_MODE'). Use 'remote' ou 'docker'." + exit 1 +fi + +log "Dump concluído: $(du -sh "$DUMP_FILE" | cut -f1) (.dump) | $(du -sh "$SQL_FILE" | cut -f1) (.sql.gz)" + +# --- Upload para Google Drive --- +if ! command -v rclone &>/dev/null; then + log "AVISO: rclone não encontrado. Pulando upload." +else + rclone copy "$BACKUP_DIR" "$GDRIVE_REMOTE" \ + --include "openmonetis_*" \ + --min-age 1s + log "Upload concluído → $GDRIVE_REMOTE" + + # Limpeza remota + rclone delete "$GDRIVE_REMOTE" \ + --min-age "${RETENTION_REMOTE_DAYS}d" \ + --include "openmonetis_*" + log "Limpeza remota: mantidos últimos $RETENTION_REMOTE_DAYS dias." +fi + +# --- Limpeza local --- +find "$BACKUP_DIR" -name "openmonetis_*" -mtime +"$RETENTION_LOCAL_DAYS" -delete +log "Limpeza local: mantidos últimos $RETENTION_LOCAL_DAYS dias." + +log "Backup finalizado com sucesso." diff --git a/scripts/setup-env.sh b/scripts/setup-env.sh index 7b0340d..b8f7b7e 100755 --- a/scripts/setup-env.sh +++ b/scripts/setup-env.sh @@ -27,12 +27,23 @@ fi if [ -f .env.example ]; then cp .env.example .env echo "✅ Arquivo .env criado a partir de .env.example" - echo "" - echo "⚠️ IMPORTANTE: Edite o arquivo .env e configure:" - echo " - DATABASE_URL" - echo " - BETTER_AUTH_SECRET (gere com: openssl rand -base64 32)" - echo " - Outras variáveis necessárias" else echo "❌ Erro: .env.example não encontrado!" exit 1 fi + +# Gerar BETTER_AUTH_SECRET automaticamente +if command -v openssl &> /dev/null; then + SECRET=$(openssl rand -base64 32) + sed -i.bak "s|BETTER_AUTH_SECRET=.*|BETTER_AUTH_SECRET=$SECRET|" .env && rm -f .env.bak + echo "✅ BETTER_AUTH_SECRET gerado automaticamente" +else + echo "⚠️ openssl não encontrado — configure BETTER_AUTH_SECRET manualmente:" + echo " openssl rand -base64 32" +fi + +echo "" +echo "⚠️ IMPORTANTE: Edite o arquivo .env e configure:" +echo " - DATABASE_URL" +echo " - BETTER_AUTH_URL" +echo " - Demais variáveis opcionais (OAuth, e-mail, IA)" diff --git a/setup.mjs b/setup.mjs new file mode 100644 index 0000000..ef77d8c --- /dev/null +++ b/setup.mjs @@ -0,0 +1,365 @@ +#!/usr/bin/env node + +/** + * OpenMonetis Setup Script + * Uso: node setup.mjs + */ + +import { createInterface } from "readline"; +import { execSync } from "child_process"; +import { writeFileSync, existsSync } from "fs"; +import { randomBytes } from "crypto"; +import { resolve, join } from "path"; + +// ─── Cores e símbolos ──────────────────────────────────────────────────────── + +const c = { + reset: "\x1b[0m", + bold: "\x1b[1m", + dim: "\x1b[2m", + green: "\x1b[32m", + red: "\x1b[31m", + yellow: "\x1b[33m", + cyan: "\x1b[36m", +}; + +const sym = { + ok: `${c.green}✔${c.reset}`, + fail: `${c.red}✗${c.reset}`, + warn: `${c.yellow}!${c.reset}`, + arrow: `${c.cyan}→${c.reset}`, +}; + +// ─── Helpers ───────────────────────────────────────────────────────────────── + +function section(label) { + console.log(`\n${c.dim}── ${label} ${"─".repeat(Math.max(0, 48 - label.length))}${c.reset}`); +} + +function runSilent(cmd) { + try { + return execSync(cmd, { stdio: "pipe" }).toString().trim(); + } catch { + return null; + } +} + +function run(cmd, opts = {}) { + execSync(cmd, { stdio: "pipe", ...opts }); +} + +function spinner(text) { + const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + let i = 0; + const id = setInterval(() => { + process.stdout.write(`\r${c.cyan}${frames[i++ % frames.length]}${c.reset} ${text}`); + }, 80); + return { + stop: (msg) => { clearInterval(id); process.stdout.write(`\r${sym.ok} ${msg}\n`); }, + fail: (msg) => { clearInterval(id); process.stdout.write(`\r${sym.fail} ${msg}\n`); }, + }; +} + +const rl = createInterface({ input: process.stdin, output: process.stdout }); +const ask = (q) => new Promise((res) => rl.question(q, res)); + +async function askDefault(question, defaultValue) { + const answer = await ask(`${question} [${c.dim}${defaultValue}${c.reset}]: `); + return answer.trim() || defaultValue; +} + +async function askYesNo(question) { + const answer = await ask(`${question} ${c.dim}[s/N]${c.reset}: `); + return answer.trim().toLowerCase() === "s"; +} + +function abort(msg) { + console.log(`\n${sym.fail} ${msg}\n`); + rl.close(); + process.exit(1); +} + +// ─── Header ────────────────────────────────────────────────────────────────── + +console.log(` +${c.bold}${c.cyan} OpenMonetis — Setup${c.reset} + ${c.dim}Gestão financeira self-hosted${c.reset} +`); + +// ─── ETAPA 1: Verificações do sistema ──────────────────────────────────────── + +section("Verificando sistema"); + +// Node +const nodeMajor = parseInt(process.versions.node.split(".")[0]); +if (nodeMajor < 22) { + console.log(`${sym.fail} Node.js ${process.versions.node} — requer 22+`); + console.log(` ${sym.arrow} https://nodejs.org`); + process.exit(1); +} +console.log(`${sym.ok} Node.js ${process.versions.node}`); + +// pnpm +let pnpmVersion = runSilent("pnpm --version"); +if (!pnpmVersion) { + process.stdout.write(`${sym.warn} pnpm não encontrado — instalando... `); + try { + run("npm install -g pnpm"); + pnpmVersion = runSilent("pnpm --version"); + process.stdout.write(`${sym.ok}\n`); + console.log(`${sym.ok} pnpm ${pnpmVersion}`); + } catch { + console.log(`\n${sym.fail} Falha ao instalar pnpm`); + console.log(` ${sym.arrow} npm install -g pnpm`); + process.exit(1); + } +} else { + console.log(`${sym.ok} pnpm ${pnpmVersion}`); +} + +// Git +if (!runSilent("git --version")) { + console.log(`${sym.fail} Git não encontrado`); + console.log(` ${sym.arrow} https://git-scm.com`); + process.exit(1); +} +console.log(`${sym.ok} Git disponível`); + +// Docker +const dockerAvailable = !!runSilent("docker --version"); +if (dockerAvailable) { + console.log(`${sym.ok} Docker disponível`); +} else { + console.log(`${sym.warn} Docker não encontrado — banco local indisponível`); +} + +// ─── ETAPA 2: Banco de dados ────────────────────────────────────────────────── + +section("Banco de dados"); + +let databaseUrl; +let useLocalDocker = false; + +if (dockerAvailable) { + console.log(` [1] PostgreSQL local via Docker ${c.dim}(recomendado)${c.reset}`); + console.log(` [2] URL remota ${c.dim}(Supabase, Neon, Railway...)${c.reset}\n`); + const dbChoice = await ask(`Escolha [1]: `); + + if (dbChoice.trim() === "2") { + databaseUrl = await ask(`DATABASE_URL: `); + if (!databaseUrl.match(/^postgre(s|sql):\/\//)) { + abort("URL inválida — deve começar com postgresql:// ou postgres://"); + } + } else { + useLocalDocker = true; + databaseUrl = + "postgresql://openmonetis:openmonetis_dev_password@localhost:5432/openmonetis_db"; + console.log(`${sym.ok} Banco local selecionado`); + } +} else { + console.log(` ${c.dim}Insira a URL de um banco remoto (Supabase, Neon, Railway...)${c.reset}\n`); + databaseUrl = await ask(`DATABASE_URL: `); + if (!databaseUrl.match(/^postgre(s|sql):\/\//)) { + abort("URL inválida — deve começar com postgresql:// ou postgres://"); + } +} + +// ─── ETAPA 3: Autenticação ──────────────────────────────────────────────────── + +section("Autenticação"); + +const authSecret = randomBytes(32).toString("base64"); +const betterAuthUrl = await askDefault("URL da aplicação", "http://localhost:3000"); + +console.log(`${sym.ok} BETTER_AUTH_SECRET gerado`); +console.log(`${sym.ok} BETTER_AUTH_URL: ${betterAuthUrl}`); + +// ─── ETAPA 4: Opcionais ─────────────────────────────────────────────────────── + +section("Opcionais"); +console.log(` ${c.dim}Deixe em branco e configure depois editando o .env${c.reset}\n`); + +// Google OAuth +let googleClientId = ""; +let googleClientSecret = ""; +if (await askYesNo(" Google OAuth (login social)?")) { + googleClientId = await ask(" GOOGLE_CLIENT_ID: "); + googleClientSecret = await ask(" GOOGLE_CLIENT_SECRET: "); +} + +// Resend +let resendApiKey = ""; +let resendFromEmail = ""; +if (await askYesNo(" E-mail via Resend (notificações e convites)?")) { + resendApiKey = await ask(" RESEND_API_KEY: "); + resendFromEmail = await ask(` RESEND_FROM_EMAIL [OpenMonetis ]: `); + if (!resendFromEmail.trim()) resendFromEmail = "OpenMonetis "; +} + +// AI +let anthropicKey = ""; +let openaiKey = ""; +let googleAiKey = ""; +let openrouterKey = ""; +if (await askYesNo(" Insights com IA (Claude, GPT, Gemini, OpenRouter)?")) { + console.log(` ${c.dim}Deixe em branco o que não for usar${c.reset}`); + anthropicKey = await ask(" ANTHROPIC_API_KEY: "); + openaiKey = await ask(" OPENAI_API_KEY: "); + googleAiKey = await ask(" GOOGLE_GENERATIVE_AI_API_KEY: "); + openrouterKey = await ask(" OPENROUTER_API_KEY: "); +} + +// Domínio público +let publicDomain = ""; +if (await askYesNo(" Domínio público separado para a landing page?")) { + publicDomain = await ask(" PUBLIC_DOMAIN (ex: openmonetis.com): "); +} + +rl.close(); + +// ─── ETAPA 5: Confirmar e executar ──────────────────────────────────────────── + +const targetDir = resolve("openmonetis"); + +section("Instalação"); +console.log(` + ${sym.arrow} Clonar repositório em ./openmonetis + ${sym.arrow} Gerar .env + ${sym.arrow} pnpm install${useLocalDocker ? `\n ${sym.arrow} Subir banco PostgreSQL (Docker)\n ${sym.arrow} Habilitar extensões` : ""} + ${sym.arrow} pnpm db:push +`); + +if (existsSync(targetDir)) { + abort("A pasta ./openmonetis já existe. Remova-a e tente novamente."); +} + +// Clonar +let s = spinner("Clonando repositório..."); +try { + run("git clone https://github.com/felipegcoutinho/openmonetis.git openmonetis"); + s.stop("Repositório clonado"); +} catch { + s.fail("Falha ao clonar repositório"); + process.exit(1); +} + +// Gerar .env +const val = (v, fallback = "") => v?.trim() || fallback; +const opt = (key, value) => (value?.trim() ? `${key}=${value}` : `# ${key}=`); + +const envContent = [ + `# Gerado por setup.mjs em ${new Date().toISOString()}`, + "", + "# === Database ===", + `DATABASE_URL=${databaseUrl}`, + "", + "# === Better Auth ===", + `BETTER_AUTH_SECRET=${authSecret}`, + `BETTER_AUTH_URL=${betterAuthUrl}`, + "", + "# === Portas ===", + "APP_PORT=3000", + "DB_PORT=5432", + "", + "# === PostgreSQL (Docker local) ===", + "POSTGRES_USER=openmonetis", + "POSTGRES_PASSWORD=openmonetis_dev_password", + "POSTGRES_DB=openmonetis_db", + "", + "# === Multi-domínio ===", + opt("PUBLIC_DOMAIN", publicDomain), + "", + "# === Google OAuth ===", + opt("GOOGLE_CLIENT_ID", googleClientId), + opt("GOOGLE_CLIENT_SECRET", googleClientSecret), + "", + "# === Email (Resend) ===", + opt("RESEND_API_KEY", resendApiKey), + resendFromEmail ? `RESEND_FROM_EMAIL="${resendFromEmail}"` : "# RESEND_FROM_EMAIL=", + "", + "# === AI Providers ===", + opt("ANTHROPIC_API_KEY", anthropicKey), + opt("OPENAI_API_KEY", openaiKey), + opt("GOOGLE_GENERATIVE_AI_API_KEY", googleAiKey), + opt("OPENROUTER_API_KEY", openrouterKey), +].join("\n"); + +writeFileSync(join(targetDir, ".env"), envContent); +console.log(`${sym.ok} .env gerado`); + +// pnpm install +s = spinner("Instalando dependências..."); +try { + run("pnpm install", { cwd: targetDir }); + s.stop("Dependências instaladas"); +} catch { + s.fail("Falha ao instalar dependências"); + process.exit(1); +} + +// Docker local +if (useLocalDocker) { + s = spinner("Subindo banco PostgreSQL..."); + try { + run("pnpm docker:up:db", { cwd: targetDir }); + s.stop("Banco iniciado"); + } catch { + s.fail("Falha ao iniciar o banco"); + process.exit(1); + } + + // Aguardar postgres ficar pronto + s = spinner("Aguardando PostgreSQL ficar pronto..."); + let ready = false; + for (let i = 0; i < 20; i++) { + try { + run("docker compose exec -T db pg_isready -U openmonetis", { cwd: targetDir }); + ready = true; + break; + } catch { + await new Promise((r) => setTimeout(r, 1500)); + } + } + if (!ready) { + s.fail("PostgreSQL não respondeu a tempo"); + process.exit(1); + } + s.stop("PostgreSQL pronto"); + + // Extensões + s = spinner("Habilitando extensões do banco..."); + try { + run("pnpm db:enableExtensions", { cwd: targetDir }); + s.stop("Extensões habilitadas"); + } catch { + s.fail("Falha ao habilitar extensões"); + process.exit(1); + } +} + +// db:push +s = spinner("Aplicando schema no banco..."); +try { + run("pnpm db:push", { cwd: targetDir }); + s.stop("Schema aplicado"); +} catch { + s.fail("Falha ao aplicar schema"); + process.exit(1); +} + +// ─── Finalização ────────────────────────────────────────────────────────────── + +console.log(` +${c.green}${c.bold} ✔ OpenMonetis instalado com sucesso!${c.reset} + + ${c.bold}Para iniciar:${c.reset} + cd openmonetis + pnpm dev${ + useLocalDocker + ? ` ${c.dim}→ desenvolvimento${c.reset}\n pnpm docker:up ${c.dim}→ produção local (app + banco)${c.reset}` + : ` ${c.dim}→ desenvolvimento${c.reset}` + } + + ${c.bold}Acesse:${c.reset} ${betterAuthUrl} + ${c.bold}Docs:${c.reset} https://github.com/felipegcoutinho/openmonetis +`);