diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 9a19157..f583852 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -47,11 +47,14 @@ jobs: run: | files=( supabase/functions/_shared/hermes-config.ts + supabase/functions/_shared/default-skills.ts supabase/functions/_shared/runtime-sync.ts supabase/functions/sync-agent-runtime/index.ts supabase/functions/sync-agent-skills/index.ts supabase/functions/keep-alive-agents/index.ts supabase/functions/provision-agent/index.ts + supabase/functions/create-cronjob-from-agent/index.ts + supabase/functions/create-skill-from-agent/index.ts supabase/functions/publish-skill-version/index.ts supabase/functions/railway-webhook/index.ts supabase/functions/update-agent-config/index.ts diff --git a/README.md b/README.md index 359a062..cc79a09 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,10 @@ Já configuradas via `.env` (gerado automaticamente pelo Lovable Cloud): - `PADDLE_API_KEY` / `PADDLE_WEBHOOK_SECRET` - `SUPABASE_SERVICE_ROLE_KEY` - `RAILWAY_API_TOKEN` — token da Railway Public API, usado por `provision-agent`/`suspend-agent`/`resume-agent` para criar e gerenciar containers Hermes. -- `OLLAMA_API_KEY` — chave do Ollama Cloud, injetada como env var no container Hermes (imagem custom `ghcr.io/domfelipe/hermes-agent-custom:latest`). -- `HERMES_API_SERVER_KEY` — token usado pelo API server interno do Hermes (`API_SERVER_KEY`). Valor atual: `HermesRailwayKey2026SecureToken123456`. +- `OLLAMA_API_KEY` — chave do Ollama Cloud, injetada como env var no container Hermes. +- `HERMES_RUNTIME_IMAGE` — opcional; imagem Docker usada no Railway. Default: `ghcr.io/domfelipe/hermes-agent-custom:latest`. +- `HERMES_API_SERVER_KEY` — token usado pelo API server interno do Hermes (`API_SERVER_KEY`). Gere um valor forte por ambiente e nunca versionado no repo. +- `INTERNAL_FUNCTION_SECRET` — segredo server-to-server usado pelo runtime Hermes para chamar Edge Functions internas, como `create-cronjob-from-agent`. - `TELEGRAM_MANAGER_BOT_TOKEN` — token do bot manager (`@mika_managerbot`) usado para criar bots dos clientes em 1 toque via Bot Management Mode do BotFather. - `TELEGRAM_MANAGER_BOT_USERNAME` — username do bot manager, padrão `mika_managerbot` (sem `@`). @@ -42,17 +44,21 @@ Já configuradas via `.env` (gerado automaticamente pelo Lovable Cloud): ``` Resposta esperada: `{ "webhook_set": "...", "telegram_response": { "ok": true } }`. -> **Imagem Docker custom**: o container roda `ghcr.io/domfelipe/hermes-agent-custom:latest`, que já contém o `SOUL.md` embutido. Por isso não passamos mais `HERMES_SOUL_OVERRIDE` via env var, e o Dockerfile define o `CMD` (sem `startCommand` no Railway). Secrets removidos do projeto: `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `HERMES_SOUL_OVERRIDE`. +> **Imagem Docker custom**: por padrão o container roda `ghcr.io/domfelipe/hermes-agent-custom:latest`, mas `HERMES_RUNTIME_IMAGE` pode apontar para uma tag de branch/sha durante smoke. A imagem já contém o `SOUL.md` embutido. Por isso não passamos mais `HERMES_SOUL_OVERRIDE` via env var, e o Dockerfile define o `CMD` (sem `startCommand` no Railway). Secrets removidos do projeto: `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `HERMES_SOUL_OVERRIDE`. + +> **Suspend/Resume via flag, não via stop.** Railway não permite parar containers sem redeploy. As Edge Functions `suspend-agent`/`resume-agent` usam a env var `HERMES_SUSPENDED` + `serviceInstanceRedeploy`: +> +> - `suspend` → upsert `HERMES_SUSPENDED=true` e redeploy → container entra em `sleep infinity`. +> - `resume` → upsert `HERMES_SUSPENDED=""` e redeploy → container sobe normal. +> +> Isso depende do start command verificar a flag. Novos serviços já são provisionados com o comando correto (`HERMES_START_COMMAND` em `_shared/railway.ts`): +> +> ```bash +> /bin/bash -c 'if [ "$HERMES_SUSPENDED" = "true" ]; then echo "Agent suspended" && sleep infinity; fi && if [ -n "$HERMES_SOUL_OVERRIDE" ]; then echo "$HERMES_SOUL_OVERRIDE" > /opt/data/SOUL.md; fi && /opt/hermes/docker/entrypoint.sh gateway run' +> ``` +> +> **Para serviços Railway existentes (provisionados antes desta mudança):** atualize manualmente o Start Command via Railway UI/Agent para o comando acima — caso contrário `suspend-agent` apenas marcará `status='suspended'` no banco mas o container continuará rodando. - > **Suspend/Resume via flag, não via stop.** Railway não permite parar containers sem redeploy. As Edge Functions `suspend-agent`/`resume-agent` usam a env var `HERMES_SUSPENDED` + `serviceInstanceRedeploy`: - > - `suspend` → upsert `HERMES_SUSPENDED=true` e redeploy → container entra em `sleep infinity`. - > - `resume` → upsert `HERMES_SUSPENDED=""` e redeploy → container sobe normal. - > - > Isso depende do start command verificar a flag. Novos serviços já são provisionados com o comando correto (`HERMES_START_COMMAND` em `_shared/railway.ts`): - > ```bash - > /bin/bash -c 'if [ "$HERMES_SUSPENDED" = "true" ]; then echo "Agent suspended" && sleep infinity; fi && if [ -n "$HERMES_SOUL_OVERRIDE" ]; then echo "$HERMES_SOUL_OVERRIDE" > /opt/data/SOUL.md; fi && /opt/hermes/docker/entrypoint.sh gateway run' - > ``` - > **Para serviços Railway existentes (provisionados antes desta mudança):** atualize manualmente o Start Command via Railway UI/Agent para o comando acima — caso contrário `suspend-agent` apenas marcará `status='suspended'` no banco mas o container continuará rodando. - `OPENROUTER_API_KEY` — **obrigatório**. Injetado em cada container Hermes provisionado para que o agente possa chamar os modelos `openrouter/google/gemma-4-*-it`. Sem isso o `provision-agent` retorna 500. - `ADMIN_TELEGRAM_BOT_TOKEN` — token do bot de admin (ex: `@mika_test2_bot`) usado pelo `payments-webhook` para enviar notificações de novos clientes, falhas de pagamento e cancelamentos. - `ADMIN_TELEGRAM_CHAT_ID` — chat ID do admin que recebe as notificações (ex: `179720882`). @@ -155,29 +161,29 @@ Para cada provider abaixo, crie um OAuth app e configure a **Redirect URI**: https://smsarmgoirlcedmqvdgc.supabase.co/functions/v1/oauth-callback ``` -| Provider | Console | Scopes mínimos | -|----------|---------|----------------| +| Provider | Console | Scopes mínimos | +| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | **Google Workspace** | [console.cloud.google.com](https://console.cloud.google.com) → APIs & Services → Credentials → OAuth 2.0 Client ID (Web app) | `openid email profile https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/calendar` | -| **Microsoft 365** | [Azure Portal](https://portal.azure.com) → App registrations → New registration → Web | `openid email profile offline_access Mail.Read Calendars.ReadWrite` | -| **Notion** | [notion.so/my-integrations](https://www.notion.so/my-integrations) → New integration (Public) | (definidos na integração) | -| **Todoist** | [developer.todoist.com](https://developer.todoist.com/appconsole.html) → App management → Create app | `data:read_write` | -| **Cal.com** | [app.cal.com/settings/developer](https://app.cal.com/settings/developer/oauth-clients) → New OAuth Client | `READ_BOOKING WRITE_BOOKING READ_PROFILE` | +| **Microsoft 365** | [Azure Portal](https://portal.azure.com) → App registrations → New registration → Web | `openid email profile offline_access Mail.Read Calendars.ReadWrite` | +| **Notion** | [notion.so/my-integrations](https://www.notion.so/my-integrations) → New integration (Public) | (definidos na integração) | +| **Todoist** | [developer.todoist.com](https://developer.todoist.com/appconsole.html) → App management → Create app | `data:read_write` | +| **Cal.com** | [app.cal.com/settings/developer](https://app.cal.com/settings/developer/oauth-clients) → New OAuth Client | `READ_BOOKING WRITE_BOOKING READ_PROFILE` | #### 2. Adicionar os 10 secrets no Lovable Cloud Pelo menu **Connectors → Lovable Cloud → Secrets**, adicione: ``` -GOOGLE_OAUTH_CLIENT_ID -GOOGLE_OAUTH_CLIENT_SECRET -MICROSOFT_OAUTH_CLIENT_ID -MICROSOFT_OAUTH_CLIENT_SECRET -NOTION_OAUTH_CLIENT_ID -NOTION_OAUTH_CLIENT_SECRET -TODOIST_OAUTH_CLIENT_ID -TODOIST_OAUTH_CLIENT_SECRET -CALCOM_OAUTH_CLIENT_ID -CALCOM_OAUTH_CLIENT_SECRET +GOOGLE_CLIENT_ID +GOOGLE_CLIENT_SECRET +MICROSOFT_CLIENT_ID +MICROSOFT_CLIENT_SECRET +NOTION_CLIENT_ID +NOTION_CLIENT_SECRET +TODOIST_CLIENT_ID +TODOIST_CLIENT_SECRET +CALCOM_CLIENT_ID +CALCOM_CLIENT_SECRET ``` #### 3. Verificar publicação Realtime @@ -215,8 +221,10 @@ A view `user_integration_limits` e `user_jobs_limits` usam dados de `user_integr - `user_roles` + enum `app_role` + função `has_role()` (substitui `is_admin` em profiles, mais seguro) - Trigger `on_agent_instance_provisioning` usando `pg_net` chama `provision-agent` quando uma agent_instance entra em status `provisioning` - **Edge Functions**: - - `provision-agent` (verify_jwt=false): cria serviço Docker no Railway via GraphQL API, configura variáveis (TELEGRAM_BOT_TOKEN do Vault, OPENCODE_ZEN_API_KEY, etc.) e dispara deploy. Apaga webhook do Telegram antes (Hermes opera em polling). Retry com backoff exponencial até 5 tentativas. + - `provision-agent` (verify_jwt=false): cria serviço Docker no Railway via GraphQL API, configura Telegram/modelo/soul e o contrato runtime→plataforma (`MIKA_CREATE_CRONJOB_URL`, `MIKA_CREATE_SKILL_URL`, `MIKA_AGENT_INSTANCE_ID`, `MIKA_INTERNAL_FUNCTION_SECRET`), e dispara deploy. Apaga webhook do Telegram antes (Hermes opera em polling). Retry com backoff exponencial até 5 tentativas. - `railway-webhook` (verify_jwt=false): recebe eventos do Railway. SUCCESS → marca agent como `active`; FAILED/CRASHED → marca como `error`. + - `create-cronjob-from-agent` / `create-skill-from-agent` (verify_jwt=false): endpoints server-to-server chamados pelo runtime Hermes com `X-Internal-Secret`. + - `railway-webhook` garante um pacote padrao de skills antes de sincronizar `/api/skills/sync` no runtime. - **Helper compartilhado**: `supabase/functions/_shared/railway.ts` ### Etapas pós-deploy (uma única vez) — **OBRIGATÓRIAS** @@ -292,4 +300,3 @@ bun dev # dev server (porta 8080) bun run build # build de produção bun run typecheck ``` - diff --git a/package-lock.json b/package-lock.json index acd1c94..64775b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "tw-animate-css": "^1.3.4", "vaul": "^1.1.2", "vite-tsconfig-paths": "^6.0.2", - "zod": "^4.3.6" + "zod": "^3.25.76" }, "devDependencies": { "@eslint/js": "^9.32.0", @@ -420,22 +420,22 @@ } }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz", - "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz", + "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==", "license": "MIT OR Apache-2.0", "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } }, "node_modules/@cloudflare/unenv-preset": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.0.tgz", - "integrity": "sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz", + "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==", "license": "MIT OR Apache-2.0", "peerDependencies": { "unenv": "2.0.0-rc.24", - "workerd": "1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0" + "workerd": ">1.20260305.0 <2.0.0-0" }, "peerDependenciesMeta": { "workerd": { @@ -444,26 +444,26 @@ } }, "node_modules/@cloudflare/vite-plugin": { - "version": "1.32.2", - "resolved": "https://registry.npmjs.org/@cloudflare/vite-plugin/-/vite-plugin-1.32.2.tgz", - "integrity": "sha512-sEI/jusfDvzHIL4oiBBV5iUxAXfTRvguecIDWQ/AxBgEjGO1ZslHOEy4rlxfgqrdRWtq0TM9m3oC+hT32hajEg==", + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@cloudflare/vite-plugin/-/vite-plugin-1.39.0.tgz", + "integrity": "sha512-AHC+KSR+3dtGu7Ab7I0Ode4Whx12TxMEmiZt7w+Fc3/2wYNByIzbb6cndWZ78tnveFdO1xhNLv1YaNngxGtOPg==", "license": "MIT", "dependencies": { - "@cloudflare/unenv-preset": "2.16.0", - "miniflare": "4.20260410.0", + "@cloudflare/unenv-preset": "2.16.1", + "miniflare": "4.20260526.0", "unenv": "2.0.0-rc.24", - "wrangler": "4.82.2", - "ws": "8.18.0" + "wrangler": "4.95.0", + "ws": "8.20.1" }, "peerDependencies": { "vite": "^6.1.0 || ^7.0.0 || ^8.0.0", - "wrangler": "^4.82.2" + "wrangler": "^4.95.0" } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20260410.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260410.1.tgz", - "integrity": "sha512-0sh6xPmCKUfv/lUklP1dfyeKxCuEZGS0HeduxnucL8ECxSgAdWTOD42h/lQTwZCIiWtyHB+ZNB9hsS2Mlf0tMQ==", + "version": "1.20260526.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260526.1.tgz", + "integrity": "sha512-/pR3GH3gfv0PUp7DjI8v0aAIDOqFwibq4bg5xT7TZgcVdBV/cJQWckdXCMqiRtHiawLwogUX00EIOINkYJ1Zqg==", "cpu": [ "x64" ], @@ -477,9 +477,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20260410.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260410.1.tgz", - "integrity": "sha512-r2On29gPvlk/eiH/OpeUT23xoB8W8D1PHr8lul5nyxElLqvh3yNxZUnJWrbcOl+ubfrvw7+jFwgopMe17xyf0g==", + "version": "1.20260526.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260526.1.tgz", + "integrity": "sha512-rcyu0iANYfaiezKh3Mcao1O4IIgVfQldxduiL5TZT1sP0NIeRY4YReSTrzPxNnXxSYaIqaqRHMcHbUM/ic4knA==", "cpu": [ "arm64" ], @@ -493,9 +493,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20260410.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260410.1.tgz", - "integrity": "sha512-qWORRcAzPZeHJjrcYBNZTN6Y9l+iZQUz4KBdWbNrM6My4CpNrXS5kErPR373vG//5QPaDGwMXgBqyn9xfzarJQ==", + "version": "1.20260526.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260526.1.tgz", + "integrity": "sha512-5EZAEnlLwa9oGJRo8Nd3iY5Wcd9ROGNNG90xNIGp8MEjj8v2jTn42NC47fCZKFdnLj3+S+vWEhu1x0GVJnALjA==", "cpu": [ "x64" ], @@ -509,9 +509,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20260410.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260410.1.tgz", - "integrity": "sha512-jQfuHL4mnGDFyomSS3JNs9TpTvCu6Vzz2QSNCfJRstMzTICUFLMc4Vp/xKK+M5xkb0PoAu/G0hHx7jrxB2j+OQ==", + "version": "1.20260526.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260526.1.tgz", + "integrity": "sha512-X/YBQXeXFeCN7QTStoWrATEBc9WKl7PIqkw/dQkjyJ72gh3rkLe0+Xkzp3wO7gtxTDQMa7NPGy1W4+sdMf8q1g==", "cpu": [ "arm64" ], @@ -525,9 +525,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20260410.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260410.1.tgz", - "integrity": "sha512-h8q/nbheDqpknY7AAOz19MuQkZAR1/bnoZnKipyeUPXt5No+y6HlTtva9Bohx5Fhc1MW2CX2MQVdb55qtkkqZQ==", + "version": "1.20260526.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260526.1.tgz", + "integrity": "sha512-R+tqpFFdcfZIljx8fIW9rj9fRTtDgfoA2yonsfAGa6e8snrmr+38mdFHtkRC0D3UyZpn/hOtmXiUBfdX2gMR7Q==", "cpu": [ "x64" ], @@ -722,9 +722,9 @@ "license": "MIT" }, "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", "optional": true, "dependencies": { @@ -1524,6 +1524,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1540,6 +1543,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1556,6 +1562,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1572,6 +1581,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1588,6 +1600,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1604,6 +1619,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1620,6 +1638,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1636,6 +1657,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1652,6 +1676,9 @@ "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1674,6 +1701,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1696,6 +1726,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1718,6 +1751,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1740,6 +1776,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1762,6 +1801,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1784,6 +1826,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1806,6 +1851,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -3807,9 +3855,9 @@ "license": "MIT" }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.40.tgz", - "integrity": "sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { @@ -3819,7 +3867,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3833,7 +3880,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3847,7 +3893,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3861,7 +3906,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3875,7 +3919,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3889,7 +3932,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3903,7 +3945,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3917,7 +3958,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3931,7 +3971,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3945,7 +3984,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3959,7 +3997,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3973,7 +4010,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3987,7 +4023,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4001,7 +4036,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4015,7 +4049,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4029,7 +4062,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4043,7 +4075,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4057,7 +4088,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4071,7 +4101,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4085,7 +4114,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4099,7 +4127,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4113,7 +4140,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4127,7 +4153,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4141,7 +4166,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4155,7 +4179,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4243,27 +4266,6 @@ "node": ">=20.0.0" } }, - "node_modules/@supabase/realtime-js/node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@supabase/storage-js": { "version": "2.103.3", "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.103.3.tgz", @@ -4618,9 +4620,9 @@ } }, "node_modules/@tanstack/history": { - "version": "1.161.6", - "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.161.6.tgz", - "integrity": "sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg==", + "version": "1.162.0", + "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.162.0.tgz", + "integrity": "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==", "license": "MIT", "engines": { "node": ">=20.19" @@ -4657,14 +4659,14 @@ } }, "node_modules/@tanstack/react-router": { - "version": "1.168.21", - "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.168.21.tgz", - "integrity": "sha512-slnitYiHHmU52eMWtW8JbV9EMT5q6mRMbTA5yepBmJAnj5WZDrDRsLY/TuUrdD97A4W7/25tEQRoqc1G2X0oCw==", + "version": "1.170.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.170.8.tgz", + "integrity": "sha512-Qw2ju6jjnIsMpuW+VrnHZWHuugqs592PWsnI56sG28qNhg14CgRLahOcNajfuJR9P4MxKGP94WVzmFKSYUz/ig==", "license": "MIT", "dependencies": { - "@tanstack/history": "1.161.6", + "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", - "@tanstack/router-core": "1.168.15", + "@tanstack/router-core": "1.171.6", "isbot": "^5.1.22" }, "engines": { @@ -4680,24 +4682,21 @@ } }, "node_modules/@tanstack/react-start": { - "version": "1.167.39", - "resolved": "https://registry.npmjs.org/@tanstack/react-start/-/react-start-1.167.39.tgz", - "integrity": "sha512-57vpXGWhrisb69mgYBlEmpNvZCKYKix4jj4vqkiInCM4b97Y3SA8fwTPRXs7L/kEXGZCkCFzMR6EDiP15a3rWg==", + "version": "1.168.14", + "resolved": "https://registry.npmjs.org/@tanstack/react-start/-/react-start-1.168.14.tgz", + "integrity": "sha512-Y/CXqtufmZkUL6OCcxxDoGxDDnz/hqrYqCJQeiBHx4MUbn9mx3sZviFVDkFrsyi/8J+IKjXdV5LlNATAxHQzAQ==", "license": "MIT", "dependencies": { - "@tanstack/react-router": "1.168.21", - "@tanstack/react-start-client": "1.166.38", - "@tanstack/react-start-rsc": "0.0.18", - "@tanstack/react-start-server": "1.166.39", - "@tanstack/router-utils": "^1.161.6", - "@tanstack/start-client-core": "1.167.17", - "@tanstack/start-plugin-core": "1.167.34", - "@tanstack/start-server-core": "1.167.19", + "@tanstack/react-router": "1.170.8", + "@tanstack/react-start-client": "1.168.5", + "@tanstack/react-start-rsc": "0.1.13", + "@tanstack/react-start-server": "1.167.9", + "@tanstack/router-utils": "1.162.1", + "@tanstack/start-client-core": "1.170.4", + "@tanstack/start-plugin-core": "1.171.6", + "@tanstack/start-server-core": "1.169.4", "pathe": "^2.0.3" }, - "bin": { - "intent": "bin/intent.js" - }, "engines": { "node": ">=22.12.0" }, @@ -4706,25 +4705,32 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { + "@rsbuild/core": "^2.0.0", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0", "vite": ">=7.0.0" }, "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, "@vitejs/plugin-rsc": { "optional": true + }, + "vite": { + "optional": true } } }, "node_modules/@tanstack/react-start-client": { - "version": "1.166.38", - "resolved": "https://registry.npmjs.org/@tanstack/react-start-client/-/react-start-client-1.166.38.tgz", - "integrity": "sha512-TdJBwVxVePuZts7vQp432ZwqcdxTA0St2MFEurpdOC03FZPMN+eov8HdGsRcFCtoI+AeorPDO8LkZjfvL/afVQ==", + "version": "1.168.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-start-client/-/react-start-client-1.168.5.tgz", + "integrity": "sha512-xRAGDhb81kvJa9lkr5CLt66HVMJWGh1iPZL/AYO8/wnPdbwFbRKSv5Yzx5SI+YQbB0qTgcYCyOPi4jrscAppag==", "license": "MIT", "dependencies": { - "@tanstack/react-router": "1.168.21", - "@tanstack/router-core": "1.168.15", - "@tanstack/start-client-core": "1.167.17" + "@tanstack/react-router": "1.170.8", + "@tanstack/router-core": "1.171.6", + "@tanstack/start-client-core": "1.170.4" }, "engines": { "node": ">=22.12.0" @@ -4739,20 +4745,20 @@ } }, "node_modules/@tanstack/react-start-rsc": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/@tanstack/react-start-rsc/-/react-start-rsc-0.0.18.tgz", - "integrity": "sha512-ZCdi7TNAamn0yioK/6LJzHI24TXP6dyhal9DlLQkzJ9ss1CROFJSE6V5liWugadT3LVt2dN5Uu6xU9wEZ9wj4Q==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@tanstack/react-start-rsc/-/react-start-rsc-0.1.13.tgz", + "integrity": "sha512-nl5pKkxy1RnRxOLjy/c3g/RKdQSQYWzK5iuLlsRaO9TbLuMhQlNAn255xQgVXG56G9xCtDg8/nD0ZycxSlSkWA==", "license": "MIT", "dependencies": { - "@tanstack/react-router": "1.168.21", - "@tanstack/react-start-server": "1.166.39", - "@tanstack/router-core": "1.168.15", - "@tanstack/router-utils": "1.161.6", - "@tanstack/start-client-core": "1.167.17", - "@tanstack/start-fn-stubs": "1.161.6", - "@tanstack/start-plugin-core": "1.167.34", - "@tanstack/start-server-core": "1.167.19", - "@tanstack/start-storage-context": "1.166.29", + "@tanstack/react-router": "1.170.8", + "@tanstack/react-start-server": "1.167.9", + "@tanstack/router-core": "1.171.6", + "@tanstack/router-utils": "1.162.1", + "@tanstack/start-client-core": "1.170.4", + "@tanstack/start-fn-stubs": "1.162.0", + "@tanstack/start-plugin-core": "1.171.6", + "@tanstack/start-server-core": "1.169.4", + "@tanstack/start-storage-context": "1.167.8", "pathe": "^2.0.3" }, "engines": { @@ -4763,27 +4769,35 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { + "@rspack/core": ">=2.0.0-0", "@vitejs/plugin-rsc": ">=0.5.20", "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0" + "react-dom": ">=18.0.0 || >=19.0.0", + "react-server-dom-rspack": ">=0.0.2" }, "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, "@vitejs/plugin-rsc": { "optional": true + }, + "react-server-dom-rspack": { + "optional": true } } }, "node_modules/@tanstack/react-start-server": { - "version": "1.166.39", - "resolved": "https://registry.npmjs.org/@tanstack/react-start-server/-/react-start-server-1.166.39.tgz", - "integrity": "sha512-4IVUck079SgT9GywpqIxnk8Xt7GxPfiGjaNiLKwpGrcl5Ui5Zd4N/bbVsOPlwTM7NR1yZX2IsBzDGOjmi9SWcA==", + "version": "1.167.9", + "resolved": "https://registry.npmjs.org/@tanstack/react-start-server/-/react-start-server-1.167.9.tgz", + "integrity": "sha512-a1SGeeoIEg411vEN6DThB2Bm5tiYBb0tCC/RaG8BSjRVtsY6kxD9cP1+LOpZwjRSgfdyqtSbe1v78ZDB9z0/uw==", "license": "MIT", "dependencies": { - "@tanstack/history": "1.161.6", - "@tanstack/react-router": "1.168.21", - "@tanstack/router-core": "1.168.15", - "@tanstack/start-client-core": "1.167.17", - "@tanstack/start-server-core": "1.167.19" + "@tanstack/history": "1.162.0", + "@tanstack/react-router": "1.170.8", + "@tanstack/router-core": "1.171.6", + "@tanstack/start-client-core": "1.170.4", + "@tanstack/start-server-core": "1.169.4" }, "engines": { "node": ">=22.12.0" @@ -4816,18 +4830,15 @@ } }, "node_modules/@tanstack/router-core": { - "version": "1.168.15", - "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.168.15.tgz", - "integrity": "sha512-Wr0424NDtD8fT/uALobMZ9DdcfsTyXtW5IPR++7zvW8/7RaIOeaqXpVDId8ywaGtqPWLWOfaUg2zUtYtukoXYA==", + "version": "1.171.6", + "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.171.6.tgz", + "integrity": "sha512-Ol6DQ+j6rf/rPVELIzo8LHwOQV2KL+zry3b+39kL/GKrt7YId52WJRAFMzuseY4XceSW+PU7sG/Cc1QkwJr0hg==", "license": "MIT", "dependencies": { - "@tanstack/history": "1.161.6", + "@tanstack/history": "1.162.0", "cookie-es": "^3.0.0", - "seroval": "^1.5.0", - "seroval-plugins": "^1.5.0" - }, - "bin": { - "intent": "bin/intent.js" + "seroval": "^1.5.4", + "seroval-plugins": "^1.5.4" }, "engines": { "node": ">=20.19" @@ -4838,19 +4849,19 @@ } }, "node_modules/@tanstack/router-generator": { - "version": "1.166.32", - "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.166.32.tgz", - "integrity": "sha512-VuusKwEXcgKq+myq1JQfZogY8scTXIIeFls50dJ/UXgCXWp5n14iFreYNlg41wURcak2oA3M+t2TVfD0xUUD6g==", + "version": "1.167.10", + "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.167.10.tgz", + "integrity": "sha512-CjbjWRSo6djLU/C7ncb9IbKUcf4IwpdqhLGngkwKkXaVFXGxEAafA/uhvOCv/UEUVR7NI3tJqqQmxYXGcJPbjw==", "license": "MIT", "dependencies": { "@babel/types": "^7.28.5", - "@tanstack/router-core": "1.168.15", - "@tanstack/router-utils": "1.161.6", - "@tanstack/virtual-file-routes": "1.161.7", + "@tanstack/router-core": "1.171.6", + "@tanstack/router-utils": "1.162.1", + "@tanstack/virtual-file-routes": "1.162.0", + "jiti": "^2.7.0", "magic-string": "^0.30.21", "prettier": "^3.5.0", - "tsx": "^4.19.2", - "zod": "^3.24.2" + "zod": "^4.4.3" }, "engines": { "node": ">=20.19" @@ -4861,18 +4872,18 @@ } }, "node_modules/@tanstack/router-generator/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/@tanstack/router-plugin": { - "version": "1.167.22", - "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.167.22.tgz", - "integrity": "sha512-wYPzIvBK8bcmXVUpZfSgGBXOrfBAdF4odKevz6rejio5rEd947NtKDF5R7eYdwlAOmRqYpLJnJ1QHkc5t8bY4w==", + "version": "1.168.11", + "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.11.tgz", + "integrity": "sha512-b2eom/8xCWL/OiWxKub8kYsr8p+kvmB/eXwYGqCWG8vilcJo+eQCSyp54nKt0AZ5k/ET1+eINc+4mwL3bVeAgg==", "license": "MIT", "dependencies": { "@babel/core": "^7.28.5", @@ -4881,16 +4892,13 @@ "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", - "@tanstack/router-core": "1.168.15", - "@tanstack/router-generator": "1.166.32", - "@tanstack/router-utils": "1.161.6", - "@tanstack/virtual-file-routes": "1.161.7", - "chokidar": "^3.6.0", - "unplugin": "^2.1.2", - "zod": "^3.24.2" - }, - "bin": { - "intent": "bin/intent.js" + "@tanstack/router-core": "1.171.6", + "@tanstack/router-generator": "1.167.10", + "@tanstack/router-utils": "1.162.1", + "@tanstack/virtual-file-routes": "1.162.0", + "chokidar": "^5.0.0", + "unplugin": "^3.0.0", + "zod": "^4.4.3" }, "engines": { "node": ">=20.19" @@ -4900,8 +4908,8 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@rsbuild/core": ">=1.0.2", - "@tanstack/react-router": "^1.168.21", + "@rsbuild/core": ">=1.0.2 || ^2.0.0", + "@tanstack/react-router": "^1.170.8", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", "webpack": ">=5.92.0" @@ -4924,19 +4932,47 @@ } } }, + "node_modules/@tanstack/router-plugin/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@tanstack/router-plugin/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@tanstack/router-plugin/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/@tanstack/router-utils": { - "version": "1.161.6", - "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.161.6.tgz", - "integrity": "sha512-nRcYw+w2OEgK6VfjirYvGyPLOK+tZQz1jkYcmH5AjMamQ9PycnlxZF2aEZtPpNoUsaceX2bHptn6Ub5hGXqNvw==", + "version": "1.162.1", + "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.162.1.tgz", + "integrity": "sha512-62layyTGmclHDQS/eidwKRfN1hhCKwViG7iEBcVmL0MXgcAB3OOucWCEcDDGd9Cu11H6b4QQ5oOo47MWIqwz0A==", "license": "MIT", "dependencies": { "@babel/core": "^7.28.5", @@ -4958,18 +4994,15 @@ } }, "node_modules/@tanstack/start-client-core": { - "version": "1.167.17", - "resolved": "https://registry.npmjs.org/@tanstack/start-client-core/-/start-client-core-1.167.17.tgz", - "integrity": "sha512-3ZnpQ0LPnhrm/GX+HT7XfRxTcqnmBE1KJd7LtaJNuN13NH0C4ZOWchKLPEed2/gluhgsT6UgWm+Ec0kEFtxSaw==", + "version": "1.170.4", + "resolved": "https://registry.npmjs.org/@tanstack/start-client-core/-/start-client-core-1.170.4.tgz", + "integrity": "sha512-j/Deupf0zR7P5QObN38xTHufCRZkWTb6a/7aauu8eBmzOzDVggvuEdYHRZWiwJ9HRKbR2/SIJASVKeTtj1OcWw==", "license": "MIT", "dependencies": { - "@tanstack/router-core": "1.168.15", - "@tanstack/start-fn-stubs": "1.161.6", - "@tanstack/start-storage-context": "1.166.29", - "seroval": "^1.5.0" - }, - "bin": { - "intent": "bin/intent.js" + "@tanstack/router-core": "1.171.6", + "@tanstack/start-fn-stubs": "1.162.0", + "@tanstack/start-storage-context": "1.167.8", + "seroval": "^1.5.4" }, "engines": { "node": ">=22.12.0" @@ -4980,9 +5013,9 @@ } }, "node_modules/@tanstack/start-fn-stubs": { - "version": "1.161.6", - "resolved": "https://registry.npmjs.org/@tanstack/start-fn-stubs/-/start-fn-stubs-1.161.6.tgz", - "integrity": "sha512-Y6QSlGiLga8cHfvxGGaonXIlt2bIUTVdH6AMjmpMp7+ANNCp+N96GQbjjhLye3JkaxDfP68x5iZA8NK4imgRig==", + "version": "1.162.0", + "resolved": "https://registry.npmjs.org/@tanstack/start-fn-stubs/-/start-fn-stubs-1.162.0.tgz", + "integrity": "sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==", "license": "MIT", "engines": { "node": ">=22.12.0" @@ -4993,33 +5026,33 @@ } }, "node_modules/@tanstack/start-plugin-core": { - "version": "1.167.34", - "resolved": "https://registry.npmjs.org/@tanstack/start-plugin-core/-/start-plugin-core-1.167.34.tgz", - "integrity": "sha512-uBUAPvdZNNVXRiradfE60hmsfBBYUMDyqZiwlBRipT1FKu2k//UX8zImi3y6rvIYVWRPKMgYeOewAghXc3OJcA==", + "version": "1.171.6", + "resolved": "https://registry.npmjs.org/@tanstack/start-plugin-core/-/start-plugin-core-1.171.6.tgz", + "integrity": "sha512-e0AUN+omib0qLgs0r3zoKRSeHEkwL8qs8skvbl8zgDQXw9zF73K7ZXE7QarSzbqfLAiehVqlv0iPETp8ogUftQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "7.27.1", "@babel/core": "^7.28.5", "@babel/types": "^7.28.5", - "@rolldown/pluginutils": "1.0.0-beta.40", - "@tanstack/router-core": "1.168.15", - "@tanstack/router-generator": "1.166.32", - "@tanstack/router-plugin": "1.167.22", - "@tanstack/router-utils": "1.161.6", - "@tanstack/start-client-core": "1.167.17", - "@tanstack/start-server-core": "1.167.19", - "cheerio": "^1.0.0", + "@rolldown/pluginutils": "1.0.1", + "@tanstack/router-core": "1.171.6", + "@tanstack/router-generator": "1.167.10", + "@tanstack/router-plugin": "1.168.11", + "@tanstack/router-utils": "1.162.1", + "@tanstack/start-client-core": "1.170.4", + "@tanstack/start-server-core": "1.169.4", "exsolve": "^1.0.7", + "lightningcss": "^1.32.0", "pathe": "^2.0.3", "picomatch": "^4.0.3", - "seroval": "^1.5.0", + "seroval": "^1.5.4", "source-map": "^0.7.6", "srvx": "^0.11.9", "tinyglobby": "^0.2.15", "ufo": "^1.5.4", "vitefu": "^1.1.1", "xmlbuilder2": "^4.0.3", - "zod": "^3.24.2" + "zod": "^4.4.3" }, "engines": { "node": ">=22.12.0" @@ -5029,7 +5062,16 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { + "@rsbuild/core": "^2.0.0", "vite": ">=7.0.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, + "vite": { + "optional": true + } } }, "node_modules/@tanstack/start-plugin-core/node_modules/@babel/code-frame": { @@ -5047,29 +5089,27 @@ } }, "node_modules/@tanstack/start-plugin-core/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/@tanstack/start-server-core": { - "version": "1.167.19", - "resolved": "https://registry.npmjs.org/@tanstack/start-server-core/-/start-server-core-1.167.19.tgz", - "integrity": "sha512-wzOdfzLsK91CnjoywnEjXSlVlaRVK99HJhyVijNU1TECBI2JEKvW9S6d14YfS4gD4fFH4V86tFYhkcLPe6nzWg==", + "version": "1.169.4", + "resolved": "https://registry.npmjs.org/@tanstack/start-server-core/-/start-server-core-1.169.4.tgz", + "integrity": "sha512-iM3HamWRQPROuAb+22frV/+GkqG2a3rL0X14N+Y0Dt5OajrIumPuprOn9ldUXsbdg89RTBf1KoJNDPeYGOqH4g==", "license": "MIT", "dependencies": { - "@tanstack/history": "1.161.6", - "@tanstack/router-core": "1.168.15", - "@tanstack/start-client-core": "1.167.17", - "@tanstack/start-storage-context": "1.166.29", + "@tanstack/history": "1.162.0", + "@tanstack/router-core": "1.171.6", + "@tanstack/start-client-core": "1.170.4", + "@tanstack/start-storage-context": "1.167.8", + "fetchdts": "^0.1.6", "h3-v2": "npm:h3@2.0.1-rc.20", - "seroval": "^1.5.0" - }, - "bin": { - "intent": "bin/intent.js" + "seroval": "^1.5.4" }, "engines": { "node": ">=22.12.0" @@ -5080,12 +5120,12 @@ } }, "node_modules/@tanstack/start-storage-context": { - "version": "1.166.29", - "resolved": "https://registry.npmjs.org/@tanstack/start-storage-context/-/start-storage-context-1.166.29.tgz", - "integrity": "sha512-KrJYudc1nbnTY43jdN+hQFMYkhz7+3T+hkgBoGnIP1OspSe6vGQaYGDB4EUXYnkLfyQp+iUuKubgS8hSKeJ0ng==", + "version": "1.167.8", + "resolved": "https://registry.npmjs.org/@tanstack/start-storage-context/-/start-storage-context-1.167.8.tgz", + "integrity": "sha512-y9T+bIIp1ihLAXyS2+r+UovSupfu4KydSXpnoeRsw/14/E0huJsX7xB/n6XXOdmDYAaJ2WGOrG9wYjzeIDuBAw==", "license": "MIT", "dependencies": { - "@tanstack/router-core": "1.168.15" + "@tanstack/router-core": "1.171.6" }, "engines": { "node": ">=22.12.0" @@ -5106,13 +5146,10 @@ } }, "node_modules/@tanstack/virtual-file-routes": { - "version": "1.161.7", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.161.7.tgz", - "integrity": "sha512-olW33+Cn+bsCsZKPwEGhlkqS6w3M2slFv11JIobdnCFKMLG97oAI2kWKdx5/zsywTL8flpnoIgaZZPlQTFYhdQ==", + "version": "1.162.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.162.0.tgz", + "integrity": "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==", "license": "MIT", - "bin": { - "intent": "bin/intent.js" - }, "engines": { "node": ">=20.19" }, @@ -5314,7 +5351,6 @@ "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -5324,7 +5360,7 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -5544,9 +5580,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -5731,6 +5767,7 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -5802,6 +5839,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -5815,6 +5853,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -5893,6 +5932,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5907,12 +5947,6 @@ "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", "license": "MIT" }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "license": "ISC" - }, "node_modules/brace-expansion": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", @@ -5928,6 +5962,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -6076,52 +6111,11 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/cheerio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", - "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", - "license": "MIT", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "encoding-sniffer": "^0.2.1", - "htmlparser2": "^10.1.0", - "parse5": "^7.3.0", - "parse5-htmlparser2-tree-adapter": "^7.1.0", - "parse5-parser-stream": "^7.1.2", - "undici": "^7.19.0", - "whatwg-mimetype": "^4.0.0" - }, - "engines": { - "node": ">=20.18.1" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -6298,34 +6292,6 @@ "node": ">= 8" } }, - "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -6595,61 +6561,6 @@ "csstype": "^3.0.2" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.336", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.336.tgz", @@ -6684,19 +6595,6 @@ "embla-carousel": "8.6.0" } }, - "node_modules/encoding-sniffer": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", - "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", - "license": "MIT", - "dependencies": { - "iconv-lite": "^0.6.3", - "whatwg-encoding": "^3.1.1" - }, - "funding": { - "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" - } - }, "node_modules/enhanced-resolve": { "version": "5.20.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", @@ -6710,18 +6608,6 @@ "node": ">=10.13.0" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/error-stack-parser-es": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", @@ -7151,6 +7037,12 @@ } } }, + "node_modules/fetchdts": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.7.tgz", + "integrity": "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==", + "license": "MIT" + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -7168,6 +7060,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -7283,22 +7176,11 @@ "node": ">=6" } }, - "node_modules/get-tsconfig": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -7430,37 +7312,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/htmlparser2": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", - "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "entities": "^7.0.1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/iceberg-js": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", @@ -7470,18 +7321,6 @@ "node": ">=20.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -7584,6 +7423,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -7622,6 +7462,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7631,6 +7472,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -7653,6 +7495,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -7687,9 +7530,9 @@ "license": "ISC" }, "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -9106,32 +8949,23 @@ } }, "node_modules/miniflare": { - "version": "4.20260410.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260410.0.tgz", - "integrity": "sha512-94LEU8d+XPVGp18eW4+bu1v7Tnq7srhqWMIsrx2jhSkdbTnGqg1I613R0GKY4eygBYl9MbqXEhzK/bczJb6uMg==", + "version": "4.20260526.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260526.0.tgz", + "integrity": "sha512-JYQ7jPZZWoaaj9jWHb8Ucp6Cu2SbDVqIsAJhumqdzzLkkfq0pYkDeino/sZfW1ixJWPjv/C44zjm9gVJC2izCA==", "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", - "undici": "7.24.4", - "workerd": "1.20260410.1", - "ws": "8.18.0", + "undici": "7.24.8", + "workerd": "1.20260526.1", + "ws": "8.20.1", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" }, "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/miniflare/node_modules/undici": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", - "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", - "license": "MIT", - "engines": { - "node": ">=20.18.1" + "node": ">=22.0.0" } }, "node_modules/minimatch": { @@ -9181,10 +9015,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -9216,23 +9049,12 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -9340,55 +9162,6 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", - "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", - "license": "MIT", - "dependencies": { - "domhandler": "^5.0.3", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-parser-stream": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", - "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", - "license": "MIT", - "dependencies": { - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9467,10 +9240,9 @@ } }, "node_modules/postcss": { - "version": "8.5.9", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", - "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", - "dev": true, + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -9487,7 +9259,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -9967,6 +9739,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -9979,6 +9752,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -10117,15 +9891,6 @@ "node": ">=4" } }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -10141,7 +9906,6 @@ "version": "4.60.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -10182,6 +9946,62 @@ "fsevents": "~2.3.2" } }, + "node_modules/rosie-skills": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/rosie-skills/-/rosie-skills-0.6.4.tgz", + "integrity": "sha512-ojfhSiQRdZ2QyWbmKAHOSAUbaLYrTc5zIH7mS1jKoP8KCFSQddwVhMyFqldckTeybTfW3zNcsZzyOTzGTN1SBA==", + "license": "BSD-3-Clause", + "bin": { + "rosie-skills": "dist/bin.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "rosie-skills-darwin-arm64": "0.6.4", + "rosie-skills-freebsd-x64": "0.6.4", + "rosie-skills-linux-x64": "0.6.4" + } + }, + "node_modules/rosie-skills-darwin-arm64": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/rosie-skills-darwin-arm64/-/rosie-skills-darwin-arm64-0.6.4.tgz", + "integrity": "sha512-rn1s5hqFKcxeiDEWWoFa1hdGPshR8TkwHLzy/cBavb9XJNAaUxbe3oQ78W9sQkRHAgRyzJYyk9tw68Qrdnizgg==", + "cpu": [ + "arm64" + ], + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/rosie-skills-freebsd-x64": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/rosie-skills-freebsd-x64/-/rosie-skills-freebsd-x64-0.6.4.tgz", + "integrity": "sha512-SxCRduPBMtfjkQ+q56Yw9OLA3PyaqoALzt7kER7IDKuUVfM2O/1w8sa5xhTDiCvWkZJixnH5d5Ya6KT+/Mwcng==", + "cpu": [ + "x64" + ], + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/rosie-skills-linux-x64": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/rosie-skills-linux-x64/-/rosie-skills-linux-x64-0.6.4.tgz", + "integrity": "sha512-D9Y9mfu7goB0s0X59uU3hcFeUTef3VbpCIDwFMzyvJrAq3XhRACWBDMHQsHlyWdHxTXPX/ILyW65RXyrJlgqng==", + "cpu": [ + "x64" + ], + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/rou3": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.8.1.tgz", @@ -10212,12 +10032,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -10234,18 +10048,18 @@ } }, "node_modules/seroval": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.2.tgz", - "integrity": "sha512-xcRN39BdsnO9Tf+VzsE7b3JyTJASItIV1FVFewJKCFcW4s4haIKS3e6vj8PGB9qBwC7tnuOywQMdv5N4qkzi7Q==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.4.tgz", + "integrity": "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==", "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/seroval-plugins": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.2.tgz", - "integrity": "sha512-qpY0Cl+fKYFn4GOf3cMiq6l72CpuVaawb6ILjubOQ+diJ54LfOWaSSPsaswN8DRPIPW4Yq+tE1k5aKd7ILyaFg==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.4.tgz", + "integrity": "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==", "license": "MIT", "engines": { "node": ">=10" @@ -10299,9 +10113,9 @@ } }, "node_modules/sharp/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -10372,9 +10186,9 @@ } }, "node_modules/srvx": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.15.tgz", - "integrity": "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==", + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.16.tgz", + "integrity": "sha512-bp07zRuycfTY43IjAvvTFnmnJi8ikW0VFiHwOhhYcVW/L4xQ1XY4PAd4Nuum1rsA17C39zL7x+CDhrn5AL32Rw==", "license": "MIT", "bin": { "srvx": "bin/srvx.mjs" @@ -10577,6 +10391,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -10651,482 +10466,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "license": "MIT", - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" - } - }, "node_modules/tw-animate-css": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", @@ -11153,7 +10492,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -11188,15 +10527,15 @@ } }, "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", "license": "MIT" }, "node_modules/undici": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", - "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz", + "integrity": "sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==", "license": "MIT", "engines": { "node": ">=20.18.1" @@ -11305,18 +10644,17 @@ } }, "node_modules/unplugin": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", - "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", - "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" }, "engines": { - "node": ">=18.12.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/update-browserslist-db": { @@ -11485,7 +10823,6 @@ "version": "7.3.2", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.27.0", @@ -11577,7 +10914,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11594,7 +10930,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11611,7 +10946,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11628,7 +10962,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11645,7 +10978,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11662,7 +10994,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11679,7 +11010,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11696,7 +11026,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11713,7 +11042,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11730,7 +11058,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11747,7 +11074,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11764,7 +11090,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11781,7 +11106,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11798,7 +11122,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11815,7 +11138,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11832,7 +11154,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11849,7 +11170,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11866,7 +11186,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11883,7 +11202,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11900,7 +11218,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11917,7 +11234,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11934,7 +11250,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11951,7 +11266,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11968,7 +11282,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11985,7 +11298,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12002,7 +11314,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12016,7 +11327,6 @@ "version": "0.27.7", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", - "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -12085,28 +11395,6 @@ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "license": "MIT" }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -12134,9 +11422,9 @@ } }, "node_modules/workerd": { - "version": "1.20260410.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260410.1.tgz", - "integrity": "sha512-T/GRD6Y5vN9g4CnGmOlfST1w7bj+1IjRFvX0K7CodZPJuPVPNPGhz8Wppah0WdT6A7I8Kad3zgZ2OkDdWtENrg==", + "version": "1.20260526.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260526.1.tgz", + "integrity": "sha512-IHzymht98p10JH1zzwdCpbViAqw97HrwKl7+KfZeASFMsYSrIsAULWdPn0LRC5FTUzBpamLNyKCCKxbgXHgRHQ==", "hasInstallScript": true, "license": "Apache-2.0", "bin": { @@ -12146,40 +11434,41 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20260410.1", - "@cloudflare/workerd-darwin-arm64": "1.20260410.1", - "@cloudflare/workerd-linux-64": "1.20260410.1", - "@cloudflare/workerd-linux-arm64": "1.20260410.1", - "@cloudflare/workerd-windows-64": "1.20260410.1" + "@cloudflare/workerd-darwin-64": "1.20260526.1", + "@cloudflare/workerd-darwin-arm64": "1.20260526.1", + "@cloudflare/workerd-linux-64": "1.20260526.1", + "@cloudflare/workerd-linux-arm64": "1.20260526.1", + "@cloudflare/workerd-windows-64": "1.20260526.1" } }, "node_modules/wrangler": { - "version": "4.82.2", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.82.2.tgz", - "integrity": "sha512-SKfW21sTJUkM/Qd8zc9oc8TBkAWHRsXuTxE6XdToC55Ct84pR+IfRdaTjCTuC0dL+KYvauSvSn2rtqS2Ae+Dcw==", + "version": "4.95.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.95.0.tgz", + "integrity": "sha512-vgXzFVSCdUbeCadgVXvu8fK5tzNm8T9W+7lriyGWZMx0B1+CAdr4d8JTlZszHfgjypRAHmAxb49etZGIRD9pgg==", "license": "MIT OR Apache-2.0", "dependencies": { - "@cloudflare/kv-asset-handler": "0.4.2", - "@cloudflare/unenv-preset": "2.16.0", + "@cloudflare/kv-asset-handler": "0.5.0", + "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", "esbuild": "0.27.3", - "miniflare": "4.20260410.0", + "miniflare": "4.20260526.0", "path-to-regexp": "6.3.0", + "rosie-skills": "^0.6.3", "unenv": "2.0.0-rc.24", - "workerd": "1.20260410.1" + "workerd": "1.20260526.1" }, "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" }, "engines": { - "node": ">=20.3.0" + "node": ">=22.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20260410.1" + "@cloudflare/workers-types": "^4.20260526.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -12645,9 +11934,9 @@ } }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -12723,9 +12012,9 @@ } }, "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 3fd7c78..d2e6b10 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "tw-animate-css": "^1.3.4", "vaul": "^1.1.2", "vite-tsconfig-paths": "^6.0.2", - "zod": "^4.3.6" + "zod": "^3.25.76" }, "devDependencies": { "@eslint/js": "^9.32.0", diff --git a/src/components/mika/cronjobs/CronjobWizard.tsx b/src/components/mika/cronjobs/CronjobWizard.tsx index 5b8aff8..0f661e1 100644 --- a/src/components/mika/cronjobs/CronjobWizard.tsx +++ b/src/components/mika/cronjobs/CronjobWizard.tsx @@ -11,7 +11,7 @@ import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { invokeFunction } from "@/lib/invoke-function"; import { syncAgentRuntime } from "@/lib/sync-agent-runtime"; -import { useCreateCronjob } from "@/hooks/use-cronjobs"; +import { markCronjobRuntimeSyncError, useCreateCronjob } from "@/hooks/use-cronjobs"; import { useAvailableMcps, useUserIntegrations } from "@/hooks/use-integrations"; import { useAgentInstance } from "@/hooks/use-agent-instance"; import { useProfile } from "@/hooks/use-profile"; @@ -54,9 +54,12 @@ export function CronjobWizard({ onCreated, onCancel }: Props) { const { data: integrations = [] } = useUserIntegrations(); const createMut = useCreateCronjob(); - const tz = profile && "timezone" in profile && typeof (profile as { timezone?: string }).timezone === "string" - ? (profile as { timezone: string }).timezone - : "America/Sao_Paulo"; + const tz = + profile && + "timezone" in profile && + typeof (profile as { timezone?: string }).timezone === "string" + ? (profile as { timezone: string }).timezone + : "America/Sao_Paulo"; const mcpsBySlug = useMemo(() => { const m = new Map(); @@ -83,10 +86,10 @@ export function CronjobWizard({ onCreated, onCancel }: Props) { return; } setParsing(true); - const { data, error } = await invokeFunction( - "parse-cronjob-natural-language", - { natural_language_input: trimmed, user_timezone: tz }, - ); + const { data, error } = await invokeFunction("parse-cronjob-natural-language", { + natural_language_input: trimmed, + user_timezone: tz, + }); setParsing(false); if (error || !data) { toast.error(error?.message ?? "Não conseguimos interpretar. Tente reescrever."); @@ -131,11 +134,14 @@ export function CronjobWizard({ onCreated, onCancel }: Props) { timezone: tz, next_run_at: parsed?.next_run_at ?? null, }); - toast.success("Automação criada!"); - const { error: syncError } = await syncAgentRuntime(agent.id, "cronjobs"); if (syncError) { - toast.warning("Automação criada, mas o runtime do agente não sincronizou."); + await markCronjobRuntimeSyncError(job.id, syncError.message); + toast.error("Automação criada, mas não foi ativada no agente.", { + description: "Corrija o runtime e tente sincronizar novamente pelo painel.", + }); + } else { + toast.success("Automação criada e sincronizada!"); } onCreated?.(job.id); @@ -208,26 +214,29 @@ export function CronjobWizard({ onCreated, onCancel }: Props) { parsed.confidence === "high" ? "success" : parsed.confidence === "medium" - ? "secondary" - : "destructive"; + ? "secondary" + : "destructive"; return (

Revisar interpretação

- Confiança: {parsed.confidence === "high" ? "alta" : parsed.confidence === "medium" ? "média" : "baixa"} + Confiança:{" "} + {parsed.confidence === "high" + ? "alta" + : parsed.confidence === "medium" + ? "média" + : "baixa"}
{parsed.warnings.length > 0 && ( -
+
- +
-

- Suposições da IA — confira: -

+

Suposições da IA — confira:

    {parsed.warnings.map((w, i) => (
  • {w}
  • @@ -317,7 +326,11 @@ export function CronjobWizard({ onCreated, onCancel }: Props) { variant={connected ? "success" : "destructive"} className="gap-1" > - {connected ? : } + {connected ? ( + + ) : ( + + )} {mcp?.name ?? slug} {!connected && " (não conectado)"} @@ -331,7 +344,9 @@ export function CronjobWizard({ onCreated, onCancel }: Props) { Conecte as integrações faltantes antes de criar.

)} @@ -351,11 +366,7 @@ export function CronjobWizard({ onCreated, onCancel }: Props) {
- @@ -103,8 +95,8 @@ export function StepWaiting({ agentInstanceId, botUsername, connectedAt, onFinis

🎉 Mika conectado!

- Você recebeu a primeira resposta do seu agente. Ele ainda está em modo de teste, - mas em breve vai responder de verdade. + Você recebeu a primeira resposta do seu agente. Ele ainda está em modo de teste, mas + em breve vai responder de verdade.

-

- Você ainda não conectou {mcp.name}. -

+

Você ainda não conectou {mcp.name}.

@@ -248,9 +248,7 @@ function IntegrationDetailPage() { className="flex items-center justify-between text-sm border-b border-border last:border-0 pb-2 last:pb-0" > {j.name} - - {j.status} - + {j.status} ))} @@ -271,25 +269,20 @@ function IntegrationDetailPage() { {(status === "expired" || status === "revoked" || status === "error") && ( )} -
@@ -300,14 +293,12 @@ function IntegrationDetailPage() { setDisconnectOpen(o); if (!o) { // se desconectou, volta para a lista - queryClient - .invalidateQueries({ queryKey: ["user-integrations"] }) - .then(() => { - const stillConnected = integs.some((i) => i.id === integration.id); - if (!stillConnected) { - navigate({ to: "/painel/integracoes", search: {} }); - } - }); + queryClient.invalidateQueries({ queryKey: ["user-integrations"] }).then(() => { + const stillConnected = integs.some((i) => i.id === integration.id); + if (!stillConnected) { + navigate({ to: "/painel/integracoes", search: {} }); + } + }); } }} integrationId={integration.id} diff --git a/supabase/config.toml b/supabase/config.toml index 2983681..cc369ce 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -60,3 +60,5 @@ verify_jwt = false [functions.create-cronjob-from-agent] verify_jwt = false +[functions.create-skill-from-agent] +verify_jwt = false diff --git a/supabase/functions/_shared/default-skills.ts b/supabase/functions/_shared/default-skills.ts new file mode 100644 index 0000000..74ec5e9 --- /dev/null +++ b/supabase/functions/_shared/default-skills.ts @@ -0,0 +1,301 @@ +import type { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.4"; + +type GenericTable = { + Row: Record; + Insert: Record; + Update: Record; + Relationships: []; +}; + +type GenericDatabase = { + public: { + Tables: Record; + Views: Record; + Functions: Record; Returns: unknown }>; + }; +}; + +type SupabaseAdminClient = ReturnType>; + +export interface DefaultSkillsEnsureResult { + agent_instance_id: string; + created_count: number; + skipped_count: number; + errors: string[]; +} + +interface DefaultSkillTemplate { + name: string; + description: string; + trigger_keywords: string; + form_inputs: Record; + markdown_content: string; +} + +const DEFAULT_HERMES_SKILLS: DefaultSkillTemplate[] = [ + { + name: "Resumo diario", + description: "Gera um resumo curto do dia com compromissos, tarefas e proximas prioridades.", + trigger_keywords: "resumo diario, resumo do dia, briefing diario, revisar dia", + form_inputs: { + name: "Resumo diario", + description: "Gera um resumo curto do dia com compromissos, tarefas e proximas prioridades.", + trigger_keywords: "resumo diario, resumo do dia, briefing diario, revisar dia", + expected_inputs: "Periodo desejado e ferramentas conectadas, quando houver.", + steps: "Consolidar agenda, tarefas e pontos pendentes. Apontar prioridades e riscos.", + required_tools: ["calendar_optional", "tasks_optional", "notes_optional"], + success_criteria: "Usuario recebe um resumo acionavel e curto.", + example_use_case: "Me manda meu resumo diario as 8h.", + }, + markdown_content: `--- +name: Resumo diario +description: Gera um resumo curto do dia com compromissos, tarefas e proximas prioridades. +trigger_keywords: resumo diario, resumo do dia, briefing diario, revisar dia +--- + +## Quando usar + +Use quando o usuario pedir um resumo do dia, briefing, revisao diaria ou preparacao rapida para comecar/encerrar o expediente. + +## Inputs esperados + +- Periodo desejado, se o usuario informar. +- Ferramentas conectadas relevantes, como agenda, tarefas ou notas. + +## Passo a passo + +1. Identifique o periodo solicitado. Se nao houver periodo, use hoje no fuso do usuario. +2. Consulte agenda, tarefas e notas quando essas integracoes estiverem disponiveis. +3. Organize a resposta em compromissos, tarefas importantes, pendencias e sugestao de foco. +4. Se uma integracao necessaria nao estiver conectada, explique isso de forma curta e ofereca um resumo com o contexto disponivel. + +## Ferramentas necessarias + +- Calendar opcional. +- Tasks opcional. +- Notes opcional. + +## Criterio de sucesso + +O usuario recebe um resumo curto, confiavel e acionavel, sem inventar dados ausentes. + +## Exemplo + +"Me manda meu resumo diario as 8h."`, + }, + { + name: "Planejamento semanal", + description: + "Ajuda o usuario a transformar objetivos da semana em prioridades e proximas acoes.", + trigger_keywords: + "planejar semana, planejamento semanal, prioridades da semana, organizar semana", + form_inputs: { + name: "Planejamento semanal", + description: + "Ajuda o usuario a transformar objetivos da semana em prioridades e proximas acoes.", + trigger_keywords: + "planejar semana, planejamento semanal, prioridades da semana, organizar semana", + expected_inputs: "Objetivos, restricoes e contexto da semana.", + steps: "Levantar objetivos, quebrar em acoes, priorizar e sugerir agenda.", + required_tools: ["calendar_optional", "tasks_optional"], + success_criteria: "Usuario sai com prioridades e proximas acoes claras.", + example_use_case: "Me ajuda a planejar minha semana.", + }, + markdown_content: `--- +name: Planejamento semanal +description: Ajuda o usuario a transformar objetivos da semana em prioridades e proximas acoes. +trigger_keywords: planejar semana, planejamento semanal, prioridades da semana, organizar semana +--- + +## Quando usar + +Use quando o usuario pedir ajuda para planejar a semana, organizar prioridades, distribuir tarefas ou revisar foco semanal. + +## Inputs esperados + +- Objetivos da semana. +- Prazos, reunioes ou restricoes conhecidas. +- Tarefas pendentes, se houver integracao disponivel. + +## Passo a passo + +1. Liste os objetivos principais mencionados pelo usuario. +2. Quebre cada objetivo em proximas acoes pequenas. +3. Sugira uma ordem de prioridade realista. +4. Se houver agenda conectada, proponha blocos de foco sem assumir disponibilidade que nao foi verificada. +5. Termine com um plano curto e facil de revisar. + +## Ferramentas necessarias + +- Calendar opcional. +- Tasks opcional. + +## Criterio de sucesso + +O usuario recebe prioridades claras, proximas acoes e uma sugestao de distribuicao da semana. + +## Exemplo + +"Me ajuda a planejar minha semana."`, + }, + { + name: "Preparar reuniao", + description: + "Monta um briefing rapido antes de reunioes com contexto, pauta e perguntas uteis.", + trigger_keywords: "preparar reuniao, briefing de reuniao, pauta de reuniao, antes da reuniao", + form_inputs: { + name: "Preparar reuniao", + description: + "Monta um briefing rapido antes de reunioes com contexto, pauta e perguntas uteis.", + trigger_keywords: "preparar reuniao, briefing de reuniao, pauta de reuniao, antes da reuniao", + expected_inputs: "Nome da reuniao, participantes ou tema.", + steps: "Localizar contexto, resumir objetivo, sugerir pauta e perguntas.", + required_tools: ["calendar_optional", "email_optional", "notes_optional"], + success_criteria: "Usuario chega preparado para a reuniao.", + example_use_case: "Prepara meu briefing para a reuniao com o cliente.", + }, + markdown_content: `--- +name: Preparar reuniao +description: Monta um briefing rapido antes de reunioes com contexto, pauta e perguntas uteis. +trigger_keywords: preparar reuniao, briefing de reuniao, pauta de reuniao, antes da reuniao +--- + +## Quando usar + +Use quando o usuario pedir preparacao para uma reuniao, briefing, pauta ou contexto antes de falar com alguem. + +## Inputs esperados + +- Nome, horario, participantes ou tema da reuniao. +- Materiais ou contexto fornecidos pelo usuario. + +## Passo a passo + +1. Identifique qual reuniao ou tema o usuario quer preparar. +2. Consulte agenda, emails ou notas quando houver integracao disponivel. +3. Resuma objetivo, contexto conhecido, riscos e decisoes pendentes. +4. Sugira uma pauta curta e perguntas uteis. +5. Se faltar contexto, diga exatamente o que falta. + +## Ferramentas necessarias + +- Calendar opcional. +- Email opcional. +- Notes opcional. + +## Criterio de sucesso + +O usuario recebe um briefing pratico para entrar na reuniao com clareza. + +## Exemplo + +"Prepara meu briefing para a reuniao com o cliente."`, + }, +]; + +export async function ensureDefaultSkillsForAgent( + supabase: SupabaseAdminClient, + agentInstanceId: string, +): Promise { + const result: DefaultSkillsEnsureResult = { + agent_instance_id: agentInstanceId, + created_count: 0, + skipped_count: 0, + errors: [], + }; + + const { data: agentData, error: agentErr } = await supabase + .from("agent_instances") + .select("id, user_id") + .eq("id", agentInstanceId) + .maybeSingle(); + const agent = agentData as { id: string; user_id: string } | null; + + if (agentErr || !agent) { + throw new Error( + `agent_instance not found for default skills: ${agentErr?.message ?? agentInstanceId}`, + ); + } + + for (const template of DEFAULT_HERMES_SKILLS) { + const { data: existing, error: existingErr } = await supabase + .from("skills") + .select("id") + .eq("user_id", agent.user_id) + .eq("name", template.name) + .neq("status", "archived") + .maybeSingle(); + + if (existingErr) { + result.errors.push( + `${template.name}: failed to check existing skill (${existingErr.message})`, + ); + continue; + } + + if (existing) { + result.skipped_count += 1; + continue; + } + + const { data: skillData, error: skillErr } = await supabase + .from("skills") + .insert({ + user_id: agent.user_id, + agent_instance_id: agent.id, + name: template.name, + description: template.description, + trigger_keywords: template.trigger_keywords, + status: "draft", + }) + .select("id") + .single(); + const skill = skillData as { id: string } | null; + + if (skillErr || !skill) { + result.errors.push( + `${template.name}: failed to create skill (${skillErr?.message ?? "unknown"})`, + ); + continue; + } + + const { data: versionData, error: versionErr } = await supabase + .from("skill_versions") + .insert({ + skill_id: skill.id, + version_number: 1, + markdown_content: template.markdown_content, + form_inputs: template.form_inputs, + is_live: true, + created_by: agent.user_id, + }) + .select("id") + .single(); + const version = versionData as { id: string } | null; + + if (versionErr || !version) { + result.errors.push( + `${template.name}: failed to create skill version (${versionErr?.message ?? "unknown"})`, + ); + continue; + } + + const { error: updateErr } = await supabase + .from("skills") + .update({ + current_version_id: version.id, + status: "active", + updated_at: new Date().toISOString(), + }) + .eq("id", skill.id); + + if (updateErr) { + result.errors.push(`${template.name}: failed to publish skill (${updateErr.message})`); + continue; + } + + result.created_count += 1; + } + + return result; +} diff --git a/supabase/functions/create-cronjob-from-agent/index.ts b/supabase/functions/create-cronjob-from-agent/index.ts index e58a067..1641939 100644 --- a/supabase/functions/create-cronjob-from-agent/index.ts +++ b/supabase/functions/create-cronjob-from-agent/index.ts @@ -23,12 +23,30 @@ import cronstrue from "https://esm.sh/cronstrue@2.50.0/i18n"; import { corsHeaders } from "../_shared/cors.ts"; import { syncAgentRuntimeSnapshot } from "../_shared/runtime-sync.ts"; +type GenericTable = { + Row: Record; + Insert: Record; + Update: Record; + Relationships: []; +}; + +type GenericDatabase = { + public: { + Tables: Record; + Views: Record; + Functions: Record; Returns: unknown }>; + }; +}; + +type SupabaseAdminClient = ReturnType>; + const SUPABASE_URL = Deno.env.get("SUPABASE_URL")!; const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; const INTERNAL_FUNCTION_SECRET = Deno.env.get("INTERNAL_FUNCTION_SECRET") ?? ""; const LOVABLE_API_KEY = Deno.env.get("LOVABLE_API_KEY") ?? ""; const RAILWAY_API_TOKEN = Deno.env.get("RAILWAY_API_TOKEN") ?? ""; const HERMES_API_SERVER_KEY = Deno.env.get("HERMES_API_SERVER_KEY") ?? ""; +const CONTRACT_VERSION = "2026-05-28"; const MODEL = "google/gemini-2.5-flash"; @@ -66,6 +84,13 @@ function constantTimeEq(a: string, b: string): boolean { return diff === 0; } +function isAuthorized(req: Request): boolean { + const received = req.headers.get("x-internal-secret") ?? ""; + return ( + !!INTERNAL_FUNCTION_SECRET && !!received && constantTimeEq(INTERNAL_FUNCTION_SECRET, received) + ); +} + function buildSystemPrompt(tz: string): string { return `Você é um parser de descrições de cronjobs em português para o assistente Mika. Receba uma descrição em linguagem natural e retorne APENAS JSON válido, sem markdown, sem explicações. @@ -90,12 +115,16 @@ interface ParsedJob { function tryParseJson(text: string): ParsedJob | null { try { return JSON.parse(text) as ParsedJob; - } catch (_) { /* segue */ } + } catch (_) { + /* segue */ + } const match = text.match(/\{[\s\S]*\}/); if (match) { try { return JSON.parse(match[0]) as ParsedJob; - } catch (_) { /* falhou */ } + } catch (_) { + /* falhou */ + } } return null; } @@ -123,16 +152,56 @@ async function parseWithAI(input: string, tz: string): Promise return tryParseJson(content); } +async function markJobRuntimeSyncError( + admin: SupabaseAdminClient, + jobId: string, + syncError: string, +): Promise { + const message = syncError.slice(0, 2000); + const { error } = await admin + .from("scheduled_jobs") + .update({ + status: "error", + auto_paused_reason: "Falha ao sincronizar esta automação com o runtime do agente.", + runtime_state: "error", + runtime_last_status: "error", + runtime_last_error: message, + }) + .eq("id", jobId); + + if (error) { + console.error("failed to mark scheduled_job runtime sync error:", error); + } +} + Deno.serve(async (req) => { if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders }); - if (req.method !== "POST") return json({ error: "method not allowed" }, 405); // 1) Auth: apenas X-Internal-Secret (chamada server-to-server do runtime) - const received = req.headers.get("x-internal-secret") ?? ""; - if (!INTERNAL_FUNCTION_SECRET || !received || !constantTimeEq(INTERNAL_FUNCTION_SECRET, received)) { + if (!isAuthorized(req)) { return json({ error: "unauthorized" }, 401); } + if (req.method === "GET" || req.method === "HEAD") { + return json({ + success: true, + endpoint: "create-cronjob-from-agent", + contract_version: CONTRACT_VERSION, + expected_header: "X-Internal-Secret", + required_body_fields: ["agent_instance_id", "natural_language_input"], + optional_body_fields: [ + "cron_expression", + "action_prompt", + "required_mcp_slugs", + "name", + "description", + "timezone", + ], + }); + } + + if (req.method !== "POST") return json({ error: "method not allowed" }, 405); + // 2) Body let body: RequestBody; try { @@ -144,7 +213,8 @@ Deno.serve(async (req) => { if (!body.agent_instance_id) return json({ error: "agent_instance_id required" }, 400); const input = (body.natural_language_input ?? "").trim(); if (input.length < 5) return json({ error: "natural_language_input too short" }, 400); - if (input.length > 1000) return json({ error: "natural_language_input too long (max 1000)" }, 400); + if (input.length > 1000) + return json({ error: "natural_language_input too long (max 1000)" }, 400); const admin = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, { auth: { persistSession: false, autoRefreshToken: false }, @@ -172,7 +242,9 @@ Deno.serve(async (req) => { let cron = (body.cron_expression ?? "").trim(); let actionPrompt = (body.action_prompt ?? "").trim(); let reqSlugs = Array.isArray(body.required_mcp_slugs) - ? body.required_mcp_slugs.filter((s): s is string => typeof s === "string" && VALID_MCP_SLUGS.has(s)) + ? body.required_mcp_slugs.filter( + (s): s is string => typeof s === "string" && VALID_MCP_SLUGS.has(s), + ) : []; if (!cron || !actionPrompt) { @@ -208,7 +280,9 @@ Deno.serve(async (req) => { let humanReadable = cron; try { humanReadable = cronstrue.toString(cron, { locale: "pt_BR" }); - } catch (_) { /* fallback */ } + } catch (_) { + /* fallback */ + } // 7) Nome: usa o fornecido ou deriva do input const name = (body.name ?? "").trim() || input.slice(0, 80); @@ -245,7 +319,8 @@ Deno.serve(async (req) => { return json({ error: "failed to create cronjob", detail: insertErr.message }, 500); } - // 9) Push para o runtime (best-effort; não derruba a criação se falhar) + // 9) Push para o runtime. Se falhar, o job fica registrado como erro, + // mas não fica ativo na UI como se estivesse realmente agendado. let syncOk = false; let syncError: string | null = null; try { @@ -259,7 +334,23 @@ Deno.serve(async (req) => { syncOk = true; } catch (e) { syncError = e instanceof Error ? e.message : String(e); - console.error("runtime sync failed (job created anyway):", syncError); + console.error("runtime sync failed; marking job as error:", syncError); + await markJobRuntimeSyncError(admin, inserted.id, syncError); + return json( + { + success: false, + job_id: inserted.id, + name: inserted.name, + cron_expression: inserted.cron_expression, + human_readable: inserted.human_readable, + next_run_at: inserted.next_run_at, + required_mcp_slugs: inserted.required_mcp_slugs, + status: "error", + runtime_sync_ok: false, + runtime_sync_error: syncError, + }, + 502, + ); } return json({ @@ -270,6 +361,7 @@ Deno.serve(async (req) => { human_readable: inserted.human_readable, next_run_at: inserted.next_run_at, required_mcp_slugs: inserted.required_mcp_slugs, + status: inserted.status, runtime_sync_ok: syncOk, runtime_sync_error: syncError, }); diff --git a/supabase/functions/create-skill-from-agent/index.ts b/supabase/functions/create-skill-from-agent/index.ts new file mode 100644 index 0000000..8c4c907 --- /dev/null +++ b/supabase/functions/create-skill-from-agent/index.ts @@ -0,0 +1,334 @@ +// create-skill-from-agent +// Endpoint server-to-server chamado pelo runtime Mika/Hermes quando o usuario +// pede pelo Telegram para criar uma nova skill. + +import { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.4"; +import { corsHeaders } from "../_shared/cors.ts"; +import { syncAgentSkillsSnapshot } from "../_shared/runtime-sync.ts"; + +const SUPABASE_URL = Deno.env.get("SUPABASE_URL")!; +const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; +const INTERNAL_FUNCTION_SECRET = Deno.env.get("INTERNAL_FUNCTION_SECRET") ?? ""; +const LOVABLE_API_KEY = Deno.env.get("LOVABLE_API_KEY") ?? ""; +const RAILWAY_API_TOKEN = Deno.env.get("RAILWAY_API_TOKEN") ?? ""; +const HERMES_API_SERVER_KEY = Deno.env.get("HERMES_API_SERVER_KEY") ?? ""; +const MODEL = "google/gemini-2.5-flash"; +const CONTRACT_VERSION = "2026-05-28"; +const MAX_MARKDOWN_LEN = 50000; + +interface RequestBody { + agent_instance_id: string; + natural_language_input: string; + name?: string; + description?: string; + trigger_keywords?: string; + markdown_content?: string; +} + +interface GeneratedSkill { + name: string; + description: string; + trigger_keywords: string; + markdown_content: string; +} + +function json(body: unknown, status = 200) { + return new Response(JSON.stringify(body), { + status, + headers: { ...corsHeaders, "Content-Type": "application/json" }, + }); +} + +function constantTimeEq(a: string, b: string): boolean { + if (a.length !== b.length) return false; + let diff = 0; + for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i); + return diff === 0; +} + +function isAuthorized(req: Request): boolean { + const received = req.headers.get("x-internal-secret") ?? ""; + return ( + !!INTERNAL_FUNCTION_SECRET && !!received && constantTimeEq(INTERNAL_FUNCTION_SECRET, received) + ); +} + +function normalizeText(value: unknown, fallback: string, max = 200): string { + const text = typeof value === "string" ? value.trim() : ""; + return (text || fallback).slice(0, max); +} + +function extractFrontmatterField(markdown: string, field: string): string | null { + const match = markdown.match(new RegExp(`^${field}:\\s*(.+)$`, "im")); + return match?.[1]?.trim().replace(/^["']|["']$/g, "") || null; +} + +function ensureSkillFrontmatter(skill: GeneratedSkill): string { + const markdown = skill.markdown_content + .trim() + .replace(/^```(?:markdown)?\s*/i, "") + .replace(/```$/i, "") + .trim(); + const body = markdown.replace(/^---\s*[\s\S]*?\n---\s*/i, "").trim(); + + return `--- +name: ${skill.name} +description: ${skill.description} +trigger_keywords: ${skill.trigger_keywords} +--- + +${body}`.slice(0, MAX_MARKDOWN_LEN); +} + +function tryParseJson(text: string): GeneratedSkill | null { + try { + return JSON.parse(text) as GeneratedSkill; + } catch (_) { + // segue + } + const match = text.match(/\{[\s\S]*\}/); + if (!match) return null; + try { + return JSON.parse(match[0]) as GeneratedSkill; + } catch (_) { + return null; + } +} + +async function generateSkillFromInput(input: string): Promise { + if (!LOVABLE_API_KEY) return null; + + const systemPrompt = `Voce cria skills para o Hermes Agent no padrao agentskills.io. +Retorne APENAS JSON valido, sem markdown fence e sem comentarios. +Formato: +{"name":"Nome curto","description":"Descricao curta","trigger_keywords":"palavra, sinonimo, frase","markdown_content":"---\\nname: ...\\ndescription: ...\\ntrigger_keywords: ...\\n---\\n\\n## Quando usar\\n...\\n\\n## Inputs esperados\\n...\\n\\n## Passo a passo\\n1. ...\\n\\n## Ferramentas necessarias\\n...\\n\\n## Criterio de sucesso\\n..."} +Use portugues brasileiro, comandos claros, e nao prometa executar ferramentas que nao foram citadas ou conectadas.`; + + const res = await fetch("https://ai.gateway.lovable.dev/v1/chat/completions", { + method: "POST", + headers: { + Authorization: `Bearer ${LOVABLE_API_KEY}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + model: MODEL, + max_tokens: 1800, + messages: [ + { role: "system", content: systemPrompt }, + { role: "user", content: input }, + ], + }), + }); + + if (!res.ok) { + console.error("create-skill-from-agent AI gateway status:", res.status); + return null; + } + + const data = await res.json(); + const content: string = data?.choices?.[0]?.message?.content ?? ""; + return tryParseJson(content); +} + +function buildFormInputs(skill: GeneratedSkill, originalInput: string): Record { + return { + name: skill.name, + description: skill.description, + trigger_keywords: skill.trigger_keywords, + expected_inputs: originalInput, + steps: "Criada via Hermes a partir de instrucao em linguagem natural.", + required_tools: [], + success_criteria: "A skill possui gatilhos claros, passos executaveis e criterio de sucesso.", + example_use_case: originalInput, + }; +} + +Deno.serve(async (req) => { + if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders }); + + if (!isAuthorized(req)) { + return json({ error: "unauthorized" }, 401); + } + + if (req.method === "GET" || req.method === "HEAD") { + return json({ + success: true, + endpoint: "create-skill-from-agent", + contract_version: CONTRACT_VERSION, + expected_header: "X-Internal-Secret", + required_body_fields: ["agent_instance_id", "natural_language_input"], + optional_body_fields: ["name", "description", "trigger_keywords", "markdown_content"], + }); + } + + if (req.method !== "POST") return json({ error: "method not allowed" }, 405); + + let body: RequestBody; + try { + body = await req.json(); + } catch { + return json({ error: "invalid json body" }, 400); + } + + if (!body.agent_instance_id) return json({ error: "agent_instance_id required" }, 400); + const input = (body.natural_language_input ?? "").trim(); + if (input.length < 10) return json({ error: "natural_language_input too short" }, 400); + if (input.length > 3000) + return json({ error: "natural_language_input too long (max 3000)" }, 400); + + const admin = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, { + auth: { persistSession: false, autoRefreshToken: false }, + }); + + const { data: agent, error: agentErr } = await admin + .from("agent_instances") + .select("id, user_id") + .eq("id", body.agent_instance_id) + .maybeSingle(); + + if (agentErr || !agent) return json({ error: "agent_instance not found" }, 404); + + let generated: GeneratedSkill | null = null; + if (body.markdown_content?.trim()) { + const markdown = body.markdown_content.trim(); + generated = { + name: normalizeText( + body.name ?? extractFrontmatterField(markdown, "name"), + "Skill criada pelo Hermes", + 80, + ), + description: normalizeText( + body.description ?? extractFrontmatterField(markdown, "description"), + "Skill criada via Hermes.", + 240, + ), + trigger_keywords: normalizeText( + body.trigger_keywords ?? extractFrontmatterField(markdown, "trigger_keywords"), + input.slice(0, 120), + 240, + ), + markdown_content: markdown, + }; + } else { + generated = await generateSkillFromInput(input); + } + + if (!generated?.markdown_content?.trim()) { + return json({ error: "failed to generate skill content" }, 422); + } + + const skillName = normalizeText(body.name ?? generated.name, "Skill criada pelo Hermes", 80); + const skillDescription = normalizeText( + body.description ?? generated.description, + "Skill criada via Hermes.", + 240, + ); + const skillTriggerKeywords = normalizeText( + body.trigger_keywords ?? generated.trigger_keywords, + input.slice(0, 120), + 240, + ); + const skill: GeneratedSkill = { + name: skillName, + description: skillDescription, + trigger_keywords: skillTriggerKeywords, + markdown_content: ensureSkillFrontmatter({ + name: skillName, + description: skillDescription, + trigger_keywords: skillTriggerKeywords, + markdown_content: generated.markdown_content, + }), + }; + + const { data: insertedSkill, error: skillErr } = await admin + .from("skills") + .insert({ + user_id: agent.user_id, + agent_instance_id: agent.id, + name: skill.name, + description: skill.description, + trigger_keywords: skill.trigger_keywords, + status: "draft", + }) + .select("id") + .single(); + + if (skillErr || !insertedSkill) { + const code = (skillErr as { code?: string } | null)?.code ?? ""; + if (code === "P0001") return json({ error: "no active subscription" }, 402); + if (code === "P0002") return json({ error: "skill limit reached for plan" }, 403); + if (code === "23505") return json({ error: "skill name already exists" }, 409); + console.error("create-skill-from-agent insert skill failed:", skillErr); + return json({ error: "failed to create skill", detail: skillErr?.message }, 500); + } + + const { data: version, error: versionErr } = await admin + .from("skill_versions") + .insert({ + skill_id: insertedSkill.id, + version_number: 1, + markdown_content: skill.markdown_content, + form_inputs: buildFormInputs(skill, input), + is_live: true, + created_by: agent.user_id, + }) + .select("id") + .single(); + + if (versionErr || !version) { + await admin.from("skills").update({ status: "archived" }).eq("id", insertedSkill.id); + console.error("create-skill-from-agent insert version failed:", versionErr); + return json({ error: "failed to create skill version", detail: versionErr?.message }, 500); + } + + const { error: publishErr } = await admin + .from("skills") + .update({ + current_version_id: version.id, + status: "active", + updated_at: new Date().toISOString(), + }) + .eq("id", insertedSkill.id); + + if (publishErr) { + console.error("create-skill-from-agent publish failed:", publishErr); + return json({ error: "failed to publish skill", detail: publishErr.message }, 500); + } + + try { + const syncResult = await syncAgentSkillsSnapshot({ + supabase: admin, + agentInstanceId: agent.id, + railwayToken: RAILWAY_API_TOKEN, + apiKey: HERMES_API_SERVER_KEY, + }); + + return json({ + success: true, + skill_id: insertedSkill.id, + skill_version_id: version.id, + name: skill.name, + description: skill.description, + trigger_keywords: skill.trigger_keywords, + status: "active", + runtime_sync_ok: true, + synced_count: syncResult.synced_count, + }); + } catch (e) { + const syncError = e instanceof Error ? e.message : String(e); + await admin.from("skills").update({ status: "testing" }).eq("id", insertedSkill.id); + console.error("create-skill-from-agent skills sync failed:", syncError); + return json( + { + success: false, + skill_id: insertedSkill.id, + skill_version_id: version.id, + name: skill.name, + status: "testing", + runtime_sync_ok: false, + runtime_sync_error: syncError, + }, + 502, + ); + } +}); diff --git a/supabase/functions/deno.lock b/supabase/functions/deno.lock new file mode 100644 index 0000000..2271797 --- /dev/null +++ b/supabase/functions/deno.lock @@ -0,0 +1,65 @@ +{ + "version": "5", + "specifiers": { + "npm:@supabase/supabase-js@2": "2.106.2" + }, + "npm": { + "@supabase/auth-js@2.106.2": { + "integrity": "sha512-VcAjUErkHkhC5Jaf+g/G1qbkQrFh8edaCdHa7pxJmHUjkWKjT7UnYCtPA89XV0N0GIYRkEqJZw5V62CtOxTmBQ==", + "dependencies": [ + "tslib" + ] + }, + "@supabase/functions-js@2.106.2": { + "integrity": "sha512-oRnr0QrL8H+zTO1YyQ1QjiHZU/957jvubbxSJTUm2XLAgzoGGV9Tahfyd+uvLsBLRVmXLtpU3oyCjdQIvkGMOA==", + "dependencies": [ + "tslib" + ] + }, + "@supabase/phoenix@0.4.2": { + "integrity": "sha512-YSAGnmDAfuleFCVt3CeurQZAhxRfXWeZIIkwp7NhYzQ1UwW6ePSnzsFAiUm/mbCkfoCf70QQHKW/K6RKh52a4A==" + }, + "@supabase/postgrest-js@2.106.2": { + "integrity": "sha512-tDOzyPgp9pIRMR2x6C9+uDSJrnXSzxLtt3d7nC+Lrsy3jnJDHYfdQC/xcRyhJE/TOBJ0heSqRKR3UmejDjZxsw==", + "dependencies": [ + "tslib" + ] + }, + "@supabase/realtime-js@2.106.2": { + "integrity": "sha512-LdRGT7DNhyZkPjubUv5bSdAZ0jSEX8wTHvx7htj7+K59TOZRvz4TuQK7tL2RWxyIZVeFMRluL04SzWS61rKnUA==", + "dependencies": [ + "@supabase/phoenix", + "tslib" + ] + }, + "@supabase/storage-js@2.106.2": { + "integrity": "sha512-xgKCSYuev1YarV+iVqr+zlfgSyremnJtn8T0NCT8L4XmMv1CLtESc0Q6kNp8+mKWdX/8ND0nzm7OMKx08kwNAw==", + "dependencies": [ + "iceberg-js", + "tslib" + ] + }, + "@supabase/supabase-js@2.106.2": { + "integrity": "sha512-2/RZ/1fmJx/MRSEDG2Xk8+J4JVk5clM9V0uSI6kUTrcS32KA89DtqI5RUOC9r6mzY3WBC9qexLjssIHjbLyVJA==", + "dependencies": [ + "@supabase/auth-js", + "@supabase/functions-js", + "@supabase/postgrest-js", + "@supabase/realtime-js", + "@supabase/storage-js" + ] + }, + "iceberg-js@0.8.1": { + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==" + }, + "tslib@2.8.1": { + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + } + }, + "remote": { + "https://esm.sh/@supabase/supabase-js@2.45.4": "1108d69216995335d057dbd15907caaf514a4d1ef082f097050573b9d589a57c", + "https://esm.sh/@supabase/supabase-js@2.57.4": "05a369085eb4a4c99d85ccece97f0cf1e05357122e0e74373da1f0e91b014902", + "https://esm.sh/cron-parser@4.9.0": "d55208635006ce12cce8101d42835ea617d48d335b2e6ec9316169ba42d64813", + "https://esm.sh/cronstrue@2.50.0/i18n": "cf6a244bd4498587470f730691105754b801fe645a53fabde956c56cfe30f492" + } +} diff --git a/supabase/functions/provision-agent/index.ts b/supabase/functions/provision-agent/index.ts index d41983b..cecb751 100644 --- a/supabase/functions/provision-agent/index.ts +++ b/supabase/functions/provision-agent/index.ts @@ -22,6 +22,23 @@ import { normalizeOllamaModelSelection, } from "../_shared/hermes-config.ts"; +type GenericTable = { + Row: Record; + Insert: Record; + Update: Record; + Relationships: []; +}; + +type GenericDatabase = { + public: { + Tables: Record; + Views: Record; + Functions: Record; Returns: unknown }>; + }; +}; + +type SupabaseAdminClient = ReturnType>; + interface RequestBody { agent_instance_id: string; agent_name?: string; @@ -31,28 +48,77 @@ interface RequestBody { tts_provider?: string; } +interface SubscriptionWithPlan { + plans?: { slug?: string | null } | { slug?: string | null }[] | null; +} + +interface AgentInstanceRow { + id: string; + user_id: string; + uuid_tenant: string; + status: string; + telegram_bot_token_vault_id?: string | null; + telegram_bot_username?: string | null; + telegram_user_chat_id?: string | number | null; + railway_service_id?: string | null; + agent_name?: string | null; + vps_pool_id?: string | null; +} + +function getPlanSlug(subscription: SubscriptionWithPlan | null): string { + const plans = subscription?.plans; + const plan = Array.isArray(plans) ? plans[0] : plans; + return plan?.slug ?? "basic"; +} + const SUPABASE_URL = Deno.env.get("SUPABASE_URL")!; const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; const RAILWAY_API_TOKEN = Deno.env.get("RAILWAY_API_TOKEN"); +const HERMES_API_SERVER_KEY = Deno.env.get("HERMES_API_SERVER_KEY") ?? ""; +const INTERNAL_FUNCTION_SECRET = Deno.env.get("INTERNAL_FUNCTION_SECRET") ?? ""; +const HERMES_RUNTIME_IMAGE = + Deno.env.get("HERMES_RUNTIME_IMAGE") ?? "ghcr.io/domfelipe/hermes-agent-custom:latest"; +const MIKA_RUNTIME_CONTRACT_VERSION = "2026-05-28"; const ADMIN_TELEGRAM_BOT_TOKEN = Deno.env.get("ADMIN_TELEGRAM_BOT_TOKEN"); const ADMIN_TELEGRAM_CHAT_ID = Deno.env.get("ADMIN_TELEGRAM_CHAT_ID"); +function buildRuntimePlatformEnv(agentInstanceId: string): Record { + const functionsBaseUrl = `${SUPABASE_URL.replace(/\/$/, "")}/functions/v1`; + const createCronjobUrl = `${functionsBaseUrl}/create-cronjob-from-agent`; + const createSkillUrl = `${functionsBaseUrl}/create-skill-from-agent`; + + return { + AGENT_INSTANCE_ID: agentInstanceId, + HERMES_AGENT_INSTANCE_ID: agentInstanceId, + HERMES_CREATE_CRONJOB_URL: createCronjobUrl, + HERMES_CREATE_SKILL_URL: createSkillUrl, + HERMES_INTERNAL_FUNCTION_SECRET: INTERNAL_FUNCTION_SECRET, + HERMES_PLATFORM_FUNCTIONS_BASE_URL: functionsBaseUrl, + HERMES_RUNTIME_CONTRACT_VERSION: MIKA_RUNTIME_CONTRACT_VERSION, + INTERNAL_FUNCTION_SECRET, + MIKA_AGENT_INSTANCE_ID: agentInstanceId, + MIKA_CREATE_CRONJOB_URL: createCronjobUrl, + MIKA_CREATE_SKILL_URL: createSkillUrl, + MIKA_INTERNAL_FUNCTION_SECRET: INTERNAL_FUNCTION_SECRET, + MIKA_PLATFORM_FUNCTIONS_BASE_URL: functionsBaseUrl, + MIKA_RUNTIME_CONTRACT_VERSION, + SUPABASE_URL, + }; +} + async function notifyAdmin(message: string): Promise { if (!ADMIN_TELEGRAM_BOT_TOKEN || !ADMIN_TELEGRAM_CHAT_ID) return; try { - await fetch( - `https://api.telegram.org/bot${ADMIN_TELEGRAM_BOT_TOKEN}/sendMessage`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - chat_id: ADMIN_TELEGRAM_CHAT_ID, - text: message, - parse_mode: "HTML", - }), - }, - ); + await fetch(`https://api.telegram.org/bot${ADMIN_TELEGRAM_BOT_TOKEN}/sendMessage`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + chat_id: ADMIN_TELEGRAM_CHAT_ID, + text: message, + parse_mode: "HTML", + }), + }); } catch (e) { console.error("notifyAdmin failed:", e); } @@ -93,7 +159,7 @@ Deno.serve(async (req) => { const { data: agent, error: agentErr } = await supabase .from("agent_instances") .select( - "id, user_id, uuid_tenant, status, telegram_bot_token_vault_id, telegram_bot_username, telegram_user_chat_id, railway_service_id, agent_name", + "id, user_id, uuid_tenant, status, telegram_bot_token_vault_id, telegram_bot_username, telegram_user_chat_id, railway_service_id, agent_name, vps_pool_id", ) .eq("id", body.agent_instance_id) .maybeSingle(); @@ -105,29 +171,33 @@ Deno.serve(async (req) => { if (agent.status !== "provisioning") { console.log(`[provision-agent] status atual=${agent.status}, abortando`); - return jsonResponse(409, { error: "agent_instance is not in provisioning status", status: agent.status }); + return jsonResponse(409, { + error: "agent_instance is not in provisioning status", + status: agent.status, + }); } // Se já existe railway_service_id → fluxo de UPDATE (não tenta criar novo serviço) if (agent.railway_service_id) { - console.log(`[provision-agent] railway_service_id já existe (${agent.railway_service_id}) → modo update`); + console.log( + `[provision-agent] railway_service_id já existe (${agent.railway_service_id}) → modo update`, + ); return await handleUpdateExistingService(supabase, agent, body); } // 1b) Carregar profile (full_name → nome do agente) - const { data: profile } = await supabase + const { data: profileData } = await supabase .from("profiles") .select("full_name") .eq("id", agent.user_id) .maybeSingle(); + const profile = profileData as { full_name?: string | null } | null; const fullName = (profile?.full_name?.trim() || "Usuário").toString(); const firstName = fullName.split(" ")[0] || "Usuário"; // Prioridade: body > coluna agent_name no DB > default "Mika de {firstName}" const agentName = - body.agent_name?.trim() || - (agent.agent_name?.trim() ?? "") || - `Mika de ${firstName}`; + body.agent_name?.trim() || (agent.agent_name?.trim() ?? "") || `Mika de ${firstName}`; console.log(`[provision-agent] profile carregado: ${fullName} → agent_name=${agentName}`); // 1c) Carregar subscription ativa (para definir modelo Pro vs Basic) @@ -140,8 +210,7 @@ Deno.serve(async (req) => { .limit(1) .maybeSingle(); - // deno-lint-ignore no-explicit-any - const planSlug = ((subscription as any)?.plans?.slug as string | undefined) ?? "basic"; + const planSlug = getPlanSlug(subscription as SubscriptionWithPlan | null); console.log(`[provision-agent] plano=${planSlug}`); // 2) Buscar pool disponível (com IDs Railway preenchidos e capacidade) @@ -166,7 +235,9 @@ Deno.serve(async (req) => { ); return jsonResponse(503, { error: "no railway pool available" }); } - console.log(`[provision-agent] pool selecionado: ${pool.id} (railway_project=${pool.railway_project_id})`); + console.log( + `[provision-agent] pool selecionado: ${pool.id} (railway_project=${pool.railway_project_id})`, + ); // 3) Criar provisioning_job em status running const { data: job, error: jobErr } = await supabase @@ -190,14 +261,19 @@ Deno.serve(async (req) => { if (jobErr || !job) { console.error(`[provision-agent] falha ao criar job: ${jobErr?.message}`); - return jsonResponse(500, { error: "failed to create provisioning_job", detail: jobErr?.message }); + return jsonResponse(500, { + error: "failed to create provisioning_job", + detail: jobErr?.message, + }); } console.log(`[provision-agent] provisioning_job criado: ${job.id}`); // 4) Decrypt do telegram_bot_token (se existir) let telegramBotToken = ""; if (agent.telegram_bot_token_vault_id) { - console.log(`[provision-agent] decifrando token do Vault: ${agent.telegram_bot_token_vault_id}`); + console.log( + `[provision-agent] decifrando token do Vault: ${agent.telegram_bot_token_vault_id}`, + ); const { data: secret } = await supabase.rpc("vault_decrypt_secret", { secret_id: agent.telegram_bot_token_vault_id, }); @@ -240,9 +316,10 @@ Deno.serve(async (req) => { const modelFinal = normalizeOllamaModelSelection(body.model || DEFAULT_OLLAMA_MODEL); const envVars: Record = { + ...buildRuntimePlatformEnv(agent.id), HERMES_HOME: "/opt/data/.hermes", API_SERVER_ENABLED: "true", - API_SERVER_KEY: Deno.env.get("HERMES_API_SERVER_KEY") ?? "", + API_SERVER_KEY: HERMES_API_SERVER_KEY, GATEWAY_ALLOW_ALL_USERS: "false", HERMES_MODEL_DEFAULT: modelFinal, HERMES_MODEL_PROVIDER: DEFAULT_OLLAMA_PROVIDER, @@ -275,7 +352,9 @@ Deno.serve(async (req) => { const msg = createErr instanceof Error ? createErr.message : String(createErr); // Recover from "service already exists" — provavelmente sobra de attempt anterior if (msg.includes("already exists")) { - console.warn(`[provision-agent] serviço já existe, tentando recuperar ID por nome: ${serviceName}`); + console.warn( + `[provision-agent] serviço já existe, tentando recuperar ID por nome: ${serviceName}`, + ); const existingId = await findRailwayServiceByName({ token: RAILWAY_API_TOKEN, projectId: pool.railway_project_id, @@ -296,11 +375,13 @@ Deno.serve(async (req) => { serviceId: railwayServiceId, environmentId: pool.railway_environment_id, projectId: pool.railway_project_id, - image: "ghcr.io/domfelipe/hermes-agent-custom:latest", + image: HERMES_RUNTIME_IMAGE, variables: envVars, startCommand: HERMES_START_COMMAND, }); - console.log(`[provision-agent] serviço configurado com ${Object.keys(envVars).length} env vars`); + console.log( + `[provision-agent] serviço configurado com ${Object.keys(envVars).length} env vars`, + ); await deployRailwayService({ token: RAILWAY_API_TOKEN, @@ -346,7 +427,9 @@ Deno.serve(async (req) => { .update({ railway_service_id: railwayServiceId, status: "running" }) .eq("id", job.id); - console.log(`[provision-agent] sucesso: agent=${agent.id} railway=${railwayServiceId} (aguardando deploy)`); + console.log( + `[provision-agent] sucesso: agent=${agent.id} railway=${railwayServiceId} (aguardando deploy)`, + ); // status do agent permanece 'provisioning' — railway-webhook atualiza para 'active' quando deploy subir return jsonResponse(200, { @@ -367,8 +450,7 @@ function jsonResponse(status: number, body: unknown) { } async function failJob( - // deno-lint-ignore no-explicit-any - supabase: any, + supabase: SupabaseAdminClient, agent: { id: string }, jobId: string | null, message: string, @@ -383,8 +465,7 @@ async function failJob( } async function scheduleRetry( - // deno-lint-ignore no-explicit-any - supabase: any, + supabase: SupabaseAdminClient, agent: { id: string }, jobId: string, message: string, @@ -424,27 +505,27 @@ async function scheduleRetry( * faz upsert das variáveis de ambiente com defaults automáticos e dispara redeploy. */ async function handleUpdateExistingService( - // deno-lint-ignore no-explicit-any - supabase: any, - // deno-lint-ignore no-explicit-any - agent: any, + supabase: SupabaseAdminClient, + agent: AgentInstanceRow, body: RequestBody, ): Promise { - const railwayServiceId: string = agent.railway_service_id; + const railwayServiceId = agent.railway_service_id; + if (!railwayServiceId) { + return jsonResponse(400, { error: "railway_service_id required for update mode" }); + } // Carregar profile + plano para gerar defaults coerentes - const { data: profile } = await supabase + const { data: profileData } = await supabase .from("profiles") .select("full_name") .eq("id", agent.user_id) .maybeSingle(); + const profile = profileData as { full_name?: string | null } | null; const fullName = (profile?.full_name?.trim() || "Usuário").toString(); const firstName = fullName.split(" ")[0] || "Usuário"; const agentName = - body.agent_name?.trim() || - (agent.agent_name?.trim() ?? "") || - `Mika de ${firstName}`; + body.agent_name?.trim() || (agent.agent_name?.trim() ?? "") || `Mika de ${firstName}`; const { data: subscription } = await supabase .from("subscriptions") @@ -455,8 +536,7 @@ async function handleUpdateExistingService( .limit(1) .maybeSingle(); - // deno-lint-ignore no-explicit-any - const planSlug = ((subscription as any)?.plans?.slug as string | undefined) ?? "basic"; + const planSlug = getPlanSlug(subscription as SubscriptionWithPlan | null); const defaultSoul = `Você se chama ${agentName}. Você é um assistente pessoal de IA criado pela DOMCO para ${fullName}. Você é proativo, direto e fala sempre em português brasileiro. Você ajuda ${firstName} a ser mais produtivo — gerenciando emails, agenda, tarefas e automatizando o que puder. Seja conciso nas respostas via Telegram. Nunca se identifique como Hermes ou como produto da Nous Research — você é Mika.`; const soulContent = body.soul_content?.trim() || defaultSoul; @@ -464,18 +544,24 @@ async function handleUpdateExistingService( const sttProvider = body.stt_provider || "local"; const ttsProvider = body.tts_provider || "disabled"; - console.log(`[provision-agent:update] agent=${agent.id} service=${railwayServiceId} plano=${planSlug}`); + console.log( + `[provision-agent:update] agent=${agent.id} service=${railwayServiceId} plano=${planSlug}`, + ); // Resolver project/environment Railway let projectId: string | null = null; let environmentId: string | null = null; if (agent.vps_pool_id) { - const { data: pool } = await supabase + const { data: poolData } = await supabase .from("vps_pool") .select("railway_project_id, railway_environment_id") .eq("id", agent.vps_pool_id) .maybeSingle(); + const pool = poolData as { + railway_project_id?: string | null; + railway_environment_id?: string | null; + } | null; projectId = pool?.railway_project_id ?? null; environmentId = pool?.railway_environment_id ?? null; } @@ -492,6 +578,11 @@ async function handleUpdateExistingService( } const variables: Record = { + ...buildRuntimePlatformEnv(agent.id), + API_SERVER_ENABLED: "true", + API_SERVER_KEY: HERMES_API_SERVER_KEY, + GATEWAY_ALLOW_ALL_USERS: "false", + HERMES_HOME: "/opt/data/.hermes", HERMES_MODEL_DEFAULT: model, HERMES_MODEL_PROVIDER: DEFAULT_OLLAMA_PROVIDER, HERMES_SOUL_OVERRIDE: soulContent, @@ -517,14 +608,16 @@ async function handleUpdateExistingService( variables, skipDeploys: true, }); - console.log(`[provision-agent:update] variáveis atualizadas (${Object.keys(variables).length})`); + console.log( + `[provision-agent:update] variáveis atualizadas (${Object.keys(variables).length})`, + ); await configureRailwayService({ token: RAILWAY_API_TOKEN!, serviceId: railwayServiceId, environmentId, projectId, - image: "ghcr.io/domfelipe/hermes-agent-custom:latest", + image: HERMES_RUNTIME_IMAGE, variables: {}, startCommand: HERMES_START_COMMAND, }); diff --git a/supabase/functions/railway-webhook/index.ts b/supabase/functions/railway-webhook/index.ts index 1cab649..5613fb3 100644 --- a/supabase/functions/railway-webhook/index.ts +++ b/supabase/functions/railway-webhook/index.ts @@ -10,10 +10,33 @@ import { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.4"; import { corsHeaders } from "../_shared/cors.ts"; -import { - syncAgentRuntimeSnapshot, - syncAgentSkillsSnapshot, -} from "../_shared/runtime-sync.ts"; +import { syncAgentRuntimeSnapshot, syncAgentSkillsSnapshot } from "../_shared/runtime-sync.ts"; +import { ensureDefaultSkillsForAgent } from "../_shared/default-skills.ts"; + +type GenericTable = { + Row: Record; + Insert: Record; + Update: Record; + Relationships: []; +}; + +type GenericDatabase = { + public: { + Tables: Record; + Views: Record; + Functions: Record; Returns: unknown }>; + }; +}; + +type SupabaseAdminClient = ReturnType>; + +interface AgentWelcomeRow { + id: string; + user_id: string; + telegram_bot_token_vault_id: string; + telegram_user_chat_id: string | number; + agent_name?: string | null; +} const SUPABASE_URL = Deno.env.get("SUPABASE_URL")!; const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; @@ -25,18 +48,15 @@ const HERMES_API_SERVER_KEY = Deno.env.get("HERMES_API_SERVER_KEY") ?? ""; async function notifyAdmin(message: string): Promise { if (!ADMIN_TELEGRAM_BOT_TOKEN || !ADMIN_TELEGRAM_CHAT_ID) return; try { - await fetch( - `https://api.telegram.org/bot${ADMIN_TELEGRAM_BOT_TOKEN}/sendMessage`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - chat_id: ADMIN_TELEGRAM_CHAT_ID, - text: message, - parse_mode: "HTML", - }), - }, - ); + await fetch(`https://api.telegram.org/bot${ADMIN_TELEGRAM_BOT_TOKEN}/sendMessage`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + chat_id: ADMIN_TELEGRAM_CHAT_ID, + text: message, + parse_mode: "HTML", + }), + }); } catch (e) { console.error("notifyAdmin failed:", e); } @@ -64,7 +84,9 @@ Deno.serve(async (req) => { ["sign"], ); const macBuf = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(rawBody)); - const macHex = Array.from(new Uint8Array(macBuf)).map((b) => b.toString(16).padStart(2, "0")).join(""); + const macHex = Array.from(new Uint8Array(macBuf)) + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); const expected = sig.startsWith("sha256=") ? sig.slice(7) : sig; if (expected !== macHex) { console.warn("railway-webhook: invalid signature"); @@ -188,7 +210,10 @@ Deno.serve(async (req) => { ); } catch (e) { runtimeSyncError = e instanceof Error ? e.message : String(e); - console.error(`railway-webhook: falha ao sincronizar runtime do agent ${agent.id}:`, runtimeSyncError); + console.error( + `railway-webhook: falha ao sincronizar runtime do agent ${agent.id}:`, + runtimeSyncError, + ); if (wasProvisioning) { const fullName = await loadFullName(); await notifyAdmin( @@ -201,6 +226,33 @@ Deno.serve(async (req) => { } } + let defaultSkillsError: string | null = null; + try { + const defaultSkillsResult = await ensureDefaultSkillsForAgent(supabase, agent.id); + if (defaultSkillsResult.errors.length > 0) { + throw new Error(defaultSkillsResult.errors.join("; ")); + } + console.log( + `railway-webhook: default skills agent ${agent.id} (${defaultSkillsResult.created_count} criadas, ${defaultSkillsResult.skipped_count} existentes)`, + ); + } catch (e) { + defaultSkillsError = e instanceof Error ? e.message : String(e); + console.error( + `railway-webhook: falha ao garantir skills padrão do agent ${agent.id}:`, + defaultSkillsError, + ); + if (wasProvisioning) { + const fullName = await loadFullName(); + await notifyAdmin( + `⚠️ Agente subiu, mas as skills padrão falharam\n\n` + + `👤 Cliente: ${fullName}\n` + + `🚀 Railway: ${agent.railway_service_id}\n` + + `❗ Erro: ${defaultSkillsError}\n\n` + + `➡️ Revisar no admin`, + ); + } + } + let skillsSyncError: string | null = null; try { const syncResult = await syncAgentSkillsSnapshot({ @@ -214,7 +266,10 @@ Deno.serve(async (req) => { ); } catch (e) { skillsSyncError = e instanceof Error ? e.message : String(e); - console.error(`railway-webhook: falha ao sincronizar skills do agent ${agent.id}:`, skillsSyncError); + console.error( + `railway-webhook: falha ao sincronizar skills do agent ${agent.id}:`, + skillsSyncError, + ); if (wasProvisioning) { const fullName = await loadFullName(); await notifyAdmin( @@ -228,7 +283,7 @@ Deno.serve(async (req) => { } // Notifica admin somente se era um auto-provisionamento (status anterior=provisioning) - if (wasProvisioning && !skillsSyncError && !runtimeSyncError) { + if (wasProvisioning && !skillsSyncError && !runtimeSyncError && !defaultSkillsError) { const fullName = await loadFullName(); await notifyAdmin( `✅ Agente provisionado automaticamente!\n\n` + @@ -243,10 +298,7 @@ Deno.serve(async (req) => { } if (upper === "FAILED" || upper === "CRASHED") { - await supabase - .from("agent_instances") - .update({ status: "error" }) - .eq("id", agent.id); + await supabase.from("agent_instances").update({ status: "error" }).eq("id", agent.id); await supabase .from("provisioning_jobs") @@ -286,12 +338,15 @@ function jsonResponse(status: number, body: unknown) { }); } -// deno-lint-ignore no-explicit-any -async function sendWelcomeMessage(supabase: any, agent: any): Promise { +async function sendWelcomeMessage( + supabase: SupabaseAdminClient, + agent: AgentWelcomeRow, +): Promise { // Decifra o token do bot - const { data: secret } = await supabase.rpc("vault_decrypt_secret", { + const { data: secretData } = await supabase.rpc("vault_decrypt_secret", { secret_id: agent.telegram_bot_token_vault_id, }); + const secret = secretData as { decrypted_secret?: string | null }[] | null; const token: string = secret?.[0]?.decrypted_secret ?? ""; if (!token) { console.warn("sendWelcomeMessage: token vazio, abortando");