diff --git a/.env b/.env new file mode 100644 index 0000000..819b8e0 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +VITE_SUPABASE_URL=http://127.0.0.1:54321 +VITE_SUPABASE_ANON_KEY=sb_publishable_ACJWlzQHlZjBrEguHvfOxg_3BJgxAaH diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..819b8e0 --- /dev/null +++ b/.env.local @@ -0,0 +1,2 @@ +VITE_SUPABASE_URL=http://127.0.0.1:54321 +VITE_SUPABASE_ANON_KEY=sb_publishable_ACJWlzQHlZjBrEguHvfOxg_3BJgxAaH diff --git a/.gitignore b/.gitignore index d45df1c..47cb90c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,12 @@ coverage .nitro .cache .output -.env +# .env dist .DS_Store .idea .eslintcache api-generator/typedoc.json **/.DS_Store +Dev-documentacao/ +supabase/ diff --git a/ARCHITECTURE_NOTES.md b/ARCHITECTURE_NOTES.md new file mode 100644 index 0000000..d3ca41b --- /dev/null +++ b/ARCHITECTURE_NOTES.md @@ -0,0 +1,31 @@ +### Observação sobre `tenant_admin` com UUID coincidente + +Foi identificado que o registro de `tenant_members` possui: + +- `tenant_id = 816b24fe-a0c3-4409-b79b-c6c0a6935d03` +- `user_id = 816b24fe-a0c3-4409-b79b-c6c0a6935d03` +- `role = tenant_admin` + +À primeira vista pode parecer inconsistência, mas não é. + +Verificação realizada: +O UUID `816b24fe-a0c3-4409-b79b-c6c0a6935d03` existe em `auth.users` +(email: admin@agenciapsi.com.br). + +Portanto: + +- `tenant_members.user_id` referencia corretamente `auth.users.id` +- Não há violação de integridade referencial +- O registro é válido + +Trata-se de um caso em que: + +- O usuário administrador principal possui um UUID específico +- O tenant foi criado com o mesmo UUID +- O administrador é `tenant_admin` desse próprio tenant + +Esse padrão não quebra a arquitetura multi-tenant e é funcionalmente válido. +A coincidência entre `tenant_id` e `user_id` é apenas estrutural, não conceitual. + +Conclusão: +Nenhuma correção estrutural é necessária. diff --git a/O-que-foi-feito.txt b/O-que-foi-feito.txt new file mode 100644 index 0000000..3fd539b --- /dev/null +++ b/O-que-foi-feito.txt @@ -0,0 +1,101 @@ +O que foi feito (até agora) +Usuários de teste criados + +admin@agenciapsi.com.br + — senha: 123Mudar@ + +patient@agenciapsi.com.br + — senha: 123Mudar@ + +therapist@agenciapsi.com.br + — senha: 123Mudar@ + +Base funcionando + +✅ Auth (Supabase) está funcionando +✅ Tabela profiles criada e ok +✅ Trigger automático cria profile após signup +✅ Campo role definido (admin | therapist | patient) +✅ RLS básico ativo +✅ Login funcionando +✅ Logout funcionando +✅ Guard de rota implementado e ativo +✅ RBAC básico operando via meta.role + redirect para painel correto +✅ Home pública / com 3 cards (Admin | Therapist | Patient) levando ao login +✅ Pós-login: busca profiles.role e redireciona para: + +/admin + +/therapist + +/patient + +Estrutura implementada agora (menus e sessão para o Sakai) +Sessão central (evita menu errado e if(role) espalhado) + +✅ Criado src/app/session.js com: + +sessionUser, sessionRole, sessionReady (refs globais) + +initSession() (carrega user + role antes de renderizar o layout) + +listenAuthChanges() (atualiza sessão ao logar/deslogar) + +✅ Ajustado src/main.js para usar bootstrap async: + +chama await initSession() antes de app.mount() + +liga listenAuthChanges() + +mantém PrimeVue, tema Aura, ToastService e ConfirmationService + +mantém imports de CSS existentes + +Menu dinâmico por role no Sakai + +✅ Menus foram estruturados no formato do Sakai (sections com label + items) e separados por role: + +src/navigation/menus/admin.menu.js + +src/navigation/menus/therapist.menu.js + +src/navigation/menus/patient.menu.js + +✅ Criado src/navigation/index.js com getMenuByRole(role) para centralizar a escolha do menu (sem if(role) em componentes). + +✅ Ajustado o AppMenu.vue (menu do Sakai) para: + +usar computed() com sessionRole/sessionReady + +carregar dinamicamente getMenuByRole(sessionRole.value) + +evitar “piscar” menu errado antes de carregar (sessionReady) + +Menu demo do Sakai mantido sem quebrar o produto + +✅ Mantivemos o menu demo (UIKit/Blocks/Start etc.) em arquivo separado para não perder as páginas do template: + +src/navigation/menus/sakai.demo.menu.js (conteúdo original do template) + +✅ Estratégia adotada: + +Admin pode ver o menu demo (idealmente só em DEV) + +Therapist/Patient ficam com menu limpo (clínico) + +Rotas demo do Sakai corrigidas (arquivos com sufixo Doc) + +✅ Problema resolvido: itens do menu demo davam 404 porque as rotas/imports não existiam com os nomes esperados (Input.vue etc.). +✅ Ajuste aplicado: rotas demo apontam para arquivos *Doc.vue (ex.: ButtonDoc.vue, InputDoc.vue). + +📌 Criado/ajustado src/router/routes.demo.js para mapear: + +/uikit/* → @/views/uikit/*Doc.vue + +e demais demos conforme existirem + +✅ Incluído demoRoutes no router principal para o menu demo funcionar. + +Testes + +✅ Confirmado que localStorage.clear() limpa sessão para testar outros usuários/roles rapidamente. \ No newline at end of file diff --git a/checklist-novo-chat.txt b/checklist-novo-chat.txt new file mode 100644 index 0000000..6f95736 --- /dev/null +++ b/checklist-novo-chat.txt @@ -0,0 +1,47 @@ +🔁 CONTEXTO DO PROJETO (SaaS multi-tenant) + +Stack: +- Supabase +- Multi-tenant por clinic/tenant +- Assinaturas por tenant (subscriptions.tenant_id) +- Controle de features: features, plan_features, subscription_intents, entitlementsStore, view v_tenant_entitlements +- Ativação manual: activate_subscription_from_intent() +- Merge concluído: agenda_online → online_scheduling.manage +- Entitlements e bloqueio PRO no menu funcionando +- Signup + intent funcionando; ativação cria subscription ativa; view retorna feature correta + +Modelo de “Contas” decidido: +- Auth user (login) ≠ Clínica (tenant) +- Clínica = tenant; Usuário pode ser dono/admin de clínica e também profissional +- Clínica convida usuários (tenant_members). Usuário pode aceitar/recusar. +- Profissional pode trabalhar anos e depois sair: clínica mantém registros; profissional mantém histórico (audit trail), sem acesso após saída. + +Regras de offboarding: +- Profissional só pode sair se NÃO houver agenda futura atribuída a ele. +- Se houver, cria “pedido de saída” e admin precisa realocar/cancelar; depois finaliza saída. + +Tabelas existentes: +- tenant_members: (id uuid pk, tenant_id uuid, user_id uuid, role text, status text, created_at timestamptz) + - UNIQUE (tenant_id, user_id) atualmente +- Agenda: agenda_eventos, agenda_excecoes, agenda_configuracoes, agenda_regras_semanais +- Outros: subscriptions, subscription_intents, plan_features, features, subscription_events + +O que estamos fazendo agora: +- Ajustar modelo de membership lifecycle e offboarding (exit_requests) +- Garantir integridade: histórico de vínculos + auditoria + bloqueio de saída com agenda futura +- Implementar SQL + RPC + RLS + UI (passo a passo) + +✔ subscriptions +Representa o plano da clínica (tenant) +✔ tenant_members +Define quais usuários pertencem à clínica +✔ entitlements + +Define o que aquela clínica pode usar + +Dados que faltam confirmar: +1) Estrutura de agenda_eventos (colunas e como relaciona com profissional) +2) Valores usados em tenant_members.status (active/invited/etc) +3) Estratégia de reentrada: remover UNIQUE (tenant_id,user_id) e usar unique parcial por status ativo/convite +4) Se existe tabela public.users como espelho do auth.users + diff --git a/package-lock.json b/package-lock.json index 35c04fc..58bb217 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,17 @@ { "name": "sakai-vue", - "version": "4.3.0", - "lockfileVersion": 3, + "version": "5.0.0", + "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "sakai-vue", - "version": "4.3.0", + "version": "5.0.0", "dependencies": { "@primeuix/themes": "^2.0.0", + "@supabase/supabase-js": "^2.95.3", "chart.js": "3.3.2", + "pinia": "^3.0.4", "primeicons": "^7.0.0", "primevue": "^4.5.4", "tailwindcss-primeui": "^0.6.0", @@ -22,11 +24,13 @@ "@tailwindcss/vite": "^4.1.17", "@vitejs/plugin-vue": "^5.0.5", "@vue/eslint-config-prettier": "^9.0.0", + "autoprefixer": "^10.4.24", "eslint": "^8.57.0", "eslint-plugin-vue": "^9.23.0", + "postcss": "^8.5.6", "prettier": "^3.2.5", "sass": "^1.55.0", - "tailwindcss": "^4.1.17", + "tailwindcss": "^4.1.18", "unplugin-vue-components": "^0.27.3", "vite": "^5.3.1" } @@ -36,7 +40,6 @@ "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" } @@ -45,7 +48,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -54,18 +56,16 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "license": "MIT", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -75,10 +75,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "license": "MIT", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" @@ -95,7 +94,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -112,7 +110,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -129,7 +126,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -146,7 +142,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -163,7 +158,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -180,7 +174,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -197,7 +190,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -214,7 +206,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -231,7 +222,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -248,7 +238,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -265,7 +254,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -282,7 +270,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -299,7 +286,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -316,7 +302,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -333,7 +318,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -350,7 +334,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -367,7 +350,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -384,7 +366,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -401,7 +382,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -418,7 +398,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -435,7 +414,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -452,7 +430,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -469,7 +446,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -479,11 +455,10 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -502,7 +477,6 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, - "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -512,7 +486,6 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -536,7 +509,6 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -547,7 +519,6 @@ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -562,7 +533,6 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -576,15 +546,13 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" @@ -595,7 +563,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -606,7 +573,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -614,15 +580,13 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -633,7 +597,6 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -647,7 +610,6 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } @@ -657,7 +619,6 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -667,18 +628,17 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "dependencies": { - "detect-libc": "^1.0.3", + "detect-libc": "^2.0.3", "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">= 10.0.0" @@ -688,30 +648,29 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -725,14 +684,13 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -746,14 +704,13 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -767,14 +724,13 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -788,14 +744,13 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -809,14 +764,13 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -830,14 +784,13 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -851,14 +804,13 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -872,14 +824,13 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -893,14 +844,13 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -914,14 +864,13 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -935,14 +884,13 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -956,14 +904,13 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -976,26 +923,11 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher/node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/@pkgr/core": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, - "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -1007,7 +939,6 @@ "version": "0.7.4", "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.7.4.tgz", "integrity": "sha512-QSO/NpOQg8e9BONWRBx9y8VGMCMYz0J/uKfNJEya/RGEu7ARx0oYW0ugI1N3/KB1AAvyGxzKBzGImbwg0KUiOQ==", - "license": "MIT", "dependencies": { "@primeuix/utils": "^0.6.1" }, @@ -1016,28 +947,25 @@ } }, "node_modules/@primeuix/styles": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-2.0.2.tgz", - "integrity": "sha512-LNtkJsTonNHF5ag+9s3+zQzm00+LRmffw68QRIHy6S/dam1JpdrrAnUzNYlWbaY7aE2EkZvQmx7Np7+PyHn+ow==", - "license": "MIT", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-2.0.3.tgz", + "integrity": "sha512-2ykAB6BaHzR/6TwF8ShpJTsZrid6cVIEBVlookSdvOdmlWuevGu5vWOScgIwqWwlZcvkFYAGR/SUV3OHCTBMdw==", "dependencies": { "@primeuix/styled": "^0.7.4" } }, "node_modules/@primeuix/themes": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@primeuix/themes/-/themes-2.0.2.tgz", - "integrity": "sha512-prwQvA3tDGBz8yWSUenaJUttEMCEvPvxwOfFhDPmSe1vwsfVKL2Nmh5eZvtPFQnxmIOPsHZS7zc0/L3CzJ83Eg==", - "license": "MIT", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@primeuix/themes/-/themes-2.0.3.tgz", + "integrity": "sha512-3fS1883mtCWhgUgNf/feiaaDSOND4EBIOu9tZnzJlJ8QtYyL6eFLcA6V3ymCWqLVXQ1+lTVEZv1gl47FIdXReg==", "dependencies": { "@primeuix/styled": "^0.7.4" } }, "node_modules/@primeuix/utils": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.6.3.tgz", - "integrity": "sha512-/SLNQSKQ73WbBIsflKVqbpVjCfFYvQO3Sf1LMheXyxh8JqxO4M63dzP56wwm9OPGuCQ6MYOd2AHgZXz+g7PZcg==", - "license": "MIT", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.6.4.tgz", + "integrity": "sha512-pZ5f+vj7wSzRhC7KoEQRU5fvYAe+RP9+m39CTscZ3UywCD1Y2o6Fe1rRgklMPSkzUcty2jzkA0zMYkiJBD1hgg==", "engines": { "node": ">=12.11.0" } @@ -1047,7 +975,6 @@ "resolved": "https://registry.npmjs.org/@primevue/auto-import-resolver/-/auto-import-resolver-4.5.4.tgz", "integrity": "sha512-YQHrZ9PQSG/4K2BwthA2Xuna4WyS0JMHajiHD9PljaDyQtBVwCadX5ZpKcrAUWR8E/1gjva8x/si0RYxxYrRJw==", "dev": true, - "license": "MIT", "dependencies": { "@primevue/metadata": "4.5.4" }, @@ -1059,7 +986,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.5.4.tgz", "integrity": "sha512-lYJJB3wTrDJ8MkLctzHfrPZAqXVxoatjIsswSJzupatf6ZogJHVYADUKcn1JAkLLk8dtV1FA2AxDek663fHO5Q==", - "license": "MIT", "dependencies": { "@primeuix/styled": "^0.7.4", "@primeuix/utils": "^0.6.2" @@ -1075,7 +1001,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.5.4.tgz", "integrity": "sha512-DxgryEc7ZmUqcEhYMcxGBRyFzdtLIoy3jLtlH1zsVSRZaG+iSAcjQ88nvfkZxGUZtZBFL7sRjF6KLq3bJZJwUw==", - "license": "MIT", "dependencies": { "@primeuix/utils": "^0.6.2", "@primevue/core": "4.5.4" @@ -1089,7 +1014,6 @@ "resolved": "https://registry.npmjs.org/@primevue/metadata/-/metadata-4.5.4.tgz", "integrity": "sha512-jJFD0KYm8bPYgFo0JP3Dc2RkyXzrMI1XHQGsEKTysx9Jx2d1XdxtFji/ZsQeoo/RmwUNof5ciZ72URq37rnK+g==", "dev": true, - "license": "MIT", "engines": { "node": ">=12.11.0" } @@ -1099,7 +1023,6 @@ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", @@ -1117,322 +1040,326 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", - "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", - "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", - "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", - "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", - "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", - "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", - "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", - "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", - "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", - "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", - "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", - "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", - "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", - "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", - "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", - "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", - "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", - "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openharmony" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", - "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", - "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", - "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", - "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1442,15 +1369,87 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz", "integrity": "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==", - "dev": true, - "license": "MIT" + "dev": true + }, + "node_modules/@supabase/auth-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.95.3.tgz", + "integrity": "sha512-vD2YoS8E2iKIX0F7EwXTmqhUpaNsmbU6X2R0/NdFcs02oEfnHyNP/3M716f3wVJ2E5XHGiTFXki6lRckhJ0Thg==", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.95.3.tgz", + "integrity": "sha512-uTuOAKzs9R/IovW1krO0ZbUHSJnsnyJElTXIRhjJTqymIVGcHzkAYnBCJqd7468Fs/Foz1BQ7Dv6DCl05lr7ig==", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.95.3.tgz", + "integrity": "sha512-LTrRBqU1gOovxRm1vRXPItSMPBmEFqrfTqdPTRtzOILV4jPSueFz6pES5hpb4LRlkFwCPRmv3nQJ5N625V2Xrg==", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.95.3.tgz", + "integrity": "sha512-D7EAtfU3w6BEUxDACjowWNJo/ZRo7sDIuhuOGKHIm9FHieGeoJV5R6GKTLtga/5l/6fDr2u+WcW/m8I9SYmaIw==", + "dependencies": { + "@types/phoenix": "^1.6.6", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.95.3.tgz", + "integrity": "sha512-4GxkJiXI3HHWjxpC3sDx1BVrV87O0hfX+wvJdqGv67KeCu+g44SPnII8y0LL/Wr677jB7tpjAxKdtVWf+xhc9A==", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.95.3.tgz", + "integrity": "sha512-Fukw1cUTQ6xdLiHDJhKKPu6svEPaCEDvThqCne3OaQyZvuq2qjhJAd91kJu3PXLG18aooCgYBaB6qQz35hhABg==", + "dependencies": { + "@supabase/auth-js": "2.95.3", + "@supabase/functions-js": "2.95.3", + "@supabase/postgrest-js": "2.95.3", + "@supabase/realtime-js": "2.95.3", + "@supabase/storage-js": "2.95.3" + }, + "engines": { + "node": ">=20.0.0" + } }, "node_modules/@tailwindcss/node": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", @@ -1466,7 +1465,6 @@ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" }, @@ -1493,7 +1491,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -1510,7 +1507,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -1527,7 +1523,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -1544,7 +1539,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -1561,7 +1555,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1578,7 +1571,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1595,7 +1587,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1612,7 +1603,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1629,7 +1619,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -1654,7 +1643,6 @@ "wasm32" ], "dev": true, - "license": "MIT", "optional": true, "dependencies": { "@emnapi/core": "^1.7.1", @@ -1676,7 +1664,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1693,7 +1680,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1707,7 +1693,6 @@ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz", "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==", "dev": true, - "license": "MIT", "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", @@ -1721,22 +1706,40 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" + "dev": true + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/phoenix": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dependencies": { + "@types/node": "*" + } }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" }, @@ -1746,39 +1749,36 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.26.tgz", - "integrity": "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz", + "integrity": "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.26", - "entities": "^7.0.0", + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.28", + "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.26.tgz", - "integrity": "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz", + "integrity": "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==", "dependencies": { - "@vue/compiler-core": "3.5.26", - "@vue/shared": "3.5.26" + "@vue/compiler-core": "3.5.28", + "@vue/shared": "3.5.28" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.26.tgz", - "integrity": "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz", + "integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.26", - "@vue/compiler-dom": "3.5.26", - "@vue/compiler-ssr": "3.5.26", - "@vue/shared": "3.5.26", + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.28", + "@vue/compiler-dom": "3.5.28", + "@vue/compiler-ssr": "3.5.28", + "@vue/shared": "3.5.28", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", @@ -1786,27 +1786,46 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.26.tgz", - "integrity": "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz", + "integrity": "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==", "dependencies": { - "@vue/compiler-dom": "3.5.26", - "@vue/shared": "3.5.26" + "@vue/compiler-dom": "3.5.28", + "@vue/shared": "3.5.28" } }, "node_modules/@vue/devtools-api": { "version": "6.6.4", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dependencies": { + "rfdc": "^1.4.1" + } }, "node_modules/@vue/eslint-config-prettier": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", "integrity": "sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==", "dev": true, - "license": "MIT", "dependencies": { "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0" @@ -1817,61 +1836,55 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.26.tgz", - "integrity": "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.28.tgz", + "integrity": "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==", "dependencies": { - "@vue/shared": "3.5.26" + "@vue/shared": "3.5.28" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.26.tgz", - "integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.28.tgz", + "integrity": "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==", "dependencies": { - "@vue/reactivity": "3.5.26", - "@vue/shared": "3.5.26" + "@vue/reactivity": "3.5.28", + "@vue/shared": "3.5.28" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.26.tgz", - "integrity": "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz", + "integrity": "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==", "dependencies": { - "@vue/reactivity": "3.5.26", - "@vue/runtime-core": "3.5.26", - "@vue/shared": "3.5.26", + "@vue/reactivity": "3.5.28", + "@vue/runtime-core": "3.5.28", + "@vue/shared": "3.5.28", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.26.tgz", - "integrity": "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.28.tgz", + "integrity": "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==", "dependencies": { - "@vue/compiler-ssr": "3.5.26", - "@vue/shared": "3.5.26" + "@vue/compiler-ssr": "3.5.28", + "@vue/shared": "3.5.28" }, "peerDependencies": { - "vue": "3.5.26" + "vue": "3.5.28" } }, "node_modules/@vue/shared": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.26.tgz", - "integrity": "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==", - "license": "MIT" + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.28.tgz", + "integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==" }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1884,7 +1897,6 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1894,7 +1906,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1911,7 +1922,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -1921,7 +1931,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1937,7 +1946,6 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1946,26 +1954,80 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", "dev": true, - "license": "Python-2.0" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001766", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", "dev": true, - "license": "MIT" + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -1973,19 +2035,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "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==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1996,7 +2064,6 @@ "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" }, @@ -2004,22 +2071,73 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2034,15 +2152,13 @@ "node_modules/chart.js": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.3.2.tgz", - "integrity": "sha512-H0hSO7xqTIrwxoACqnSoNromEMfXvfuVnrbuSt2TuXfBDDofbnto4zuZlRtRvC73/b37q3wGAWZyUU41QPvNbA==", - "license": "MIT" + "integrity": "sha512-H0hSO7xqTIrwxoACqnSoNromEMfXvfuVnrbuSt2TuXfBDDofbnto4zuZlRtRvC73/b37q3wGAWZyUU41QPvNbA==" }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, - "license": "MIT", "dependencies": { "readdirp": "^4.0.1" }, @@ -2058,7 +2174,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2070,29 +2185,39 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/confbox": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" + "dev": true + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2107,7 +2232,6 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, - "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -2118,15 +2242,13 @@ "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -2143,15 +2265,13 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -2161,7 +2281,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -2169,25 +2288,29 @@ "node": ">=6.0.0" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true + }, "node_modules/enhanced-resolve": { - "version": "5.18.4", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", - "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dev": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" } }, "node_modules/entities": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.0.tgz", - "integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==", - "license": "BSD-2-Clause", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "engines": { "node": ">=0.12" }, @@ -2201,7 +2324,6 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -2234,12 +2356,20 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -2253,7 +2383,6 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -2309,7 +2438,6 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, - "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -2318,14 +2446,13 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", - "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "dev": true, - "license": "MIT", "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -2353,7 +2480,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "globals": "^13.24.0", @@ -2376,7 +2502,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -2393,7 +2518,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2406,7 +2530,6 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -2420,11 +2543,10 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -2437,7 +2559,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -2450,7 +2571,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -2458,15 +2578,13 @@ "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -2475,22 +2593,19 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" + "dev": true }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -2507,7 +2622,6 @@ "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" }, @@ -2519,22 +2633,19 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, - "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -2544,7 +2655,6 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -2557,7 +2667,6 @@ "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" }, @@ -2570,7 +2679,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -2587,7 +2695,6 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, - "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -2601,15 +2708,26 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", "dev": true, - "license": "ISC" + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -2617,7 +2735,6 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -2630,9 +2747,8 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, - "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2653,7 +2769,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -2666,7 +2781,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -2681,32 +2795,41 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" + }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -2715,15 +2838,13 @@ "version": "5.1.4", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2740,7 +2861,6 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -2751,7 +2871,6 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, - "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2761,15 +2880,13 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -2782,7 +2899,6 @@ "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" } @@ -2792,7 +2908,6 @@ "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" }, @@ -2805,7 +2920,6 @@ "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" } @@ -2815,24 +2929,32 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, - "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -2842,7 +2964,6 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -2854,29 +2975,25 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -2886,7 +3003,6 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -2900,7 +3016,6 @@ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", "dev": true, - "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" }, @@ -2933,7 +3048,6 @@ "arm64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "android" @@ -2954,7 +3068,6 @@ "arm64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "darwin" @@ -2975,7 +3088,6 @@ "x64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "darwin" @@ -2996,7 +3108,6 @@ "x64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "freebsd" @@ -3017,7 +3128,6 @@ "arm" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3038,7 +3148,6 @@ "arm64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3059,7 +3168,6 @@ "arm64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3080,7 +3188,6 @@ "x64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3101,7 +3208,6 @@ "x64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3122,7 +3228,6 @@ "arm64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "win32" @@ -3143,7 +3248,6 @@ "x64" ], "dev": true, - "license": "MPL-2.0", "optional": true, "os": [ "win32" @@ -3161,7 +3265,6 @@ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", "dev": true, - "license": "MIT", "dependencies": { "mlly": "^1.7.3", "pkg-types": "^1.2.1" @@ -3178,7 +3281,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -3190,24 +3292,21 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, - "license": "MIT" + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } @@ -3217,7 +3316,6 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } @@ -3227,7 +3325,6 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -3236,12 +3333,23 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3249,12 +3357,16 @@ "node": "*" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + }, "node_modules/mlly": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", "dev": true, - "license": "MIT", "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", @@ -3266,8 +3378,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/nanoid": { "version": "3.3.11", @@ -3279,7 +3390,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -3291,23 +3401,26 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, - "license": "MIT", "optional": true }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3317,7 +3430,6 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -3330,7 +3442,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "license": "ISC", "dependencies": { "wrappy": "1" } @@ -3340,7 +3451,6 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -3358,7 +3468,6 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -3374,7 +3483,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -3390,7 +3498,6 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -3403,7 +3510,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -3413,7 +3519,6 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3423,7 +3528,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -3432,34 +3536,63 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" + "dev": true + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pinia": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", + "dependencies": { + "@vue/devtools-api": "^7.7.7" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.5.0", + "vue": "^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, "node_modules/pkg-types": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, - "license": "MIT", "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", @@ -3484,7 +3617,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -3499,7 +3631,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, - "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -3508,22 +3639,26 @@ "node": ">=4" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -3535,11 +3670,10 @@ } }, "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, - "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -3550,14 +3684,12 @@ "node_modules/primeicons": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz", - "integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==", - "license": "MIT" + "integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==" }, "node_modules/primevue": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.5.4.tgz", "integrity": "sha512-nTyEohZABFJhVIpeUxgP0EJ8vKcJAhD+Z7DYj95e7ie/MNUCjRNcGjqmE1cXtXi4z54qDfTSI9h2uJ51qz2DIw==", - "license": "MIT", "dependencies": { "@primeuix/styled": "^0.7.4", "@primeuix/styles": "^2.0.2", @@ -3574,7 +3706,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -3597,15 +3728,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 14.18.0" }, @@ -3619,7 +3748,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -3629,19 +3757,22 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, - "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -3653,11 +3784,10 @@ } }, "node_modules/rollup": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", - "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.8" }, @@ -3669,28 +3799,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.54.0", - "@rollup/rollup-android-arm64": "4.54.0", - "@rollup/rollup-darwin-arm64": "4.54.0", - "@rollup/rollup-darwin-x64": "4.54.0", - "@rollup/rollup-freebsd-arm64": "4.54.0", - "@rollup/rollup-freebsd-x64": "4.54.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", - "@rollup/rollup-linux-arm-musleabihf": "4.54.0", - "@rollup/rollup-linux-arm64-gnu": "4.54.0", - "@rollup/rollup-linux-arm64-musl": "4.54.0", - "@rollup/rollup-linux-loong64-gnu": "4.54.0", - "@rollup/rollup-linux-ppc64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-musl": "4.54.0", - "@rollup/rollup-linux-s390x-gnu": "4.54.0", - "@rollup/rollup-linux-x64-gnu": "4.54.0", - "@rollup/rollup-linux-x64-musl": "4.54.0", - "@rollup/rollup-openharmony-arm64": "4.54.0", - "@rollup/rollup-win32-arm64-msvc": "4.54.0", - "@rollup/rollup-win32-ia32-msvc": "4.54.0", - "@rollup/rollup-win32-x64-gnu": "4.54.0", - "@rollup/rollup-win32-x64-msvc": "4.54.0", + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" } }, @@ -3713,17 +3846,15 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/sass": { - "version": "1.97.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz", - "integrity": "sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", "dev": true, - "license": "MIT", "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -3740,11 +3871,10 @@ } }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3757,7 +3887,6 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3770,7 +3899,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -3779,7 +3907,14 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", "engines": { "node": ">=0.10.0" } @@ -3789,7 +3924,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3802,7 +3936,6 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -3810,12 +3943,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3824,11 +3967,10 @@ } }, "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, - "license": "MIT", "dependencies": { "@pkgr/core": "^0.2.9" }, @@ -3842,14 +3984,12 @@ "node_modules/tailwindcss": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", - "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", - "license": "MIT" + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==" }, "node_modules/tailwindcss-primeui": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/tailwindcss-primeui/-/tailwindcss-primeui-0.6.1.tgz", "integrity": "sha512-T69Rylcrmnt8zy9ik+qZvsLuRIrS9/k6rYJSIgZ1trnbEzGDDQSCIdmfyZknevqiHwpSJHSmQ9XT2C+S/hJY4A==", - "license": "MIT", "peerDependencies": { "tailwindcss": ">=3.1.0" } @@ -3859,7 +3999,6 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" }, @@ -3872,15 +4011,13 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3888,12 +4025,16 @@ "node": ">=8.0" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -3906,7 +4047,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -3915,18 +4055,21 @@ } }, "node_modules/ufo": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", - "dev": true, - "license": "MIT" + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==" }, "node_modules/unplugin": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", "dev": true, - "license": "MIT", "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" @@ -3940,7 +4083,6 @@ "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.5.tgz", "integrity": "sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg==", "dev": true, - "license": "MIT", "dependencies": { "@antfu/utils": "^0.7.10", "@rollup/pluginutils": "^5.1.3", @@ -3978,7 +4120,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -3988,7 +4129,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4013,7 +4153,6 @@ "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" }, @@ -4026,7 +4165,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4037,12 +4175,23 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/unplugin-vue-components/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/unplugin-vue-components/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -4050,12 +4199,41 @@ "node": ">=8.10.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -4064,15 +4242,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/vite": { "version": "5.4.21", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -4128,16 +4304,15 @@ } }, "node_modules/vue": { - "version": "3.5.26", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz", - "integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==", - "license": "MIT", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz", + "integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==", "dependencies": { - "@vue/compiler-dom": "3.5.26", - "@vue/compiler-sfc": "3.5.26", - "@vue/runtime-dom": "3.5.26", - "@vue/server-renderer": "3.5.26", - "@vue/shared": "3.5.26" + "@vue/compiler-dom": "3.5.28", + "@vue/compiler-sfc": "3.5.28", + "@vue/runtime-dom": "3.5.28", + "@vue/server-renderer": "3.5.28", + "@vue/shared": "3.5.28" }, "peerDependencies": { "typescript": "*" @@ -4153,7 +4328,6 @@ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.3.4", "eslint-scope": "^7.1.1", @@ -4177,7 +4351,6 @@ "version": "4.6.4", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", - "license": "MIT", "dependencies": { "@vue/devtools-api": "^6.6.4" }, @@ -4192,15 +4365,13 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -4216,7 +4387,6 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4225,15 +4395,33 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" + "dev": true + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=12" } @@ -4243,7 +4431,6 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -4251,5 +4438,2709 @@ "url": "https://github.com/sponsors/sindresorhus" } } + }, + "dependencies": { + "@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true + }, + "@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" + }, + "@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==" + }, + "@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "requires": { + "@babel/types": "^7.29.0" + } + }, + "@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "requires": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + } + }, + "@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "dev": true, + "optional": true + }, + "@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.4.3" + } + }, + "@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "optional": true, + "requires": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6", + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + } + }, + "@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "dev": true, + "optional": true + }, + "@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true + }, + "@primeuix/styled": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.7.4.tgz", + "integrity": "sha512-QSO/NpOQg8e9BONWRBx9y8VGMCMYz0J/uKfNJEya/RGEu7ARx0oYW0ugI1N3/KB1AAvyGxzKBzGImbwg0KUiOQ==", + "requires": { + "@primeuix/utils": "^0.6.1" + } + }, + "@primeuix/styles": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-2.0.3.tgz", + "integrity": "sha512-2ykAB6BaHzR/6TwF8ShpJTsZrid6cVIEBVlookSdvOdmlWuevGu5vWOScgIwqWwlZcvkFYAGR/SUV3OHCTBMdw==", + "requires": { + "@primeuix/styled": "^0.7.4" + } + }, + "@primeuix/themes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@primeuix/themes/-/themes-2.0.3.tgz", + "integrity": "sha512-3fS1883mtCWhgUgNf/feiaaDSOND4EBIOu9tZnzJlJ8QtYyL6eFLcA6V3ymCWqLVXQ1+lTVEZv1gl47FIdXReg==", + "requires": { + "@primeuix/styled": "^0.7.4" + } + }, + "@primeuix/utils": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.6.4.tgz", + "integrity": "sha512-pZ5f+vj7wSzRhC7KoEQRU5fvYAe+RP9+m39CTscZ3UywCD1Y2o6Fe1rRgklMPSkzUcty2jzkA0zMYkiJBD1hgg==" + }, + "@primevue/auto-import-resolver": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@primevue/auto-import-resolver/-/auto-import-resolver-4.5.4.tgz", + "integrity": "sha512-YQHrZ9PQSG/4K2BwthA2Xuna4WyS0JMHajiHD9PljaDyQtBVwCadX5ZpKcrAUWR8E/1gjva8x/si0RYxxYrRJw==", + "dev": true, + "requires": { + "@primevue/metadata": "4.5.4" + } + }, + "@primevue/core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.5.4.tgz", + "integrity": "sha512-lYJJB3wTrDJ8MkLctzHfrPZAqXVxoatjIsswSJzupatf6ZogJHVYADUKcn1JAkLLk8dtV1FA2AxDek663fHO5Q==", + "requires": { + "@primeuix/styled": "^0.7.4", + "@primeuix/utils": "^0.6.2" + } + }, + "@primevue/icons": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.5.4.tgz", + "integrity": "sha512-DxgryEc7ZmUqcEhYMcxGBRyFzdtLIoy3jLtlH1zsVSRZaG+iSAcjQ88nvfkZxGUZtZBFL7sRjF6KLq3bJZJwUw==", + "requires": { + "@primeuix/utils": "^0.6.2", + "@primevue/core": "4.5.4" + } + }, + "@primevue/metadata": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@primevue/metadata/-/metadata-4.5.4.tgz", + "integrity": "sha512-jJFD0KYm8bPYgFo0JP3Dc2RkyXzrMI1XHQGsEKTysx9Jx2d1XdxtFji/ZsQeoo/RmwUNof5ciZ72URq37rnK+g==", + "dev": true + }, + "@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + } + }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "dev": true, + "optional": true + }, + "@rushstack/eslint-patch": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz", + "integrity": "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==", + "dev": true + }, + "@supabase/auth-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.95.3.tgz", + "integrity": "sha512-vD2YoS8E2iKIX0F7EwXTmqhUpaNsmbU6X2R0/NdFcs02oEfnHyNP/3M716f3wVJ2E5XHGiTFXki6lRckhJ0Thg==", + "requires": { + "tslib": "2.8.1" + } + }, + "@supabase/functions-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.95.3.tgz", + "integrity": "sha512-uTuOAKzs9R/IovW1krO0ZbUHSJnsnyJElTXIRhjJTqymIVGcHzkAYnBCJqd7468Fs/Foz1BQ7Dv6DCl05lr7ig==", + "requires": { + "tslib": "2.8.1" + } + }, + "@supabase/postgrest-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.95.3.tgz", + "integrity": "sha512-LTrRBqU1gOovxRm1vRXPItSMPBmEFqrfTqdPTRtzOILV4jPSueFz6pES5hpb4LRlkFwCPRmv3nQJ5N625V2Xrg==", + "requires": { + "tslib": "2.8.1" + } + }, + "@supabase/realtime-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.95.3.tgz", + "integrity": "sha512-D7EAtfU3w6BEUxDACjowWNJo/ZRo7sDIuhuOGKHIm9FHieGeoJV5R6GKTLtga/5l/6fDr2u+WcW/m8I9SYmaIw==", + "requires": { + "@types/phoenix": "^1.6.6", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + } + }, + "@supabase/storage-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.95.3.tgz", + "integrity": "sha512-4GxkJiXI3HHWjxpC3sDx1BVrV87O0hfX+wvJdqGv67KeCu+g44SPnII8y0LL/Wr677jB7tpjAxKdtVWf+xhc9A==", + "requires": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + } + }, + "@supabase/supabase-js": { + "version": "2.95.3", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.95.3.tgz", + "integrity": "sha512-Fukw1cUTQ6xdLiHDJhKKPu6svEPaCEDvThqCne3OaQyZvuq2qjhJAd91kJu3PXLG18aooCgYBaB6qQz35hhABg==", + "requires": { + "@supabase/auth-js": "2.95.3", + "@supabase/functions-js": "2.95.3", + "@supabase/postgrest-js": "2.95.3", + "@supabase/realtime-js": "2.95.3", + "@supabase/storage-js": "2.95.3" + } + }, + "@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "dev": true, + "requires": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "dev": true, + "requires": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "dev": true, + "optional": true, + "requires": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + } + }, + "@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "dev": true, + "optional": true + }, + "@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "dev": true, + "optional": true + }, + "@tailwindcss/vite": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz", + "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==", + "dev": true, + "requires": { + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "tailwindcss": "4.1.18" + } + }, + "@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "requires": { + "undici-types": "~7.16.0" + } + }, + "@types/phoenix": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==" + }, + "@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "requires": { + "@types/node": "*" + } + }, + "@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true + }, + "@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "requires": {} + }, + "@vue/compiler-core": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz", + "integrity": "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==", + "requires": { + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.28", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "@vue/compiler-dom": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz", + "integrity": "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==", + "requires": { + "@vue/compiler-core": "3.5.28", + "@vue/shared": "3.5.28" + } + }, + "@vue/compiler-sfc": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz", + "integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==", + "requires": { + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.28", + "@vue/compiler-dom": "3.5.28", + "@vue/compiler-ssr": "3.5.28", + "@vue/shared": "3.5.28", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "@vue/compiler-ssr": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz", + "integrity": "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==", + "requires": { + "@vue/compiler-dom": "3.5.28", + "@vue/shared": "3.5.28" + } + }, + "@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + }, + "@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "requires": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "requires": { + "rfdc": "^1.4.1" + } + }, + "@vue/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==", + "dev": true, + "requires": { + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0" + } + }, + "@vue/reactivity": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.28.tgz", + "integrity": "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==", + "requires": { + "@vue/shared": "3.5.28" + } + }, + "@vue/runtime-core": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.28.tgz", + "integrity": "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==", + "requires": { + "@vue/reactivity": "3.5.28", + "@vue/shared": "3.5.28" + } + }, + "@vue/runtime-dom": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz", + "integrity": "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==", + "requires": { + "@vue/reactivity": "3.5.28", + "@vue/runtime-core": "3.5.28", + "@vue/shared": "3.5.28", + "csstype": "^3.2.3" + } + }, + "@vue/server-renderer": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.28.tgz", + "integrity": "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==", + "requires": { + "@vue/compiler-ssr": "3.5.28", + "@vue/shared": "3.5.28" + } + }, + "@vue/shared": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.28.tgz", + "integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==" + }, + "acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "dependencies": { + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + } + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "dev": true, + "requires": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001766", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true + }, + "binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true + }, + "birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "requires": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chart.js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.3.2.tgz", + "integrity": "sha512-H0hSO7xqTIrwxoACqnSoNromEMfXvfuVnrbuSt2TuXfBDDofbnto4zuZlRtRvC73/b37q3wGAWZyUU41QPvNbA==" + }, + "chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "requires": { + "readdirp": "^4.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "requires": { + "is-what": "^5.2.0" + } + }, + "cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + }, + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + } + }, + "entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==" + }, + "esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + } + }, + "eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", + "dev": true, + "requires": {} + }, + "eslint-plugin-prettier": { + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" + } + }, + "eslint-plugin-vue": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", + "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", + "xml-name-validator": "^4.0.0" + } + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "dependencies": { + "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, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" + }, + "iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==" + }, + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "immutable": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "dev": true + }, + "import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "requires": { + "detect-libc": "^2.0.3", + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "dev": true, + "optional": true + }, + "lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "dev": true, + "optional": true + }, + "lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "dev": true, + "optional": true + }, + "lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "dev": true, + "optional": true + }, + "lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "dev": true, + "optional": true + }, + "lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "dev": true, + "optional": true + }, + "lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "dev": true, + "optional": true + }, + "lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "dev": true, + "optional": true + }, + "local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "dev": true, + "requires": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "dependencies": { + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + } + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + }, + "mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "dev": true, + "requires": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + }, + "node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + }, + "perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true + }, + "pinia": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", + "requires": { + "@vue/devtools-api": "^7.7.7" + }, + "dependencies": { + "@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "requires": { + "@vue/devtools-kit": "^7.7.9" + } + } + } + }, + "pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "requires": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "requires": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "primeicons": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz", + "integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==" + }, + "primevue": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.5.4.tgz", + "integrity": "sha512-nTyEohZABFJhVIpeUxgP0EJ8vKcJAhD+Z7DYj95e7ie/MNUCjRNcGjqmE1cXtXi4z54qDfTSI9h2uJ51qz2DIw==", + "requires": { + "@primeuix/styled": "^0.7.4", + "@primeuix/styles": "^2.0.2", + "@primeuix/utils": "^0.6.2", + "@primevue/core": "4.5.4", + "@primevue/icons": "4.5.4" + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true + }, + "rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@types/estree": "1.0.8", + "fsevents": "~2.3.2" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "sass": { + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "dev": true, + "requires": { + "@parcel/watcher": "^2.4.1", + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" + }, + "speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "requires": { + "copy-anything": "^4" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "requires": { + "@pkgr/core": "^0.2.9" + } + }, + "tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==" + }, + "tailwindcss-primeui": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/tailwindcss-primeui/-/tailwindcss-primeui-0.6.1.tgz", + "integrity": "sha512-T69Rylcrmnt8zy9ik+qZvsLuRIrS9/k6rYJSIgZ1trnbEzGDDQSCIdmfyZknevqiHwpSJHSmQ9XT2C+S/hJY4A==", + "requires": {} + }, + "tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true + }, + "undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==" + }, + "unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "requires": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + } + }, + "unplugin-vue-components": { + "version": "0.27.5", + "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.5.tgz", + "integrity": "sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg==", + "dev": true, + "requires": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.3", + "chokidar": "^3.6.0", + "debug": "^4.3.7", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.1", + "magic-string": "^0.30.14", + "minimatch": "^9.0.5", + "mlly": "^1.7.3", + "unplugin": "^1.16.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "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, + "requires": { + "is-glob": "^4.0.1" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + } + } + }, + "update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "requires": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "requires": { + "esbuild": "^0.21.3", + "fsevents": "~2.3.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + } + }, + "vue": { + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz", + "integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==", + "requires": { + "@vue/compiler-dom": "3.5.28", + "@vue/compiler-sfc": "3.5.28", + "@vue/runtime-dom": "3.5.28", + "@vue/server-renderer": "3.5.28", + "@vue/shared": "3.5.28" + } + }, + "vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + } + }, + "vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "requires": { + "@vue/devtools-api": "^6.6.4" + } + }, + "webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "requires": {} + }, + "xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } } } diff --git a/package.json b/package.json index 32e1374..4e88faf 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ }, "dependencies": { "@primeuix/themes": "^2.0.0", + "@supabase/supabase-js": "^2.95.3", "chart.js": "3.3.2", + "pinia": "^3.0.4", "primeicons": "^7.0.0", "primevue": "^4.5.4", "tailwindcss-primeui": "^0.6.0", @@ -22,11 +24,13 @@ "@tailwindcss/vite": "^4.1.17", "@vitejs/plugin-vue": "^5.0.5", "@vue/eslint-config-prettier": "^9.0.0", + "autoprefixer": "^10.4.24", "eslint": "^8.57.0", "eslint-plugin-vue": "^9.23.0", + "postcss": "^8.5.6", "prettier": "^3.2.5", "sass": "^1.55.0", - "tailwindcss": "^4.1.17", + "tailwindcss": "^4.1.18", "unplugin-vue-components": "^0.27.3", "vite": "^5.3.1" } diff --git a/src/App.vue b/src/App.vue index f2f1b9f..ca93f6d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,25 @@ - + - - diff --git a/src/app/bootstrapUserSettings.js b/src/app/bootstrapUserSettings.js new file mode 100644 index 0000000..c1ea9d4 --- /dev/null +++ b/src/app/bootstrapUserSettings.js @@ -0,0 +1,112 @@ +import { supabase } from '@/lib/supabase/client' +import { useLayout } from '@/layout/composables/layout' +import { $t, updatePreset, updateSurfacePalette } from '@primeuix/themes' +import Aura from '@primeuix/themes/aura' +import Lara from '@primeuix/themes/lara' +import Nora from '@primeuix/themes/nora' + +const presets = { Aura, Lara, Nora } + +function safeEq (a, b) { + return String(a || '').trim() === String(b || '').trim() +} + +// copia do seu getPresetExt (ou exporta ele do Perfil pra reutilizar) +function getPresetExt(primaryColors, layoutConfig) { + const color = primaryColors.find((c) => c.name === layoutConfig.primary) || { name: 'noir', palette: {} } + + if (color.name === 'noir') { + return { + semantic: { + primary: { + 50: '{surface.50}', 100: '{surface.100}', 200: '{surface.200}', 300: '{surface.300}', + 400: '{surface.400}', 500: '{surface.500}', 600: '{surface.600}', 700: '{surface.700}', + 800: '{surface.800}', 900: '{surface.900}', 950: '{surface.950}' + }, + colorScheme: { + light: { + primary: { color: '{primary.950}', contrastColor: '#ffffff', hoverColor: '{primary.800}', activeColor: '{primary.700}' }, + highlight: { background: '{primary.950}', focusBackground: '{primary.700}', color: '#ffffff', focusColor: '#ffffff' } + }, + dark: { + primary: { color: '{primary.50}', contrastColor: '{primary.950}', hoverColor: '{primary.200}', activeColor: '{primary.300}' }, + highlight: { background: '{primary.50}', focusBackground: '{primary.300}', color: '{primary.950}', focusColor: '{primary.950}' } + } + } + } + } + } + + return { + semantic: { + primary: color.palette, + colorScheme: { + light: { + primary: { color: '{primary.500}', contrastColor: '#ffffff', hoverColor: '{primary.600}', activeColor: '{primary.700}' }, + highlight: { background: '{primary.50}', focusBackground: '{primary.100}', color: '{primary.700}', focusColor: '{primary.800}' } + }, + dark: { + primary: { color: '{primary.400}', contrastColor: '{surface.900}', hoverColor: '{primary.300}', activeColor: '{primary.200}' }, + highlight: { + background: 'color-mix(in srgb, {primary.400}, transparent 84%)', + focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)', + color: 'rgba(255,255,255,.87)', + focusColor: 'rgba(255,255,255,.87)' + } + } + } + } + } +} + +export async function bootstrapUserSettings({ + primaryColors = [], // passe a lista do seu Perfil (ou uma versão reduzida) + surfaces = [] // idem +} = {}) { + const { layoutConfig, isDarkTheme, toggleDarkMode, changeMenuMode } = useLayout() + + const { data: uRes, error: uErr } = await supabase.auth.getUser() + if (uErr) return + const user = uRes?.user + if (!user) return + + const { data: settings, error } = await supabase + .from('user_settings') + .select('theme_mode, preset, primary_color, surface_color, menu_mode') + .eq('user_id', user.id) + .maybeSingle() + + if (error || !settings) return + + // menu mode + if (settings.menu_mode && settings.menu_mode !== layoutConfig.menuMode) { + layoutConfig.menuMode = settings.menu_mode + changeMenuMode() + } + + // preset + if (settings.preset && settings.preset !== layoutConfig.preset) { + layoutConfig.preset = settings.preset + const presetValue = presets[settings.preset] || presets.Aura + const surfacePalette = surfaces.find(s => s.name === layoutConfig.surface)?.palette + $t().preset(presetValue).preset(getPresetExt(primaryColors, layoutConfig)).surfacePalette(surfacePalette).use({ useDefaultOptions: true }) + } + + // colors + if (settings.primary_color && !safeEq(settings.primary_color, layoutConfig.primary)) { + layoutConfig.primary = settings.primary_color + updatePreset(getPresetExt(primaryColors, layoutConfig)) + } + + if (settings.surface_color && !safeEq(settings.surface_color, layoutConfig.surface)) { + layoutConfig.surface = settings.surface_color + const surface = surfaces.find(s => s.name === settings.surface_color) + if (surface) updateSurfacePalette(surface.palette) + } + + // dark/light + if (settings.theme_mode) { + const shouldBeDark = settings.theme_mode === 'dark' + if (shouldBeDark !== isDarkTheme) toggleDarkMode() + } +} diff --git a/src/app/session.js b/src/app/session.js new file mode 100644 index 0000000..2776226 --- /dev/null +++ b/src/app/session.js @@ -0,0 +1,222 @@ +import { ref } from 'vue' +import { supabase } from '@/lib/supabase/client' + +/** + * ⚠️ IMPORTANTE — ESTABILIDADE DE NAVEGAÇÃO + * + * Este módulo controla a sessão global usada pelo router guard. + * + * Já houve uma condição de corrida entre: + * - visibilitychange → refreshSession() + * - supabase.auth.onAuthStateChange (SIGNED_IN) + * - router.beforeEach + * + * Quando a aba voltava ao foco, refreshSession() era disparado, + * o Supabase emitia SIGNED_IN redundante, e o guard aguardava + * tenant + entitlements simultaneamente à re-hidratação da sessão. + * + * Isso fazia a navegação "travar" no meio do beforeEach. + * + * Para evitar isso: + * - initSession usa singleflight (initPromise) + * - refreshSession não roda se já estiver refreshing + * - SIGNED_IN redundante é ignorado quando estado já está consistente + * + * NÃO remover esses controles sem entender o fluxo completo + * entre sessão, guard e carregamento de tenant/entitlements. + */ + +export const sessionUser = ref(null) +export const sessionRole = ref(null) +export const sessionIsSaasAdmin = ref(false) + +// só no primeiro boot +export const sessionReady = ref(false) + +// refresh leve (troca de aba / refresh token) sem desmontar UI +export const sessionRefreshing = ref(false) + +let onSignedOutCallback = null +export function setOnSignedOut (cb) { + onSignedOutCallback = typeof cb === 'function' ? cb : null +} + +// evita init concorrente +let initPromise = null + +async function fetchRole (userId) { + const { data, error } = await supabase + .from('profiles') + .select('role') + .eq('id', userId) + .single() + + if (error) return null + return data?.role || null +} + +async function fetchIsSaasAdmin (userId) { + const { data, error } = await supabase + .from('saas_admins') + .select('user_id') + .eq('user_id', userId) + .maybeSingle() + + if (error) return false + return !!data +} + +/** + * Atualiza estado a partir de uma session "confiável" (getSession() ou callback do auth). + * ⚠️ NÃO zera user/role durante refresh enquanto existir sessão. + */ +async function hydrateFromSession (sess) { + const user = sess?.user || null + if (!user?.id) return false + + const prevUid = sessionUser.value?.id || null + const uid = user.id + + // ✅ pega primeiro hydrate e troca de usuário + const userChanged = prevUid !== uid + + // atualiza user imediatamente (sem flicker) + sessionUser.value = user + + // ✅ saas admin: calcula no primeiro hydrate e sempre que trocar de user + // (no primeiro hydrate prevUid é null, então userChanged = true) + if (userChanged) { + sessionIsSaasAdmin.value = await fetchIsSaasAdmin(uid) + } + + // role: busca se não tem, ou se mudou user + if (!sessionRole.value || userChanged) { + sessionRole.value = await fetchRole(uid) + } + + return true +} + +/** + * Boot inicial (pode bloquear UI) ou refresh (não pode derrubar menu). + */ +export async function initSession ({ initial = false } = {}) { + if (initPromise) return initPromise + + if (initial) sessionReady.value = false + else sessionRefreshing.value = true + + initPromise = (async () => { + try { + const { data, error } = await supabase.auth.getSession() + if (error) throw error + + const sess = data?.session || null + const ok = await hydrateFromSession(sess) + + // se não tem sessão, zera estado (aqui pode, porque é init/refresh controlado) + if (!ok) { + sessionUser.value = null + sessionRole.value = null + sessionIsSaasAdmin.value = false + } + } catch (e) { + console.warn('[initSession] getSession falhou (tratando como sem sessão):', e) + // não deixa estourar pro router guard + sessionUser.value = null + sessionRole.value = null + sessionIsSaasAdmin.value = false + } + })() + + try { + await initPromise + } finally { + initPromise = null + if (initial) sessionReady.value = true + sessionRefreshing.value = false + } +} + +// refresh leve (troca de aba etc.) +export async function refreshSession () { + // ✅ evita corrida: se já está refreshing/init, não dispara outro + if (sessionRefreshing.value || initPromise) return + + const { data, error } = await supabase.auth.getSession() + if (error) return + + const sess = data?.session || null + const uid = sess?.user?.id || null + + // se não tem sessão, não zera aqui (deixa SIGNED_OUT cuidar) + if (!uid) return + + // se já está consistente, não faz nada + if (sessionUser.value?.id === uid && sessionRole.value) return + + await initSession({ initial: false }) +} + +// evita múltiplos listeners +let authSubscription = null + +export function listenAuthChanges () { + if (authSubscription) return + + const { data } = supabase.auth.onAuthStateChange(async (event, sess) => { + console.log('[AUTH EVENT]', event) + + // ✅ SIGNED_OUT: zera e chama callback + if (event === 'SIGNED_OUT') { + sessionUser.value = null + sessionRole.value = null + sessionIsSaasAdmin.value = false + sessionRefreshing.value = false + sessionReady.value = true + if (onSignedOutCallback) onSignedOutCallback() + return + } + + // ✅ se já está consistente, ignora SIGNED_IN redundante + if (event === 'SIGNED_IN') { + const uid = sess?.user?.id || null + if (uid && sessionReady.value && sessionUser.value?.id === uid && sessionRole.value) { + return + } + } + + // ✅ use a session fornecida no callback + if (sess?.user?.id) { + // evita reentrância + if (sessionRefreshing.value) return + + sessionRefreshing.value = true + try { + await hydrateFromSession(sess) + sessionReady.value = true + } catch (e) { + console.warn('[auth hydrate error]', e) + } finally { + sessionRefreshing.value = false + } + return + } + + // fallback: refresh leve + try { + await refreshSession() + } catch (e) { + console.error('[refreshSession error]', e) + } + }) + + authSubscription = data?.subscription || null +} + +export function stopAuthChanges () { + if (authSubscription) { + authSubscription.unsubscribe() + authSubscription = null + } +} diff --git a/src/components/ComponentCadastroRapido.vue b/src/components/ComponentCadastroRapido.vue new file mode 100644 index 0000000..3a24cc7 --- /dev/null +++ b/src/components/ComponentCadastroRapido.vue @@ -0,0 +1,251 @@ + + + diff --git a/src/components/agenda/AgendaOnlineGradeCard.vue b/src/components/agenda/AgendaOnlineGradeCard.vue new file mode 100644 index 0000000..b3c202b --- /dev/null +++ b/src/components/agenda/AgendaOnlineGradeCard.vue @@ -0,0 +1,220 @@ + + + + diff --git a/src/components/agenda/AgendaSlotsPorDiaCard.vue b/src/components/agenda/AgendaSlotsPorDiaCard.vue new file mode 100644 index 0000000..5407b36 --- /dev/null +++ b/src/components/agenda/AgendaSlotsPorDiaCard.vue @@ -0,0 +1,183 @@ + + + + diff --git a/src/components/dashboard/RecentSalesWidget.vue b/src/components/dashboard/RecentSalesWidget.vue index 00d6b0d..7fc62ac 100644 --- a/src/components/dashboard/RecentSalesWidget.vue +++ b/src/components/dashboard/RecentSalesWidget.vue @@ -1,5 +1,5 @@ + + diff --git a/src/composables/useAuth.js b/src/composables/useAuth.js new file mode 100644 index 0000000..dc32818 --- /dev/null +++ b/src/composables/useAuth.js @@ -0,0 +1,19 @@ +import { ref, onMounted } from 'vue' +import { supabase } from '@/lib/supabase/client' + +const user = ref(null) + +export function useAuth() { + const init = async () => { + const { data } = await supabase.auth.getSession() + user.value = data.session?.user || null + } + + supabase.auth.onAuthStateChange((_, session) => { + user.value = session?.user || null + }) + + onMounted(init) + + return { user } +} diff --git a/src/composables/useUserSettingsPersistence.js b/src/composables/useUserSettingsPersistence.js new file mode 100644 index 0000000..b4d88bd --- /dev/null +++ b/src/composables/useUserSettingsPersistence.js @@ -0,0 +1,114 @@ +// src/composables/useUserSettingsPersistence.js +import { ref } from 'vue' +import { supabase } from '@/lib/supabase/client' +import { useLayout } from '@/layout/composables/layout' + +export function useUserSettingsPersistence() { + const { layoutConfig } = useLayout() + + const userId = ref('') + const saveTimer = ref(null) + const pendingPatch = ref({}) + const initializing = ref(false) + + function isDarkNow() { + return document.documentElement.classList.contains('app-dark') + } + + async function init() { + if (initializing.value) return + initializing.value = true + try { + const { data, error } = await supabase.auth.getUser() + if (error) throw error + userId.value = data?.user?.id || '' + console.log('[user_settings] init userId =', userId.value) + } finally { + initializing.value = false + } + } + + async function flush() { + if (!userId.value) { + console.warn('[user_settings] flush cancelado: sem userId') + return + } + + const patch = { ...pendingPatch.value } + pendingPatch.value = {} + + const payload = { + user_id: userId.value, + theme_mode: patch.theme_mode ?? (isDarkNow() ? 'dark' : 'light'), + preset: patch.preset ?? layoutConfig.preset ?? 'Aura', + primary_color: patch.primary_color ?? layoutConfig.primary ?? 'noir', + surface_color: patch.surface_color ?? layoutConfig.surface ?? 'slate', + menu_mode: patch.menu_mode ?? layoutConfig.menuMode ?? 'static', + updated_at: new Date().toISOString() + } + + console.log('[user_settings] flush payload =', payload) + + const { error } = await supabase + .from('user_settings') + .upsert(payload, { onConflict: 'user_id' }) + + if (error) { + console.error('[user_settings] flush falhou:', error.message || error) + throw error + } + } + + /** + * @param {object} patch + * @param {object} opts + * @param {number} opts.debounceMs + * @param {boolean} opts.flushNow + */ + function queuePatch(patch, opts = {}) { + const debounceMs = typeof opts.debounceMs === 'number' ? opts.debounceMs : 500 + const flushNow = !!opts.flushNow + + pendingPatch.value = { ...pendingPatch.value, ...patch } + + if (saveTimer.value) clearTimeout(saveTimer.value) + + const run = async () => { + if (!userId.value) return + + const payload = { + user_id: userId.value, + theme_mode: pendingPatch.value.theme_mode ?? (isDarkNow() ? 'dark' : 'light'), + preset: pendingPatch.value.preset ?? layoutConfig.preset, + primary_color: pendingPatch.value.primary_color ?? layoutConfig.primary, + surface_color: pendingPatch.value.surface_color ?? layoutConfig.surface, + menu_mode: pendingPatch.value.menu_mode ?? layoutConfig.menuMode, + updated_at: new Date().toISOString() + } + + pendingPatch.value = {} + + const { error } = await supabase + .from('user_settings') + .upsert(payload, { onConflict: 'user_id' }) + + if (error) { + console.error('[user_settings] save falhou:', error?.message || error, payload) + throw error + } + + console.log('[user_settings] saved:', payload) + } + + if (flushNow) return run() + + saveTimer.value = setTimeout(run, debounceMs) + } + + + return { + init, + queuePatch, + flush + } +} diff --git a/src/constants/roles.js b/src/constants/roles.js new file mode 100644 index 0000000..b783efa --- /dev/null +++ b/src/constants/roles.js @@ -0,0 +1,11 @@ +export const ROLES = { + ADMIN: 'admin', + THERAPIST: 'therapist', + PATIENT: 'patient' +} + +export const ROLE_HOME = { + admin: '/admin', + therapist: '/therapist', + patient: '/patient' +} diff --git a/src/layout/AdminLayout.vue b/src/layout/AdminLayout.vue new file mode 100644 index 0000000..af8ba43 --- /dev/null +++ b/src/layout/AdminLayout.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/layout/AppConfigurator.vue b/src/layout/AppConfigurator.vue index 5400f52..fe1698a 100644 --- a/src/layout/AppConfigurator.vue +++ b/src/layout/AppConfigurator.vue @@ -1,243 +1,119 @@ diff --git a/src/layout/AppMenu.vue b/src/layout/AppMenu.vue index 540c143..924ae3d 100644 --- a/src/layout/AppMenu.vue +++ b/src/layout/AppMenu.vue @@ -1,271 +1,483 @@ +
+ +
+
+ + + + + + + - + + +
+ + +
+
+ Recentes + +
+ + +
+ + +
+ +
+ +
+ Nenhum item encontrado. +
+ + +
+ Ctrl+K/Cmd+K focar + ↑↓ navegar + Enter abrir + Esc fechar +
+ + +
+ Dica: pressione Ctrl + K (ou Cmd + K) para buscar. +
+
+ + +
+
    + +
+
+ + + + + +
+ diff --git a/src/layout/AppMenuFooterPanel.vue b/src/layout/AppMenuFooterPanel.vue new file mode 100644 index 0000000..9e9125d --- /dev/null +++ b/src/layout/AppMenuFooterPanel.vue @@ -0,0 +1,189 @@ + + + diff --git a/src/layout/AppMenuItem.vue b/src/layout/AppMenuItem.vue index 47adb65..68624e4 100644 --- a/src/layout/AppMenuItem.vue +++ b/src/layout/AppMenuItem.vue @@ -1,78 +1,225 @@ diff --git a/src/layout/AppShellLayout.vue b/src/layout/AppShellLayout.vue new file mode 100644 index 0000000..2cb252b --- /dev/null +++ b/src/layout/AppShellLayout.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/layout/AppTopbar.vue b/src/layout/AppTopbar.vue index 82f489d..24fc5f4 100644 --- a/src/layout/AppTopbar.vue +++ b/src/layout/AppTopbar.vue @@ -1,79 +1,304 @@ diff --git a/src/layout/ConfiguracoesPage.vue b/src/layout/ConfiguracoesPage.vue new file mode 100644 index 0000000..0f0a983 --- /dev/null +++ b/src/layout/ConfiguracoesPage.vue @@ -0,0 +1,175 @@ + + + + diff --git a/src/layout/PatientLayout.vue b/src/layout/PatientLayout.vue new file mode 100644 index 0000000..af8ba43 --- /dev/null +++ b/src/layout/PatientLayout.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/layout/TherapistLayout.vue b/src/layout/TherapistLayout.vue new file mode 100644 index 0000000..af8ba43 --- /dev/null +++ b/src/layout/TherapistLayout.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/layout/composables/layout.js b/src/layout/composables/layout.js index 2ea7f06..0187fb7 100644 --- a/src/layout/composables/layout.js +++ b/src/layout/composables/layout.js @@ -1,86 +1,96 @@ -import { computed, reactive } from 'vue'; +import { computed, reactive } from 'vue' const layoutConfig = reactive({ - preset: 'Aura', - primary: 'emerald', - surface: null, - darkTheme: false, - menuMode: 'static' -}); + preset: 'Aura', + primary: 'emerald', + surface: null, + darkTheme: false, + menuMode: 'static' +}) const layoutState = reactive({ - staticMenuInactive: false, - overlayMenuActive: false, - profileSidebarVisible: false, - configSidebarVisible: false, - sidebarExpanded: false, - menuHoverActive: false, - activeMenuItem: null, - activePath: null -}); + staticMenuInactive: false, + overlayMenuActive: false, + mobileMenuActive: false, // ✅ ADICIONA (estava faltando) + profileSidebarVisible: false, + configSidebarVisible: false, + sidebarExpanded: false, + menuHoverActive: false, + activeMenuItem: null, + activePath: null +}) -export function useLayout() { - const toggleDarkMode = () => { - if (!document.startViewTransition) { - executeDarkModeToggle(); +export function useLayout () { + const toggleDarkMode = () => { + if (!document.startViewTransition) { + executeDarkModeToggle() + return + } - return; - } + document.startViewTransition(() => executeDarkModeToggle(event)) + } - document.startViewTransition(() => executeDarkModeToggle(event)); - }; + const executeDarkModeToggle = () => { + layoutConfig.darkTheme = !layoutConfig.darkTheme + document.documentElement.classList.toggle('app-dark') + } - const executeDarkModeToggle = () => { - layoutConfig.darkTheme = !layoutConfig.darkTheme; - document.documentElement.classList.toggle('app-dark'); - }; + const isDesktop = () => window.innerWidth > 991 - const toggleMenu = () => { - if (isDesktop()) { - if (layoutConfig.menuMode === 'static') { - layoutState.staticMenuInactive = !layoutState.staticMenuInactive; - } + const toggleMenu = () => { + if (isDesktop()) { + if (layoutConfig.menuMode === 'static') { + layoutState.staticMenuInactive = !layoutState.staticMenuInactive + } - if (layoutConfig.menuMode === 'overlay') { - layoutState.overlayMenuActive = !layoutState.overlayMenuActive; - } - } else { - layoutState.mobileMenuActive = !layoutState.mobileMenuActive; - } - }; + if (layoutConfig.menuMode === 'overlay') { + layoutState.overlayMenuActive = !layoutState.overlayMenuActive + } + } else { + layoutState.mobileMenuActive = !layoutState.mobileMenuActive + } + } - const toggleConfigSidebar = () => { - layoutState.configSidebarVisible = !layoutState.configSidebarVisible; - }; + const toggleConfigSidebar = () => { + layoutState.configSidebarVisible = !layoutState.configSidebarVisible + } - const hideMobileMenu = () => { - layoutState.mobileMenuActive = false; - }; + const hideMobileMenu = () => { + layoutState.mobileMenuActive = false + } - const changeMenuMode = (event) => { - layoutConfig.menuMode = event.value; - layoutState.staticMenuInactive = false; - layoutState.mobileMenuActive = false; - layoutState.sidebarExpanded = false; - layoutState.menuHoverActive = false; - layoutState.anchored = false; - }; + // ✅ use isso ao navegar: mantém menu aberto no desktop, fecha só no mobile + const closeMenuOnNavigate = () => { + if (!isDesktop()) { + layoutState.mobileMenuActive = false + layoutState.overlayMenuActive = false + layoutState.menuHoverActive = false + } + } - const isDarkTheme = computed(() => layoutConfig.darkTheme); - const isDesktop = () => window.innerWidth > 991; + const changeMenuMode = (event) => { + layoutConfig.menuMode = event.value + layoutState.staticMenuInactive = false + layoutState.mobileMenuActive = false + layoutState.sidebarExpanded = false + layoutState.menuHoverActive = false + layoutState.anchored = false + } - const hasOpenOverlay = computed(() => layoutState.overlayMenuActive); + const isDarkTheme = computed(() => layoutConfig.darkTheme) + const hasOpenOverlay = computed(() => layoutState.overlayMenuActive) - return { - layoutConfig, - layoutState, - isDarkTheme, - toggleDarkMode, - toggleConfigSidebar, - toggleMenu, - hideMobileMenu, - changeMenuMode, - isDesktop, - hasOpenOverlay - }; + return { + layoutConfig, + layoutState, + isDarkTheme, + toggleDarkMode, + toggleConfigSidebar, + toggleMenu, + hideMobileMenu, + closeMenuOnNavigate, // ✅ exporta + changeMenuMode, + isDesktop, + hasOpenOverlay + } } diff --git a/src/layout/configuracoes/ConfiguracoesAgendaPage.vue b/src/layout/configuracoes/ConfiguracoesAgendaPage.vue new file mode 100644 index 0000000..29a4eae --- /dev/null +++ b/src/layout/configuracoes/ConfiguracoesAgendaPage.vue @@ -0,0 +1,1392 @@ + + + + diff --git a/src/layout/configuracoes/ConfiguracoesClinicaPage.vue b/src/layout/configuracoes/ConfiguracoesClinicaPage.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/layout/configuracoes/ConfiguracoesContaPage.vue b/src/layout/configuracoes/ConfiguracoesContaPage.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/layout/configuracoes/ConfiguracoesIntakePage.vue b/src/layout/configuracoes/ConfiguracoesIntakePage.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/main.js b/src/main.js index d974b9e..32a5aa9 100644 --- a/src/main.js +++ b/src/main.js @@ -1,27 +1,112 @@ -import { createApp } from 'vue'; -import App from './App.vue'; -import router from './router'; +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import App from './App.vue' +import router from '@/router' +import { setOnSignedOut, initSession, listenAuthChanges, refreshSession } from '@/app/session' -import Aura from '@primeuix/themes/aura'; -import PrimeVue from 'primevue/config'; -import ConfirmationService from 'primevue/confirmationservice'; -import ToastService from 'primevue/toastservice'; +import Aura from '@primeuix/themes/aura' +import PrimeVue from 'primevue/config' +import ConfirmationService from 'primevue/confirmationservice' +import ToastService from 'primevue/toastservice' -import '@/assets/tailwind.css'; -import '@/assets/styles.scss'; +import '@/assets/tailwind.css' +import '@/assets/styles.scss' -const app = createApp(App); +import { supabase } from '@/lib/supabase/client' -app.use(router); -app.use(PrimeVue, { +async function applyUserThemeEarly() { + try { + const { data } = await supabase.auth.getUser() + const user = data?.user + if (!user) return + + const { data: settings, error } = await supabase + .from('user_settings') + .select('theme_mode') + .eq('user_id', user.id) + .maybeSingle() + + if (error || !settings?.theme_mode) return + + const isDark = settings.theme_mode === 'dark' + + // o PrimeVue usa o selector .app-dark + const root = document.documentElement + root.classList.toggle('app-dark', isDark) + + // opcional: marca em storage pra teu layout composable ler depois + localStorage.setItem('ui_theme_mode', settings.theme_mode) + } catch {} +} + +setOnSignedOut(() => { + router.replace('/auth/login') +}) + +// ===== flags globais (debug/controle) ===== +window.__sessionRefreshing = false +window.__fromVisibilityRefresh = false +window.__appBootstrapped = false +// ======================================== + +// 🛟 ao voltar da aba: refresh leve (sem concorrência + com flag global) +let refreshing = false +let refreshTimer = null + +let lastVisibilityRefreshAt = 0 + +document.addEventListener('visibilitychange', async () => { + if (document.visibilityState !== 'visible') return + + const now = Date.now() + + // evita martelar: no máximo 1 refresh a cada 10s + if (now - lastVisibilityRefreshAt < 10_000) return + + // se já tem refresh em andamento, não entra + if (window.__sessionRefreshing) return + + lastVisibilityRefreshAt = now + console.log('[VISIBILITY] Aba voltou -> refreshSession()') + + try { + window.__sessionRefreshing = true + await refreshSession() + } finally { + window.__sessionRefreshing = false + } +}) + + +async function bootstrap () { + await initSession({ initial: true }) + listenAuthChanges() + + await applyUserThemeEarly() + + const app = createApp(App) + + const pinia = createPinia() + app.use(pinia) + + app.use(router) + + // ✅ garante router pronto antes de montar + await router.isReady() + + app.use(PrimeVue, { theme: { - preset: Aura, - options: { - darkModeSelector: '.app-dark' - } + preset: Aura, + options: { darkModeSelector: '.app-dark' } } -}); -app.use(ToastService); -app.use(ConfirmationService); + }) + app.use(ToastService) + app.use(ConfirmationService) -app.mount('#app'); + app.mount('#app') + + // ✅ marca boot completo + window.__appBootstrapped = true +} + +bootstrap() diff --git a/src/navigation/index.js b/src/navigation/index.js new file mode 100644 index 0000000..fde1bad --- /dev/null +++ b/src/navigation/index.js @@ -0,0 +1,54 @@ +// src/navigation/index.js +import adminMenu from './menus/admin.menu' +import therapistMenu from './menus/therapist.menu' +import patientMenu from './menus/patient.menu' +import sakaiDemoMenu from './menus/sakai.demo.menu' +import saasMenu from './menus/saas.menu' + +import { useSaasHealthStore } from '@/stores/saasHealthStore' + +const MENUS = { + admin: adminMenu, + therapist: therapistMenu, + patient: patientMenu +} + +// aceita export de menu como ARRAY ou como FUNÇÃO (ctx) => [] +function resolveMenu (builder, ctx) { + if (!builder) return [] + return typeof builder === 'function' ? builder(ctx) : builder +} + +/** + * role: vem do seu contexto (admin/therapist/patient) + * sessionCtx: objeto que tenha { isSaasAdmin: boolean } (ex.: authStore, sessionStore, etc.) + */ +export function getMenuByRole (role, sessionCtx) { + const base = resolveMenu(MENUS[role], sessionCtx) + + // ✅ badge dinâmica do Health (contador vem do store) + // ⚠️ não faz fetch aqui: o AppMenu carrega o store. + const saasHealthStore = useSaasHealthStore() + const mismatchCount = saasHealthStore?.mismatchCount || 0 + + // ✅ menu SaaS entra como overlay, não depende de role + // passa opts com mismatchCount (saas.menu.js vai usar pra badge) + const saas = typeof saasMenu === 'function' + ? saasMenu(sessionCtx, { mismatchCount }) + : saasMenu + + // ✅ mantém demos disponíveis para admin em DEV (não polui prod) + if (role === 'admin' && import.meta.env.DEV) { + return [ + ...base, + ...(saas.length ? [{ separator: true }, ...saas] : []), + { separator: true }, + ...sakaiDemoMenu + ] + } + + return [ + ...base, + ...(saas.length ? [{ separator: true }, ...saas] : []) + ] +} diff --git a/src/navigation/menus/admin.menu.js b/src/navigation/menus/admin.menu.js new file mode 100644 index 0000000..dce0f6a --- /dev/null +++ b/src/navigation/menus/admin.menu.js @@ -0,0 +1,76 @@ +export default [ + { + label: 'Admin', + items: [ + { + label: 'Dashboard', + icon: 'pi pi-fw pi-home', + to: '/admin' + }, + { + label: 'Clínicas', + icon: 'pi pi-fw pi-building', + to: '/admin/clinics' + }, + { + label: 'Usuários', + icon: 'pi pi-fw pi-users', + to: '/admin/users' + }, + { + label: 'Assinatura', + icon: 'pi pi-fw pi-credit-card', + to: '/admin/billing' + }, + + // 🔒 MÓDULO PRO (exemplo) + { + label: 'Agendamento Online (PRO)', + icon: 'pi pi-fw pi-calendar', + to: '/admin/online-scheduling', + feature: 'online_scheduling.manage', + proBadge: true + }, + + // ✅ ajustado para bater com sua rota "configuracoes" + { + label: 'Segurança', + icon: 'pi pi-fw pi-shield', + to: '/admin/configuracoes/seguranca' + } + ] + }, + { + label: 'Pacientes', + items: [ + { + label: 'Meus Pacientes', + icon: 'pi pi-list', + to: '/admin/pacientes', + quickCreate: true, + quickCreateFullTo: '/admin/pacientes/novo', + quickCreateEntity: 'patient' + }, + { + label: 'Grupos de pacientes', + icon: 'pi pi-fw pi-users', + to: '/admin/pacientes/grupos' + }, + { + label: 'Tags', + icon: 'pi pi-tags', + to: '/admin/pacientes/tags' + }, + { + label: 'Link externo (Cadastro)', + icon: 'pi pi-link', + to: '/admin/pacientes/link-externo' + }, + { + label: 'Cadastros Recebidos', + icon: 'pi pi-inbox', + to: '/admin/pacientes/cadastro/recebidos' + } + ] + } +] diff --git a/src/navigation/menus/patient.menu.js b/src/navigation/menus/patient.menu.js new file mode 100644 index 0000000..974984c --- /dev/null +++ b/src/navigation/menus/patient.menu.js @@ -0,0 +1,59 @@ +export default [ + { + label: 'Paciente', + items: [ + // ====================== + // ✅ Básico (sempre) + // ====================== + { label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/patient' }, + + { label: 'Consultas', icon: 'pi pi-fw pi-calendar-plus', to: '/patient/appointments' }, + + { label: 'Meu Perfil', icon: 'pi pi-fw pi-user', to: '/patient/profile' }, + + { + label: 'Agendamento online', + icon: 'pi pi-fw pi-globe', + to: '/patient/online-scheduling', + feature: 'online_scheduling.manage', + proBadge: true + }, + + // ===================================================== + // 🔒 PRO (exemplos futuros no portal do paciente) + // ===================================================== + // A lógica do AppMenuItem que ajustamos suporta: + // - feature: 'chave_da_feature' + // - proBadge: true -> aparece "PRO" quando bloqueado + // + // ⚠️ Só descomente quando a rota existir. + // + // 1) Página pública de agendamento (se você criar um “link do paciente”) + // { + // label: 'Agendar online', + // icon: 'pi pi-fw pi-globe', + // to: '/patient/online-scheduling', + // feature: 'online_scheduling.public', + // proBadge: true + // }, + // + // 2) Documentos/Arquivos (muito comum em SaaS clínico) + // { + // label: 'Documentos', + // icon: 'pi pi-fw pi-file', + // to: '/patient/documents', + // feature: 'patient_documents', + // proBadge: true + // }, + // + // 3) Teleatendimento / Sala (se for ter) + // { + // label: 'Sala de atendimento', + // icon: 'pi pi-fw pi-video', + // to: '/patient/telehealth', + // feature: 'telehealth', + // proBadge: true + // } + ] + } +] diff --git a/src/navigation/menus/saas.menu.js b/src/navigation/menus/saas.menu.js new file mode 100644 index 0000000..17b95d9 --- /dev/null +++ b/src/navigation/menus/saas.menu.js @@ -0,0 +1,58 @@ +// src/navigation/menus/saas.menu.js + +export default function saasMenu (authStore, opts = {}) { + if (!authStore?.isSaasAdmin) return [] + + const mismatchCount = Number(opts?.mismatchCount || 0) + + return [ + { + label: 'SaaS', + icon: 'pi pi-building', + path: '/saas', // ✅ necessário p/ expandir e controlar activePath + items: [ + { label: 'Dashboard', icon: 'pi pi-chart-bar', to: '/saas' }, + + { + label: 'Planos', + icon: 'pi pi-star', + path: '/plans', // ✅ vira /saas/plans pelo parentPath + items: [ + { label: 'Listagem de Planos', icon: 'pi pi-list', to: '/saas/plans' }, + + // ✅ NOVO: vitrine pública (pricing page) + { label: 'Vitrine Pública', icon: 'pi pi-megaphone', to: '/saas/plans-public' }, + + { label: 'Recursos', icon: 'pi pi-bolt', to: '/saas/features' }, + { label: 'Controle de Recursos', icon: 'pi pi-th-large', to: '/saas/plan-features' } + ] + }, + + { + label: 'Assinaturas', + icon: 'pi pi-credit-card', + path: '/subscriptions', // ✅ vira /saas/subscriptions + items: [ + { label: 'Listagem de Assinaturas', icon: 'pi pi-list', to: '/saas/subscriptions' }, + { label: 'Histórico', icon: 'pi pi-history', to: '/saas/subscription-events' }, + { + label: 'Saúde das Assinaturas', + icon: 'pi pi-shield', + to: '/saas/subscription-health', + ...(mismatchCount > 0 + ? { badge: String(mismatchCount), badgeClass: 'p-badge p-badge-danger' } + : {}) + } + ] + }, + { + label: 'Intenções de Assinatura', + icon: 'pi pi-inbox', + to: '/saas/subscription-intents' + }, + + { label: 'Clínicas (Tenants)', icon: 'pi pi-users', to: '/saas/tenants' } + ] + } + ] +} diff --git a/src/navigation/menus/sakai.demo.menu.js b/src/navigation/menus/sakai.demo.menu.js new file mode 100644 index 0000000..074e16a --- /dev/null +++ b/src/navigation/menus/sakai.demo.menu.js @@ -0,0 +1,117 @@ +export default [ + { + label: 'Home', + items: [{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/' }] + }, + { + label: 'UI Components', + path: '/uikit', + items: [ + { label: 'Form Layout', icon: 'pi pi-fw pi-id-card', to: '/demo/uikit/formlayout' }, + { label: 'Input', icon: 'pi pi-fw pi-check-square', to: '/demo/uikit/input' }, + { label: 'Button', icon: 'pi pi-fw pi-mobile', to: '/demo/uikit/button', class: 'rotated-icon' }, + { label: 'Table', icon: 'pi pi-fw pi-table', to: '/demo/uikit/table' }, + { label: 'List', icon: 'pi pi-fw pi-list', to: '/demo/uikit/list' }, + { label: 'Tree', icon: 'pi pi-fw pi-share-alt', to: '/demo/uikit/tree' }, + { label: 'Panel', icon: 'pi pi-fw pi-tablet', to: '/demo/uikit/panel' }, + { label: 'Overlay', icon: 'pi pi-fw pi-clone', to: '/demo/uikit/overlay' }, + { label: 'Media', icon: 'pi pi-fw pi-image', to: '/demo/uikit/media' }, + { label: 'Menu', icon: 'pi pi-fw pi-bars', to: '/demo/uikit/menu' }, + { label: 'Message', icon: 'pi pi-fw pi-comment', to: '/demo/uikit/message' }, + { label: 'File', icon: 'pi pi-fw pi-file', to: '/demo/uikit/file' }, + { label: 'Chart', icon: 'pi pi-fw pi-chart-bar', to: '/demo/uikit/charts' }, + { label: 'Timeline', icon: 'pi pi-fw pi-calendar', to: '/demo/uikit/timeline' }, + { label: 'Misc', icon: 'pi pi-fw pi-circle', to: '/demo/uikit/misc' } + ] + }, + { + label: 'Prime Blocks', + icon: 'pi pi-fw pi-prime', + path: '/blocks', + items: [ + { label: 'Free Blocks', icon: 'pi pi-fw pi-eye', to: '/utilities' }, + { label: 'All Blocks', icon: 'pi pi-fw pi-globe', url: 'https://blocks.primevue.org/', target: '_blank' } + ] + }, + { + label: 'Pages', + icon: 'pi pi-fw pi-briefcase', + path: '/pages', + items: [ + { label: 'Landing', icon: 'pi pi-fw pi-globe', to: '/landing' }, + { + label: 'Auth', + icon: 'pi pi-fw pi-user', + path: '/auth', + items: [ + { label: 'Login', icon: 'pi pi-fw pi-sign-in', to: '/auth/login' }, + { label: 'Error', icon: 'pi pi-fw pi-times-circle', to: '/auth/error' }, + { label: 'Access Denied', icon: 'pi pi-fw pi-lock', to: '/auth/access' } + ] + }, + { label: 'Crud', icon: 'pi pi-fw pi-pencil', to: '/pages/crud' }, + { label: 'Not Found', icon: 'pi pi-fw pi-exclamation-circle', to: '/pages/notfound' }, + { label: 'Empty', icon: 'pi pi-fw pi-circle-off', to: '/pages/empty' } + ] + }, + { + label: 'Hierarchy', + icon: 'pi pi-fw pi-align-left', + path: '/hierarchy', + items: [ + { + label: 'Submenu 1', + icon: 'pi pi-fw pi-align-left', + path: '/submenu_1', + items: [ + { + label: 'Submenu 1.1', + icon: 'pi pi-fw pi-align-left', + path: '/submenu_1_1', + items: [ + { label: 'Submenu 1.1.1', icon: 'pi pi-fw pi-align-left' }, + { label: 'Submenu 1.1.2', icon: 'pi pi-fw pi-align-left' }, + { label: 'Submenu 1.1.3', icon: 'pi pi-fw pi-align-left' } + ] + }, + { + label: 'Submenu 1.2', + icon: 'pi pi-fw pi-align-left', + path: '/submenu_1_2', + items: [{ label: 'Submenu 1.2.1', icon: 'pi pi-fw pi-align-left' }] + } + ] + }, + { + label: 'Submenu 2', + icon: 'pi pi-fw pi-align-left', + path: '/submenu_2', + items: [ + { + label: 'Submenu 2.1', + icon: 'pi pi-fw pi-align-left', + path: '/submenu_2_1', + items: [ + { label: 'Submenu 2.1.1', icon: 'pi pi-fw pi-align-left' }, + { label: 'Submenu 2.1.2', icon: 'pi pi-fw pi-align-left' } + ] + }, + { + label: 'Submenu 2.2', + icon: 'pi pi-fw pi-align-left', + path: '/submenu_2_2', + items: [{ label: 'Submenu 2.2.1', icon: 'pi pi-fw pi-align-left' }] + } + ] + } + ] + }, + { + label: 'Get Started', + path: '/start', + items: [ + { label: 'Documentation', icon: 'pi pi-fw pi-book', to: '/pages' }, + { label: 'View Source', icon: 'pi pi-fw pi-github', url: 'https://github.com/primefaces/sakai-vue', target: '_blank' } + ] + } +] diff --git a/src/navigation/menus/therapist.menu.js b/src/navigation/menus/therapist.menu.js new file mode 100644 index 0000000..6e57b94 --- /dev/null +++ b/src/navigation/menus/therapist.menu.js @@ -0,0 +1,20 @@ +export default [ + { + label: 'Terapeuta', + items: [ + { label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/therapist' }, + { label: 'Agenda', icon: 'pi pi-fw pi-calendar', to: '/therapist/agenda' }, + + // ✅ PRO + { + label: 'Agendamento online', + icon: 'pi pi-fw pi-globe', + to: '/therapist/online-scheduling', + feature: 'online_scheduling.manage', + proBadge: true + }, + + { label: 'Pacientes', icon: 'pi pi-fw pi-id-card', to: '/therapist/patients' } + ] + } +] diff --git a/src/router/guards.js b/src/router/guards.js new file mode 100644 index 0000000..9790796 --- /dev/null +++ b/src/router/guards.js @@ -0,0 +1,248 @@ +// ⚠️ Guard depende de sessão estável. +// Nunca disparar refresh concorrente durante navegação protegida. +// Ver comentário em session.js sobre race condition. + +import { supabase } from '@/lib/supabase/client' +import { useTenantStore } from '@/stores/tenantStore' +import { useEntitlementsStore } from '@/stores/entitlementsStore' +import { buildUpgradeUrl } from '@/utils/upgradeContext' + +import { sessionUser, sessionReady, sessionRefreshing, initSession } from '@/app/session' + +// cache simples (evita bater no banco em toda navegação) +let sessionUidCache = null + +// cache de saas admin por uid (pra não consultar tabela toda vez) +let saasAdminCacheUid = null +let saasAdminCacheIsAdmin = null + +function roleToPath (role) { + if (role === 'tenant_admin') return '/admin' + if (role === 'therapist') return '/therapist' + if (role === 'patient') return '/patient' + if (role === 'saas_admin') return '/saas' + return '/' +} + +function sleep (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +async function waitSessionIfRefreshing () { + if (!sessionReady.value) { + try { await initSession({ initial: true }) } catch (e) { + console.warn('[guards] initSession falhou:', e) + } + } + + for (let i = 0; i < 30; i++) { + if (!sessionRefreshing.value) return + await sleep(50) + } +} + +async function isSaasAdmin (uid) { + if (!uid) return false + if (saasAdminCacheUid === uid && typeof saasAdminCacheIsAdmin === 'boolean') { + return saasAdminCacheIsAdmin + } + + const { data, error } = await supabase + .from('saas_admins') + .select('user_id') + .eq('user_id', uid) + .maybeSingle() + + const ok = !error && !!data + saasAdminCacheUid = uid + saasAdminCacheIsAdmin = ok + return ok +} + +// heurística segura: carrega entitlements se ainda não carregou ou mudou tenant +function shouldLoadEntitlements (ent, tenantId) { + if (!tenantId) return false + + const loaded = typeof ent.loaded === 'boolean' ? ent.loaded : false + const entTenantId = ent.activeTenantId ?? ent.tenantId ?? null + + if (!loaded) return true + if (entTenantId && entTenantId !== tenantId) return true + return false +} + +// wrapper: chama loadForTenant sem depender de force:false existir +async function loadEntitlementsSafe (ent, tenantId, force) { + if (!ent?.loadForTenant) return + + try { + await ent.loadForTenant(tenantId, { force: !!force }) + } catch (e) { + // se quebrou tentando force false (store não suporta), tenta força true uma vez + if (!force) { + console.warn('[guards] ent.loadForTenant(force:false) falhou, tentando force:true', e) + await ent.loadForTenant(tenantId, { force: true }) + return + } + throw e + } +} + +// util: roles guard (plural) +function matchesRoles (roles, activeRole) { + if (!Array.isArray(roles) || !roles.length) return true + return roles.includes(activeRole) +} + +export function applyGuards (router) { + if (window.__guardsBound) return + window.__guardsBound = true + + router.beforeEach(async (to) => { + const tlabel = `[guard] ${to.fullPath}` + console.time(tlabel) + + try { + // públicos + if (to.meta?.public) { console.timeEnd(tlabel); return true } + if (to.path.startsWith('/auth')) { console.timeEnd(tlabel); return true } + + // se rota não exige auth, libera + if (!to.meta?.requiresAuth) { console.timeEnd(tlabel); return true } + + // não decide nada no meio do refresh do session.js + console.timeLog(tlabel, 'waitSessionIfRefreshing') + await waitSessionIfRefreshing() + + // precisa estar logado (fonte estável do session.js) + const uid = sessionUser.value?.id || null + if (!uid) { + sessionStorage.setItem('redirect_after_login', to.fullPath) + console.timeEnd(tlabel) + return { path: '/auth/login' } + } + + // se uid mudou, invalida caches e stores dependentes + if (sessionUidCache !== uid) { + sessionUidCache = uid + saasAdminCacheUid = null + saasAdminCacheIsAdmin = null + + const ent0 = useEntitlementsStore() + if (typeof ent0.invalidate === 'function') ent0.invalidate() + } + + // saas admin (com cache) + if (to.meta?.saasAdmin) { + console.timeLog(tlabel, 'isSaasAdmin') + const ok = await isSaasAdmin(uid) + if (!ok) { console.timeEnd(tlabel); return { path: '/pages/access' } } + } + + // carrega tenant + role + const tenant = useTenantStore() + console.timeLog(tlabel, 'tenant.loadSessionAndTenant?') + if (!tenant.loaded && !tenant.loading) { + await tenant.loadSessionAndTenant() + } + + // se não tem user no store, trata como não logado + if (!tenant.user) { + sessionStorage.setItem('redirect_after_login', to.fullPath) + console.timeEnd(tlabel) + return { path: '/auth/login' } + } + + // se não tem tenant ativo: + // - se não tem memberships active -> manda pro access (sem clínica) + // - se tem memberships active mas activeTenantId está null -> seta e segue + if (!tenant.activeTenantId) { + const mem = Array.isArray(tenant.memberships) ? tenant.memberships : [] + const firstActive = mem.find(m => m && m.status === 'active' && m.tenant_id) + + if (!firstActive) { + if (to.path === '/pages/access') { console.timeEnd(tlabel); return true } + console.timeEnd(tlabel) + return { path: '/pages/access' } + } + + if (typeof tenant.setActiveTenant === 'function') { + tenant.setActiveTenant(firstActive.tenant_id) + } else { + tenant.activeTenantId = firstActive.tenant_id + tenant.activeRole = firstActive.role + } + } + + const tenantId = tenant.activeTenantId + if (!tenantId) { + if (to.path === '/pages/access') { console.timeEnd(tlabel); return true } + console.timeEnd(tlabel) + return { path: '/pages/access' } + } + + // entitlements (✅ carrega só quando precisa) + const ent = useEntitlementsStore() + if (shouldLoadEntitlements(ent, tenantId)) { + console.timeLog(tlabel, 'ent.loadForTenant') + await loadEntitlementsSafe(ent, tenantId, true) + } + + // roles guard (plural) + const allowedRoles = to.meta?.roles + if (Array.isArray(allowedRoles) && allowedRoles.length) { + if (!matchesRoles(allowedRoles, tenant.activeRole)) { + const fallback = roleToPath(tenant.activeRole) + if (to.path === fallback) { console.timeEnd(tlabel); return { path: '/pages/access' } } + console.timeEnd(tlabel) + return { path: fallback } + } + } + + // role guard (singular) - mantém compatibilidade + const requiredRole = to.meta?.role + if (requiredRole && tenant.activeRole !== requiredRole) { + const fallback = roleToPath(tenant.activeRole) + if (to.path === fallback) { console.timeEnd(tlabel); return { path: '/pages/access' } } + console.timeEnd(tlabel) + return { path: fallback } + } + + // feature guard + const requiredFeature = to.meta?.feature + if (requiredFeature && ent?.can && !ent.can(requiredFeature)) { + if (to.name === 'upgrade') { console.timeEnd(tlabel); return true } + + const url = buildUpgradeUrl({ + missingKeys: [requiredFeature], + redirectTo: to.fullPath + }) + console.timeEnd(tlabel) + return { path: url } + } + + console.timeEnd(tlabel) + return true + } catch (e) { + console.error('[guards] erro no beforeEach:', e) + + // fallback seguro + if (to.meta?.public || to.path.startsWith('/auth')) return true + if (to.path === '/pages/access') return true + + sessionStorage.setItem('redirect_after_login', to.fullPath) + return { path: '/auth/login' } + } + }) + + // auth listener (reset caches) + if (!window.__supabaseAuthListenerBound) { + window.__supabaseAuthListenerBound = true + + supabase.auth.onAuthStateChange(() => { + sessionUidCache = null + saasAdminCacheUid = null + saasAdminCacheIsAdmin = null + }) + } +} diff --git a/src/router/index.js b/src/router/index.js index 8d7e588..18920ce 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,146 +1,111 @@ -import AppLayout from '@/layout/AppLayout.vue'; -import { createRouter, createWebHistory } from 'vue-router'; +import { + createRouter, + createWebHistory, + isNavigationFailure, + NavigationFailureType +} from 'vue-router' + +import publicRoutes from './routes.public' +import adminRoutes from './routes.admin' +import therapistRoutes from './routes.therapist' +import patientRoutes from './routes.patient' +import miscRoutes from './routes.misc' +import authRoutes from './routes.auth' +import configuracoesRoutes from './router.configuracoes' +import billingRoutes from './routes.billing' +import saasRoutes from './routes.saas' +import demoRoutes from './routes.demo' +import meRoutes from './router.me' + +import { applyGuards } from './guards' + +const routes = [ + ...(Array.isArray(publicRoutes) ? publicRoutes : [publicRoutes]), + ...(Array.isArray(authRoutes) ? authRoutes : [authRoutes]), + ...(Array.isArray(miscRoutes) ? miscRoutes : [miscRoutes]), + ...(Array.isArray(billingRoutes) ? billingRoutes : [billingRoutes]), + ...(Array.isArray(saasRoutes) ? saasRoutes : [saasRoutes]), + ...(Array.isArray(meRoutes) ? meRoutes : [meRoutes]), + ...(Array.isArray(adminRoutes) ? adminRoutes : [adminRoutes]), + ...(Array.isArray(therapistRoutes) ? therapistRoutes : [therapistRoutes]), + ...(Array.isArray(patientRoutes) ? patientRoutes : [patientRoutes]), + ...(Array.isArray(demoRoutes) ? demoRoutes : [demoRoutes]), + ...(Array.isArray(configuracoesRoutes) ? configuracoesRoutes : [configuracoesRoutes]), + + { path: '/:pathMatch(.*)*', name: 'notfound', component: () => import('@/views/pages/NotFound.vue') } +] const router = createRouter({ - history: createWebHistory(), - routes: [ - { - path: '/', - component: AppLayout, - children: [ - { - path: '/', - name: 'dashboard', - component: () => import('@/views/Dashboard.vue') - }, - { - path: '/uikit/formlayout', - name: 'formlayout', - component: () => import('@/views/uikit/FormLayout.vue') - }, - { - path: '/uikit/input', - name: 'input', - component: () => import('@/views/uikit/InputDoc.vue') - }, - { - path: '/uikit/button', - name: 'button', - component: () => import('@/views/uikit/ButtonDoc.vue') - }, - { - path: '/uikit/table', - name: 'table', - component: () => import('@/views/uikit/TableDoc.vue') - }, - { - path: '/uikit/list', - name: 'list', - component: () => import('@/views/uikit/ListDoc.vue') - }, - { - path: '/uikit/tree', - name: 'tree', - component: () => import('@/views/uikit/TreeDoc.vue') - }, - { - path: '/uikit/panel', - name: 'panel', - component: () => import('@/views/uikit/PanelsDoc.vue') - }, + history: createWebHistory(), + routes, + scrollBehavior(to, from, savedPosition) { + // volta/avançar do navegador mantém posição + if (savedPosition) return savedPosition - { - path: '/uikit/overlay', - name: 'overlay', - component: () => import('@/views/uikit/OverlayDoc.vue') - }, - { - path: '/uikit/media', - name: 'media', - component: () => import('@/views/uikit/MediaDoc.vue') - }, - { - path: '/uikit/message', - name: 'message', - component: () => import('@/views/uikit/MessagesDoc.vue') - }, - { - path: '/uikit/file', - name: 'file', - component: () => import('@/views/uikit/FileDoc.vue') - }, - { - path: '/uikit/menu', - name: 'menu', - component: () => import('@/views/uikit/MenuDoc.vue') - }, - { - path: '/uikit/charts', - name: 'charts', - component: () => import('@/views/uikit/ChartDoc.vue') - }, - { - path: '/uikit/misc', - name: 'misc', - component: () => import('@/views/uikit/MiscDoc.vue') - }, - { - path: '/uikit/timeline', - name: 'timeline', - component: () => import('@/views/uikit/TimelineDoc.vue') - }, - { - path: '/blocks/free', - name: 'blocks', - meta: { - breadcrumb: ['Prime Blocks', 'Free Blocks'] - }, - component: () => import('@/views/utilities/Blocks.vue') - }, - { - path: '/pages/empty', - name: 'empty', - component: () => import('@/views/pages/Empty.vue') - }, - { - path: '/pages/crud', - name: 'crud', - component: () => import('@/views/pages/Crud.vue') - }, - { - path: '/start/documentation', - name: 'documentation', - component: () => import('@/views/pages/Documentation.vue') - } - ] - }, - { - path: '/landing', - name: 'landing', - component: () => import('@/views/pages/Landing.vue') - }, - { - path: '/pages/notfound', - name: 'notfound', - component: () => import('@/views/pages/NotFound.vue') - }, + // qualquer navegação normal NÃO altera o scroll + return false + } +}) - { - path: '/auth/login', - name: 'login', - component: () => import('@/views/pages/auth/Login.vue') - }, - { - path: '/auth/access', - name: 'accessDenied', - component: () => import('@/views/pages/auth/Access.vue') - }, - { - path: '/auth/error', - name: 'error', - component: () => import('@/views/pages/auth/Error.vue') - } - ] -}); +/* 🔎 DEBUG: listar todas as rotas registradas */ +console.log( + '[ROUTES]', + router.getRoutes().map(r => r.path).sort() +) -export default router; +// ===== DEBUG NAV + TRACE (remover depois) ===== +const _push = router.push.bind(router) +router.push = async (loc) => { + console.log('[router.push]', loc) + console.trace('[push caller]') + + const res = await _push(loc) + + if (isNavigationFailure(res, NavigationFailureType.duplicated)) { + console.warn('[NAV FAIL] duplicated', res) + } else if (isNavigationFailure(res, NavigationFailureType.cancelled)) { + console.warn('[NAV FAIL] cancelled', res) + } else if (isNavigationFailure(res, NavigationFailureType.aborted)) { + console.warn('[NAV FAIL] aborted', res) + } else if (isNavigationFailure(res, NavigationFailureType.redirected)) { + console.warn('[NAV FAIL] redirected', res) + } + + return res +} + +const _replace = router.replace.bind(router) +router.replace = async (loc) => { + console.log('[router.replace]', loc) + console.trace('[replace caller]') + + const res = await _replace(loc) + + if (isNavigationFailure(res, NavigationFailureType.cancelled)) { + console.warn('[NAV FAIL replace] cancelled', res) + } else if (isNavigationFailure(res, NavigationFailureType.aborted)) { + console.warn('[NAV FAIL replace] aborted', res) + } else if (isNavigationFailure(res, NavigationFailureType.redirected)) { + console.warn('[NAV FAIL replace] redirected', res) + } + + return res +} + +router.onError((e) => console.error('[router.onError]', e)) + +router.beforeEach((to, from) => { + console.log('[beforeEach]', from.fullPath, '->', to.fullPath) + return true +}) + +router.afterEach((to, from, failure) => { + if (failure) console.warn('[afterEach failure]', failure) + else console.log('[afterEach ok]', from.fullPath, '->', to.fullPath) +}) +// ===== /DEBUG NAV + TRACE ===== + +// ✅ mantém seus guards, mas agora a landing tem meta.public +applyGuards(router) + +export default router diff --git a/src/router/router.configuracoes.js b/src/router/router.configuracoes.js new file mode 100644 index 0000000..a2dbb24 --- /dev/null +++ b/src/router/router.configuracoes.js @@ -0,0 +1,36 @@ +// src/router/router.configuracoes.js +import AppLayout from '@/layout/AppLayout.vue' + +const configuracoesRoutes = { + path: '/configuracoes', + component: AppLayout, + + meta: { + requiresAuth: true, + roles: ['admin', 'tenant_admin', 'therapist'] + }, + + children: [ + { + path: '', + component: () => import('@/layout/ConfiguracoesPage.vue'), + redirect: { name: 'ConfiguracoesAgenda' }, + + children: [ + { + path: 'agenda', + name: 'ConfiguracoesAgenda', + component: () => import('@/layout/configuracoes/ConfiguracoesAgendaPage.vue') + } + + // Futuro: + // { path: 'clinica', name: 'ConfiguracoesClinica', component: () => import('@/layout/configuracoes/ConfiguracoesClinicaPage.vue') }, + // { path: 'intake', name: 'ConfiguracoesIntake', component: () => import('@/layout/configuracoes/ConfiguracoesIntakePage.vue') }, + // { path: 'conta', name: 'ConfiguracoesConta', component: () => import('@/layout/configuracoes/ConfiguracoesContaPage.vue') }, + ] + } + ] +} + +export default configuracoesRoutes + diff --git a/src/router/router.me.js b/src/router/router.me.js new file mode 100644 index 0000000..a57f146 --- /dev/null +++ b/src/router/router.me.js @@ -0,0 +1,32 @@ +// src/router/router.me.js +import AppLayout from '@/layout/AppLayout.vue' + +const meRoutes = { + path: '/me', + component: AppLayout, + + meta: { + requiresAuth: true, + roles: ['admin', 'tenant_admin', 'therapist', 'patient'] + }, + + children: [ + { + // ✅ quando entrar em /me, manda pro perfil + path: '', + redirect: { name: 'MeuPerfil' } + }, + + { + path: 'perfil', + name: 'MeuPerfil', + component: () => import('@/views/pages/me/MeuPerfilPage.vue') + } + + // Futuro: + // { path: 'preferencias', name: 'MePreferencias', component: () => import('@/pages/me/PreferenciasPage.vue') }, + // { path: 'notificacoes', name: 'MeNotificacoes', component: () => import('@/pages/me/NotificacoesPage.vue') }, + ] +} + +export default meRoutes diff --git a/src/router/routes.admin.js b/src/router/routes.admin.js new file mode 100644 index 0000000..55a56aa --- /dev/null +++ b/src/router/routes.admin.js @@ -0,0 +1,93 @@ +// src/router/routes.admin.js +import AppLayout from '@/layout/AppLayout.vue' + +export default { + path: '/admin', + component: AppLayout, + + meta: { + // 🔐 Tudo aqui dentro exige login + requiresAuth: true, + + // 👤 Perfil de acesso + role: 'tenant_admin' + }, + + children: [ + // DASHBOARD + { + path: '', + name: 'admin-dashboard', + component: () => import('@/views/pages/admin/AdminDashboard.vue') + }, + + // PACIENTES - LISTA + { + path: 'pacientes', + name: 'admin-pacientes', + component: () => import('@/views/pages/admin/pacientes/PatientsIndexPage.vue') + }, + + // PACIENTES - CADASTRO (NOVO / EDITAR) + { + path: 'pacientes/cadastro', + name: 'admin-pacientes-cadastro', + component: () => import('@/views/pages/admin/pacientes/cadastro/PatientsCadastroPage.vue') + }, + { + path: 'pacientes/cadastro/:id', + name: 'admin-pacientes-cadastro-edit', + component: () => import('@/views/pages/admin/pacientes/cadastro/PatientsCadastroPage.vue'), + props: true + }, + + // GRUPOS DE PACIENTES ✅ + { + path: 'pacientes/grupos', + name: 'admin-pacientes-grupos', + component: () => import('@/views/pages/admin/pacientes/grupos/GruposPacientesPage.vue') + }, + + // TAGS + { + path: 'pacientes/tags', + name: 'admin-pacientes-tags', + component: () => import('@/views/pages/admin/pacientes/tags/TagsPage.vue') + }, + + // LINK EXTERNO + { + path: 'pacientes/link-externo', + name: 'admin.pacientes.linkexterno', + component: () => import('@/views/pages/admin/pacientes/cadastro/PatientsExternalLinkPage.vue') + }, + + // CADASTROS RECEBIDOS + { + path: 'pacientes/cadastro/recebidos', + name: 'admin.pacientes.recebidos', + component: () => import('@/views/pages/admin/pacientes/cadastro/recebidos/CadastrosRecebidosPage.vue') + }, + + // SEGURANÇA + { + path: 'settings/security', + name: 'admin-settings-security', + component: () => import('@/views/pages/auth/SecurityPage.vue') + }, + + // ================================ + // 🔒 MÓDULO PRO — Online Scheduling + // ================================ + // Admin também gerencia agendamento online; mesma feature de gestão. + // Você pode ter uma página admin para isso, ou reaproveitar a do therapist. + { + path: 'online-scheduling', + name: 'admin-online-scheduling', + component: () => import('@/views/pages/admin/OnlineSchedulingAdminPage.vue'), + meta: { + feature: 'online_scheduling.manage' + } + } + ] +} diff --git a/src/router/routes.auth.js b/src/router/routes.auth.js new file mode 100644 index 0000000..3aad7e0 --- /dev/null +++ b/src/router/routes.auth.js @@ -0,0 +1,45 @@ +export default { + path: '/auth', + children: [ + { + path: 'login', + name: 'login', + component: () => import('@/views/pages/auth/Login.vue'), + meta: { public: true } + }, + + // ✅ Signup público, mas com URL /auth/signup + { + path: 'signup', + name: 'signup', + component: () => import('@/views/pages/public/Signup.vue'), + meta: { public: true } + }, + { + path: 'welcome', + name: 'auth.welcome', + component: () => import('@/views/pages/auth/Welcome.vue'), + meta: { public: true } + }, + { + path: 'reset-password', + name: 'resetPassword', + component: () => import('@/views/pages/auth/ResetPasswordPage.vue'), + meta: { public: true } + }, + + { + path: 'access', + name: 'accessDenied', + component: () => import('@/views/pages/auth/Access.vue'), + meta: { public: true } + }, + + { + path: 'error', + name: 'error', + component: () => import('@/views/pages/auth/Error.vue'), + meta: { public: true } + } + ] +} diff --git a/src/router/routes.billing.js b/src/router/routes.billing.js new file mode 100644 index 0000000..87c9508 --- /dev/null +++ b/src/router/routes.billing.js @@ -0,0 +1,15 @@ +// src/router/routes.billing.js +import AppLayout from '@/layout/AppLayout.vue' + +export default { + path: '/upgrade', + component: AppLayout, + meta: { requiresAuth: true }, + children: [ + { + path: '', + name: 'upgrade', + component: () => import('@/views/pages/billing/UpgradePage.vue') + } + ] +} diff --git a/src/router/routes.demo.js b/src/router/routes.demo.js new file mode 100644 index 0000000..ac071c4 --- /dev/null +++ b/src/router/routes.demo.js @@ -0,0 +1,29 @@ +import AppLayout from '@/layout/AppLayout.vue' + +export default { + // ✅ não use '/' aqui (conflita com HomeCards) + path: '/demo', + component: AppLayout, + meta: { requiresAuth: true, role: 'tenant_admin' }, + children: [ + { path: 'uikit/formlayout', name: 'uikit-formlayout', component: () => import('@/views/uikit/FormLayout.vue') }, + { path: 'uikit/input', name: 'uikit-input', component: () => import('@/views/uikit/InputDoc.vue') }, + { path: 'uikit/button', name: 'uikit-button', component: () => import('@/views/uikit/ButtonDoc.vue') }, + { path: 'uikit/table', name: 'uikit-table', component: () => import('@/views/uikit/TableDoc.vue') }, + { path: 'uikit/list', name: 'uikit-list', component: () => import('@/views/uikit/ListDoc.vue') }, + { path: 'uikit/tree', name: 'uikit-tree', component: () => import('@/views/uikit/TreeDoc.vue') }, + { path: 'uikit/panel', name: 'uikit-panel', component: () => import('@/views/uikit/PanelsDoc.vue') }, + { path: 'uikit/overlay', name: 'uikit-overlay', component: () => import('@/views/uikit/OverlayDoc.vue') }, + { path: 'uikit/media', name: 'uikit-media', component: () => import('@/views/uikit/MediaDoc.vue') }, + { path: 'uikit/menu', name: 'uikit-menu', component: () => import('@/views/uikit/MenuDoc.vue') }, + { path: 'uikit/message', name: 'uikit-message', component: () => import('@/views/uikit/MessagesDoc.vue') }, + { path: 'uikit/file', name: 'uikit-file', component: () => import('@/views/uikit/FileDoc.vue') }, + { path: 'uikit/charts', name: 'uikit-charts', component: () => import('@/views/uikit/ChartDoc.vue') }, + { path: 'uikit/timeline', name: 'uikit-timeline', component: () => import('@/views/uikit/TimelineDoc.vue') }, + { path: 'uikit/misc', name: 'uikit-misc', component: () => import('@/views/uikit/MiscDoc.vue') }, + { path: 'utilities', name: 'blocks', component: () => import('@/views/utilities/Blocks.vue') }, + { path: 'pages', name: 'start-documentation', component: () => import('@/views/pages/Documentation.vue') }, + { path: 'pages/empty', name: 'pages-empty', component: () => import('@/views/pages/Empty.vue') }, + { path: 'pages/crud', name: 'pages-crud', component: () => import('@/views/pages/Crud.vue') } + ] +} diff --git a/src/router/routes.misc.js b/src/router/routes.misc.js new file mode 100644 index 0000000..cc61170 --- /dev/null +++ b/src/router/routes.misc.js @@ -0,0 +1,15 @@ +export default { + path: '/', + children: [ + { + path: 'landing', + name: 'landing', + component: () => import('@/views/pages/Landing.vue') + }, + { + path: 'pages/notfound', + name: 'notfound', + component: () => import('@/views/pages/NotFound.vue') + } + ] +} diff --git a/src/router/routes.patient.js b/src/router/routes.patient.js new file mode 100644 index 0000000..cf49ccd --- /dev/null +++ b/src/router/routes.patient.js @@ -0,0 +1,19 @@ +import AppLayout from '@/layout/AppLayout.vue' + +export default { + path: '/patient', + component: AppLayout, + meta: { requiresAuth: true, role: 'patient' }, + children: [ + { + path: '', + name: 'patient-dashboard', + component: () => import('@/views/pages/patient/PatientDashboard.vue') + }, + { + path: 'settings/security', + name: 'patient-settings-security', + component: () => import('@/views/pages/auth/SecurityPage.vue') + } + ] +} diff --git a/src/router/routes.public.js b/src/router/routes.public.js new file mode 100644 index 0000000..9dd5142 --- /dev/null +++ b/src/router/routes.public.js @@ -0,0 +1,26 @@ +export default { + path: '/', + children: [ + { + path: '', + name: 'home', + component: () => import('@/views/pages/HomeCards.vue') + }, + + // ✅ LP (página separada da landing do template) + { + path: 'lp', + name: 'lp', + component: () => import('@/views/pages/public/landingpage-v1.vue'), + meta: { public: true } + }, + + // ✅ cadastro externo + { + path: 'cadastro/paciente', + name: 'public.patient.intake', + component: () => import('@/views/pages/public/CadastroPacienteExterno.vue'), + meta: { public: true } + } + ] +} diff --git a/src/router/routes.saas.js b/src/router/routes.saas.js new file mode 100644 index 0000000..a5d594a --- /dev/null +++ b/src/router/routes.saas.js @@ -0,0 +1,60 @@ +import AppLayout from '@/layout/AppLayout.vue' + +export default { + path: '/saas', + component: AppLayout, + meta: { requiresAuth: true, saasAdmin: true }, + children: [ + { + path: '', + name: 'saas-dashboard', + component: () => import('@/views/pages/saas/SaasDashboard.vue') + }, + { + path: 'plans', + name: 'saas-plans', + component: () => import('@/views/pages/saas/SaasPlansPage.vue') + }, + { + path: 'plans-public', + name: 'saas-plans-public', + component: () => import('@/views/pages/saas/SaasPlansPublicPage.vue') + }, + { + path: 'features', + name: 'saas-features', + component: () => import('@/views/pages/saas/SaasFeaturesPage.vue') + }, + { + path: 'plan-features', + name: 'saas-plan-features', + component: () => import('@/views/pages/saas/SaasPlanFeaturesMatrixPage.vue') + }, + { + path: 'subscriptions', + name: 'saas-subscriptions', + component: () => import('@/views/pages/saas/SaasSubscriptionsPage.vue') + }, + { + path: 'subscription-events', + name: 'saas-subscription-events', + component: () => import('@/views/pages/saas/SaasSubscriptionEventsPage.vue') + }, + { + path: 'subscription-health', + name: 'saas-subscription-health', + component: () => import('@/views/pages/saas/SaasSubscriptionHealthPage.vue') + }, + { + path: 'subscription-intents', + name: 'saas.subscriptionIntents', + component: () => import('@/views/pages/saas/SubscriptionIntentsPage.vue'), + meta: { requiresAuth: true, saasAdmin: true } + }, + { + path: 'tenants', + name: 'saas-tenants', + component: () => import('@/views/pages/saas/SaasPlaceholder.vue') + } + ] +} diff --git a/src/router/routes.therapist.js b/src/router/routes.therapist.js new file mode 100644 index 0000000..9352e7f --- /dev/null +++ b/src/router/routes.therapist.js @@ -0,0 +1,71 @@ +import AppLayout from '@/layout/AppLayout.vue' + +export default { + path: '/therapist', + component: AppLayout, + + meta: { + // 🔐 Tudo aqui dentro exige login + requiresAuth: true, + + // 👤 Perfil de acesso (seu guard atual usa meta.role) + role: 'therapist' + }, + + children: [ + // ====================== + // ✅ Dashboard Therapist + // ====================== + { + path: '', + name: 'therapist-dashboard', + component: () => import('@/views/pages/therapist/TherapistDashboard.vue') + // herda requiresAuth + role do pai + }, + + // ====================== + // ✅ Segurança + // ====================== + { + path: 'settings/security', + name: 'therapist-settings-security', + component: () => import('@/views/pages/auth/SecurityPage.vue') + // herda requiresAuth + role do pai + }, + + // ========================================== + // 🔒 PRO — Online Scheduling (gestão interna) + // ========================================== + // feature gate via meta.feature: + // - bloqueia rota (guard) + // - menu pode desabilitar/ocultar (entitlementsStore.has) + { + path: 'online-scheduling', + name: 'therapist-online-scheduling', + component: () => import('@/views/pages/therapist/OnlineSchedulingPage.vue'), + meta: { + // ✅ herda requiresAuth + role do pai + feature: 'online_scheduling.manage' + } + }, + + // ================================================= + // 🔒 PRO — Online Scheduling (página pública/config) + // ================================================= + // Se você tiver/for criar a tela para configurar/visualizar a página pública, + // use a chave granular: + // - online_scheduling.public + // + // Dica de produto: + // - "manage" = operação interna + // - "public" = ajustes/preview/links + // + // Quando criar o arquivo, descomente. + // { + // path: 'online-scheduling/public', + // name: 'therapist-online-scheduling-public', + // component: () => import('@/views/pages/therapist/OnlineSchedulingPublicPage.vue'), + // meta: { feature: 'online_scheduling.public' } + // } + ] +} diff --git a/src/service/CountryService.js b/src/services/CountryService.js old mode 100755 new mode 100644 similarity index 100% rename from src/service/CountryService.js rename to src/services/CountryService.js diff --git a/src/service/CustomerService.js b/src/services/CustomerService.js old mode 100755 new mode 100644 similarity index 100% rename from src/service/CustomerService.js rename to src/services/CustomerService.js diff --git a/src/services/GruposPacientes.service.js b/src/services/GruposPacientes.service.js new file mode 100644 index 0000000..fa2f931 --- /dev/null +++ b/src/services/GruposPacientes.service.js @@ -0,0 +1,173 @@ +// src/services/patientGroups.js +import { supabase } from '@/lib/supabase/client' + +function pickCount (row) { + return row?.patients_count ?? row?.patient_count ?? 0 +} + +async function getOwnerId () { + const { data, error } = await supabase.auth.getUser() + if (error) throw error + const uid = data?.user?.id + if (!uid) throw new Error('Sessão inválida.') + return uid +} + +function normalizeNome (s) { + return String(s || '').trim().toLowerCase().replace(/\s+/g, ' ') +} + +function isUniqueViolation (err) { + if (!err) return false + if (err.code === '23505') return true + const msg = String(err.message || '') + return /duplicate key value violates unique constraint/i.test(msg) +} + +/** + * Lista grupos do usuário + grupos do sistema, já com contagem. + * Usa a view v_patient_groups_with_counts (preferencial). + * Fallback: tabela patient_groups + contagem pela pivot. + */ +export async function listGroupsWithCounts () { + const ownerId = await getOwnerId() + + // 1) View (preferencial) — agora já é a fonte correta + const { data: vData, error: vErr } = await supabase + .from('v_patient_groups_with_counts') + .select('*') + .or(`owner_id.eq.${ownerId},is_system.eq.true`) + .order('nome', { ascending: true }) + + if (!vErr) { + return (vData || []).map(r => ({ + ...r, + patients_count: pickCount(r) + })) + } + + // 2) Fallback (caso view não exista / erro de schema) + const { data: groups, error: gErr } = await supabase + .from('patient_groups') + .select('id,nome,cor,is_system,is_active,owner_id,created_at,updated_at') + .or(`owner_id.eq.${ownerId},is_system.eq.true`) + .order('nome', { ascending: true }) + if (gErr) throw gErr + + const ids = (groups || []).map(g => g.id).filter(Boolean) + if (!ids.length) return [] + + // conta pacientes por grupo na pivot + const { data: rel, error: rErr } = await supabase + .from('patient_group_patient') + .select('patient_group_id') + .in('patient_group_id', ids) + if (rErr) throw rErr + + const counts = new Map() + for (const row of rel || []) { + const gid = row.patient_group_id + if (!gid) continue + counts.set(gid, (counts.get(gid) || 0) + 1) + } + + return (groups || []).map(g => ({ + ...g, + patients_count: counts.get(g.id) || 0 + })) +} + +export async function createGroup (nome, cor = null) { + const ownerId = await getOwnerId() + + const raw = String(nome || '').trim() + if (!raw) throw new Error('Nome do grupo é obrigatório.') + + const nNorm = normalizeNome(raw) + + // proteção extra no front: busca por igualdade "normalizada" + // (mantém RLS como autoridade final, mas evita UX ruim) + const { data: existing, error: exErr } = await supabase + .from('patient_groups') + .select('id,nome') + .eq('owner_id', ownerId) + .eq('is_system', false) + .limit(50) + + if (!exErr && (existing || []).some(r => normalizeNome(r.nome) === nNorm)) { + throw new Error('Já existe um grupo com esse nome.') + } + + const payload = { + owner_id: ownerId, + nome: raw, + cor: cor || null + } + + const { data, error } = await supabase + .from('patient_groups') + .insert(payload) + .select('id,nome,cor,is_system,owner_id,is_active,created_at,updated_at') + .single() + + if (error) { + if (isUniqueViolation(error)) throw new Error('Já existe um grupo com esse nome.') + throw error + } + + return data +} + +export async function updateGroup (id, nome, cor = null) { + const ownerId = await getOwnerId() + + const raw = String(nome || '').trim() + if (!id) throw new Error('ID inválido.') + if (!raw) throw new Error('Nome do grupo é obrigatório.') + + // (opcional) valida duplicidade entre os grupos do owner (não-system) + const nNorm = normalizeNome(raw) + const { data: existing, error: exErr } = await supabase + .from('patient_groups') + .select('id,nome') + .eq('owner_id', ownerId) + .eq('is_system', false) + .neq('id', id) + .limit(80) + + if (!exErr && (existing || []).some(r => normalizeNome(r.nome) === nNorm)) { + throw new Error('Já existe um grupo com esse nome.') + } + + const { data, error } = await supabase + .from('patient_groups') + .update({ nome: raw, cor: cor || null, updated_at: new Date().toISOString() }) + .eq('id', id) + .eq('owner_id', ownerId) + .eq('is_system', false) + .select('id,nome,cor,is_system,owner_id,is_active,created_at,updated_at') + .single() + + if (error) { + if (isUniqueViolation(error)) throw new Error('Já existe um grupo com esse nome.') + throw error + } + + return data +} + +export async function deleteGroup (id) { + const ownerId = await getOwnerId() + + if (!id) throw new Error('ID inválido.') + + const { error } = await supabase + .from('patient_groups') + .delete() + .eq('id', id) + .eq('owner_id', ownerId) + .eq('is_system', false) + + if (error) throw error + return true +} diff --git a/src/service/NodeService.js b/src/services/NodeService.js old mode 100755 new mode 100644 similarity index 100% rename from src/service/NodeService.js rename to src/services/NodeService.js diff --git a/src/service/PhotoService.js b/src/services/PhotoService.js old mode 100755 new mode 100644 similarity index 100% rename from src/service/PhotoService.js rename to src/services/PhotoService.js diff --git a/src/service/ProductService.js b/src/services/ProductService.js similarity index 100% rename from src/service/ProductService.js rename to src/services/ProductService.js diff --git a/src/services/agendaConfigService.js b/src/services/agendaConfigService.js new file mode 100644 index 0000000..622e78f --- /dev/null +++ b/src/services/agendaConfigService.js @@ -0,0 +1,76 @@ +// src/services/agendaConfigService.js +import { supabase } from '@/lib/supabase/client' + +export async function getOwnerId() { + const { data, error } = await supabase.auth.getUser() + if (error) throw error + const uid = data?.user?.id + if (!uid) throw new Error('Sessão inválida.') + return uid +} + +export async function fetchSlotsRegras(ownerId) { + const { data, error } = await supabase + .from('agenda_slots_regras') + .select('*') + .eq('owner_id', ownerId) + .order('dia_semana', { ascending: true }) + if (error) throw error + return data || [] +} + +export async function upsertSlotRegra(ownerId, payload) { + const row = { + owner_id: ownerId, + dia_semana: Number(payload.dia_semana), + passo_minutos: Number(payload.passo_minutos), + offset_minutos: Number(payload.offset_minutos), + buffer_antes_min: Number(payload.buffer_antes_min || 0), + buffer_depois_min: Number(payload.buffer_depois_min || 0), + min_antecedencia_horas: Number(payload.min_antecedencia_horas || 0), + ativo: !!payload.ativo + } + + const { data, error } = await supabase + .from('agenda_slots_regras') + .upsert(row, { onConflict: 'owner_id,dia_semana' }) + .select('*') + .single() + + if (error) throw error + return data +} + +export function normalizeHHMM(v) { + if (v == null) return null + const s = String(v).trim() + if (/^\d{2}:\d{2}$/.test(s)) return s + if (/^\d{2}:\d{2}:\d{2}$/.test(s)) return s.slice(0, 5) + return s +} + +export function ruleKey(r) { + return [ + r.dia_semana, + normalizeHHMM(r.hora_inicio), + normalizeHHMM(r.hora_fim), + (r.modalidade || 'ambos'), + !!r.ativo + ].join('|') +} + +/** + * Remove duplicados exatos antes de mandar pro banco. + * (DB já tem UNIQUE, mas isso evita erro e deixa UX melhor) + */ +export function dedupeRegrasSemanais(regras) { + const seen = new Set() + const out = [] + for (const r of regras || []) { + const k = ruleKey(r) + if (seen.has(k)) continue + seen.add(k) + out.push(r) + } + return out +} diff --git a/src/services/agendaSlotsBloqueadosService.js b/src/services/agendaSlotsBloqueadosService.js new file mode 100644 index 0000000..5e20a45 --- /dev/null +++ b/src/services/agendaSlotsBloqueadosService.js @@ -0,0 +1,45 @@ +// src/services/agendaSlotsBloqueadosService.js +import { supabase } from '@/lib/supabase/client' + +export async function fetchSlotsBloqueados(ownerId, diaSemana) { + const { data, error } = await supabase + .from('agenda_slots_bloqueados_semanais') + .select('*') + .eq('owner_id', ownerId) + .eq('dia_semana', diaSemana) + .eq('ativo', true) + .order('hora_inicio', { ascending: true }) + + if (error) throw error + return data || [] +} + +export async function setSlotBloqueado(ownerId, diaSemana, horaInicio, isBloqueado, motivo = null) { + if (isBloqueado) { + const { error } = await supabase + .from('agenda_slots_bloqueados_semanais') + .upsert( + { + owner_id: ownerId, + dia_semana: diaSemana, + hora_inicio: horaInicio, + motivo: motivo || null, + ativo: true + }, + { onConflict: 'owner_id,dia_semana,hora_inicio' } + ) + if (error) throw error + return true + } + + // “desbloquear”: deletar (ou marcar ativo=false; aqui vou deletar por simplicidade) + const { error } = await supabase + .from('agenda_slots_bloqueados_semanais') + .delete() + .eq('owner_id', ownerId) + .eq('dia_semana', diaSemana) + .eq('hora_inicio', horaInicio) + + if (error) throw error + return true +} diff --git a/src/services/authService.js b/src/services/authService.js new file mode 100644 index 0000000..e025522 --- /dev/null +++ b/src/services/authService.js @@ -0,0 +1,18 @@ +import { supabase } from '@/lib/supabase/client' + +export const signIn = async (email, password) => { + return await supabase.auth.signInWithPassword({ email, password }) +} + +export const signUp = async (email, password) => { + return await supabase.auth.signUp({ email, password }) +} + +export const signOut = async () => { + return await supabase.auth.signOut() +} + +export const getUser = async () => { + const { data } = await supabase.auth.getUser() + return data.user +} diff --git a/src/services/patientTags.service.js b/src/services/patientTags.service.js new file mode 100644 index 0000000..59b8507 --- /dev/null +++ b/src/services/patientTags.service.js @@ -0,0 +1,77 @@ +// src/services/patientTags.js +import { supabase } from '@/lib/supabase/client' + +async function getOwnerId() { + const { data, error } = await supabase.auth.getUser() + if (error) throw error + const user = data?.user + if (!user) throw new Error('Você precisa estar logado.') + return user.id +} + +export async function listTagsWithCounts() { + const ownerId = await getOwnerId() + const v = await supabase + .from('v_tag_patient_counts') + .select('*') + .eq('owner_id', ownerId) + .order('name', { ascending: true }) + + if (!v.error) return v.data || [] + + const t = await supabase + .from('patient_tags') + .select('id, owner_id, name, color, is_native, created_at, updated_at') + .eq('owner_id', ownerId) + .order('name', { ascending: true }) + + if (t.error) throw t.error + return (t.data || []).map(r => ({ ...r, patient_count: 0 })) +} + +export async function createTag({ name, color = null }) { + const ownerId = await getOwnerId() + const { error } = await supabase.from('patient_tags').insert({ owner_id: ownerId, name, color }) + if (error) throw error +} + +export async function updateTag({ id, name, color = null }) { + const ownerId = await getOwnerId() + const { error } = await supabase + .from('patient_tags') + .update({ name, color, updated_at: new Date().toISOString() }) + .eq('id', id) + .eq('owner_id', ownerId) + if (error) throw error +} + +export async function deleteTagsByIds(ids = []) { + const ownerId = await getOwnerId() + if (!ids.length) return + + const pivotDel = await supabase + .from('patient_patient_tag') + .delete() + .eq('owner_id', ownerId) + .in('tag_id', ids) + if (pivotDel.error) throw pivotDel.error + + const tagDel = await supabase + .from('patient_tags') + .delete() + .eq('owner_id', ownerId) + .in('id', ids) + if (tagDel.error) throw tagDel.error +} + +export async function fetchPatientsByTagId(tagId) { + const ownerId = await getOwnerId() + const { data, error } = await supabase + .from('patient_patient_tag') + .select('patient_id, patients:patients(id, name, email, phone)') + .eq('owner_id', ownerId) + .eq('tag_id', tagId) + + if (error) throw error + return (data || []).map(r => r.patients).filter(Boolean) +} diff --git a/src/services/subscriptionIntents.js b/src/services/subscriptionIntents.js new file mode 100644 index 0000000..c5f6a71 --- /dev/null +++ b/src/services/subscriptionIntents.js @@ -0,0 +1,63 @@ +// src/services/subscriptionIntents.js +import { supabase } from '@/lib/supabase/client' + +function applyFilters(query, { q, status, planKey, interval }) { + if (q) query = query.ilike('email', `%${q}%`) + if (status) query = query.eq('status', status) + if (planKey) query = query.eq('plan_key', planKey) + if (interval) query = query.eq('interval', interval) + return query +} + +export async function listSubscriptionIntents(filters = {}) { + let query = supabase + .from('subscription_intents') + .select('*') + .order('created_at', { ascending: false }) + + query = applyFilters(query, filters) + + const { data, error } = await query + if (error) throw error + return data || [] +} + +export async function markIntentPaid(intentId, notes = '') { + // 1) marca como pago + const { data: updated, error: upErr } = await supabase + .from('subscription_intents') + .update({ + status: 'paid', + paid_at: new Date().toISOString(), + notes: notes || null + }) + .eq('id', intentId) + .select('*') + .maybeSingle() + + if (upErr) throw upErr + + // 2) ativa subscription do tenant (Modelo B) + const { data: sub, error: rpcErr } = await supabase.rpc('activate_subscription_from_intent', { + p_intent_id: intentId + }) + + if (rpcErr) throw rpcErr + + return { intent: updated, subscription: sub } +} + +export async function cancelIntent(intentId, notes = '') { + const { data, error } = await supabase + .from('subscription_intents') + .update({ + status: 'canceled', + notes: notes || null + }) + .eq('id', intentId) + .select('*') + .maybeSingle() + + if (error) throw error + return data +} diff --git a/src/sql-arquivos/01_profiles.sql b/src/sql-arquivos/01_profiles.sql new file mode 100644 index 0000000..ff1694d --- /dev/null +++ b/src/sql-arquivos/01_profiles.sql @@ -0,0 +1,110 @@ +-- ========================================================= +-- Agência PSI — Profiles (v2) + Trigger + RLS +-- - 1 profile por auth.users.id +-- - role base (admin|therapist|patient) +-- - pronto para evoluir p/ multi-tenant depois +-- ========================================================= + +-- 0) Função padrão updated_at (se já existir, mantém) +create or replace function public.set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +-- 1) Tabela profiles +create table if not exists public.profiles ( + id uuid primary key, -- = auth.users.id + email text, + full_name text, + avatar_url text, + + role text not null default 'patient', + status text not null default 'active', + + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + + constraint profiles_role_check check (role in ('admin','therapist','patient')), + constraint profiles_status_check check (status in ('active','inactive','invited')) +); + +-- FK opcional (em Supabase costuma ser ok) +do $$ +begin + if not exists ( + select 1 + from pg_constraint + where conname = 'profiles_id_fkey' + ) then + alter table public.profiles + add constraint profiles_id_fkey + foreign key (id) references auth.users(id) + on delete cascade; + end if; +end $$; + +-- Índices úteis +create index if not exists profiles_role_idx on public.profiles(role); +create index if not exists profiles_status_idx on public.profiles(status); + +-- 2) Trigger updated_at +drop trigger if exists t_profiles_set_updated_at on public.profiles; +create trigger t_profiles_set_updated_at +before update on public.profiles +for each row execute function public.set_updated_at(); + +-- 3) Trigger pós-signup: cria profile automático +-- Observação: roda como SECURITY DEFINER +create or replace function public.handle_new_user() +returns trigger +language plpgsql +security definer +set search_path = public +as $$ +begin + insert into public.profiles (id, email, role, status) + values (new.id, new.email, 'patient', 'active') + on conflict (id) do update + set email = excluded.email; + + return new; +end; +$$; + +drop trigger if exists on_auth_user_created on auth.users; +create trigger on_auth_user_created +after insert on auth.users +for each row execute function public.handle_new_user(); + +-- 4) RLS +alter table public.profiles enable row level security; + +-- Leitura do próprio profile +drop policy if exists "profiles_select_own" on public.profiles; +create policy "profiles_select_own" +on public.profiles +for select +to authenticated +using (id = auth.uid()); + +-- Update do próprio profile (campos não-sensíveis) +drop policy if exists "profiles_update_own" on public.profiles; +create policy "profiles_update_own" +on public.profiles +for update +to authenticated +using (id = auth.uid()) +with check (id = auth.uid()); + +-- Insert só do próprio (na prática quem insere é trigger, mas deixa coerente) +drop policy if exists "profiles_insert_own" on public.profiles; +create policy "profiles_insert_own" +on public.profiles +for insert +to authenticated +with check (id = auth.uid()); diff --git a/src/sql-arquivos/supabase_cadastro_externo.sql b/src/sql-arquivos/supabase_cadastro_externo.sql new file mode 100644 index 0000000..e9b170f --- /dev/null +++ b/src/sql-arquivos/supabase_cadastro_externo.sql @@ -0,0 +1,212 @@ +-- ========================================================= +-- Agência PSI Quasar — Cadastro Externo de Paciente (Supabase/Postgres) +-- Objetivo: +-- - Ter um link público com TOKEN que o terapeuta envia ao paciente +-- - Paciente preenche um formulário público +-- - Salva em "intake requests" (pré-cadastro) +-- - Terapeuta revisa e converte em paciente dentro do sistema +-- +-- Tabelas: +-- - patient_invites +-- - patient_intake_requests +-- +-- Funções: +-- - create_patient_intake_request (RPC pública - anon) +-- +-- Segurança: +-- - RLS habilitada +-- - Público (anon) não lê nada, só executa RPC +-- - Terapeuta (authenticated) lê/atualiza somente seus registros +-- ========================================================= + +-- 0) Tabelas +create table if not exists public.patient_invites ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + token text not null unique, + active boolean not null default true, + expires_at timestamptz null, + max_uses int null, + uses int not null default 0, + created_at timestamptz not null default now() +); + +create index if not exists patient_invites_owner_id_idx on public.patient_invites(owner_id); +create index if not exists patient_invites_token_idx on public.patient_invites(token); + +create table if not exists public.patient_intake_requests ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + token text not null, + name text not null, + email text null, + phone text null, + notes text null, + consent boolean not null default false, + status text not null default 'new', -- new | converted | rejected + created_at timestamptz not null default now() +); + +create index if not exists patient_intake_owner_id_idx on public.patient_intake_requests(owner_id); +create index if not exists patient_intake_token_idx on public.patient_intake_requests(token); +create index if not exists patient_intake_status_idx on public.patient_intake_requests(status); + +-- 1) RLS +alter table public.patient_invites enable row level security; +alter table public.patient_intake_requests enable row level security; + +-- 2) Fechar acesso direto para anon (público) +revoke all on table public.patient_invites from anon; +revoke all on table public.patient_intake_requests from anon; + +-- 3) Policies: terapeuta (authenticated) - somente próprios registros + +-- patient_invites +drop policy if exists invites_select_own on public.patient_invites; +create policy invites_select_own +on public.patient_invites for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists invites_insert_own on public.patient_invites; +create policy invites_insert_own +on public.patient_invites for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists invites_update_own on public.patient_invites; +create policy invites_update_own +on public.patient_invites for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +-- patient_intake_requests +drop policy if exists intake_select_own on public.patient_intake_requests; +create policy intake_select_own +on public.patient_intake_requests for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists intake_update_own on public.patient_intake_requests; +create policy intake_update_own +on public.patient_intake_requests for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +-- 4) RPC pública para criar intake (página pública) +-- Importantíssimo: security definer + search_path fixo +create or replace function public.create_patient_intake_request( + p_token text, + p_name text, + p_email text default null, + p_phone text default null, + p_notes text default null, + p_consent boolean default false +) +returns uuid +language plpgsql +security definer +set search_path = public +as $$ +declare + v_owner uuid; + v_active boolean; + v_expires timestamptz; + v_max_uses int; + v_uses int; + v_id uuid; +begin + select owner_id, active, expires_at, max_uses, uses + into v_owner, v_active, v_expires, v_max_uses, v_uses + from public.patient_invites + where token = p_token + limit 1; + + if v_owner is null then + raise exception 'Token inválido'; + end if; + + if v_active is not true then + raise exception 'Link desativado'; + end if; + + if v_expires is not null and now() > v_expires then + raise exception 'Link expirado'; + end if; + + if v_max_uses is not null and v_uses >= v_max_uses then + raise exception 'Limite de uso atingido'; + end if; + + if p_name is null or length(trim(p_name)) = 0 then + raise exception 'Nome é obrigatório'; + end if; + + insert into public.patient_intake_requests + (owner_id, token, name, email, phone, notes, consent, status) + values + (v_owner, p_token, trim(p_name), + nullif(lower(trim(p_email)), ''), + nullif(trim(p_phone), ''), + nullif(trim(p_notes), ''), + coalesce(p_consent, false), + 'new') + returning id into v_id; + + update public.patient_invites + set uses = uses + 1 + where token = p_token; + + return v_id; +end; +$$; + +grant execute on function public.create_patient_intake_request(text, text, text, text, text, boolean) to anon; +grant execute on function public.create_patient_intake_request(text, text, text, text, text, boolean) to authenticated; + +-- 5) (Opcional) helper para rotacionar token no painel (somente authenticated) +-- Você pode usar no front via supabase.rpc('rotate_patient_invite_token') +create or replace function public.rotate_patient_invite_token( + p_new_token text +) +returns uuid +language plpgsql +security definer +set search_path = public +as $$ +declare + v_uid uuid; + v_id uuid; +begin + -- pega o usuário logado + v_uid := auth.uid(); + if v_uid is null then + raise exception 'Usuário não autenticado'; + end if; + + -- desativa tokens antigos ativos do usuário + update public.patient_invites + set active = false + where owner_id = v_uid + and active = true; + + -- cria novo token + insert into public.patient_invites (owner_id, token, active) + values (v_uid, p_new_token, true) + returning id into v_id; + + return v_id; +end; +$$; + +grant execute on function public.rotate_patient_invite_token(text) to authenticated; + +grant select, insert, update, delete on table public.patient_invites to authenticated; +grant select, insert, update, delete on table public.patient_intake_requests to authenticated; + +-- anon não precisa acessar tabelas diretamente +revoke all on table public.patient_invites from anon; +revoke all on table public.patient_intake_requests from anon; + diff --git a/src/sql-arquivos/supabase_cadastro_pacientes.sql b/src/sql-arquivos/supabase_cadastro_pacientes.sql new file mode 100644 index 0000000..4eb0d54 --- /dev/null +++ b/src/sql-arquivos/supabase_cadastro_pacientes.sql @@ -0,0 +1,266 @@ +-- ========================================================= +-- PATCH — Completar cadastro para bater com PatientsCadastroPage.vue +-- (rode DEPOIS do seu supabase_cadastro_pacientes.sql) +-- ========================================================= + +create extension if not exists pgcrypto; + +-- --------------------------------------------------------- +-- 1) Completar colunas que o front usa e hoje faltam em patients +-- --------------------------------------------------------- +do $$ +begin + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='email_alt' + ) then + alter table public.patients add column email_alt text; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='phones' + ) then + -- array de textos (Postgres). No JS você manda ["...","..."] normalmente. + alter table public.patients add column phones text[]; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='gender' + ) then + alter table public.patients add column gender text; + end if; + + if not exists ( + select 1 from information_schema.columns + where table_schema='public' and table_name='patients' and column_name='marital_status' + ) then + alter table public.patients add column marital_status text; + end if; +end $$; + +-- (opcional) índices úteis pra busca/filtro por nome/email +create index if not exists idx_patients_owner_name on public.patients(owner_id, name); +create index if not exists idx_patients_owner_email on public.patients(owner_id, email); + +-- --------------------------------------------------------- +-- 2) patient_groups +-- --------------------------------------------------------- +create table if not exists public.patient_groups ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null references auth.users(id) on delete cascade, + name text not null, + color text, + is_system boolean not null default false, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +-- nome único por owner +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'patient_groups_owner_name_uniq' + and conrelid = 'public.patient_groups'::regclass + ) then + alter table public.patient_groups + add constraint patient_groups_owner_name_uniq unique(owner_id, name); + end if; +end $$; + +drop trigger if exists trg_patient_groups_set_updated_at on public.patient_groups; +create trigger trg_patient_groups_set_updated_at +before update on public.patient_groups +for each row execute function public.set_updated_at(); + +create index if not exists idx_patient_groups_owner on public.patient_groups(owner_id); + +alter table public.patient_groups enable row level security; + +drop policy if exists "patient_groups_select_own" on public.patient_groups; +create policy "patient_groups_select_own" +on public.patient_groups for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists "patient_groups_insert_own" on public.patient_groups; +create policy "patient_groups_insert_own" +on public.patient_groups for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists "patient_groups_update_own" on public.patient_groups; +create policy "patient_groups_update_own" +on public.patient_groups for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "patient_groups_delete_own" on public.patient_groups; +create policy "patient_groups_delete_own" +on public.patient_groups for delete +to authenticated +using (owner_id = auth.uid()); + +grant select, insert, update, delete on public.patient_groups to authenticated; + +-- --------------------------------------------------------- +-- 3) patient_tags +-- --------------------------------------------------------- +create table if not exists public.patient_tags ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null references auth.users(id) on delete cascade, + name text not null, + color text, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'patient_tags_owner_name_uniq' + and conrelid = 'public.patient_tags'::regclass + ) then + alter table public.patient_tags + add constraint patient_tags_owner_name_uniq unique(owner_id, name); + end if; +end $$; + +drop trigger if exists trg_patient_tags_set_updated_at on public.patient_tags; +create trigger trg_patient_tags_set_updated_at +before update on public.patient_tags +for each row execute function public.set_updated_at(); + +create index if not exists idx_patient_tags_owner on public.patient_tags(owner_id); + +alter table public.patient_tags enable row level security; + +drop policy if exists "patient_tags_select_own" on public.patient_tags; +create policy "patient_tags_select_own" +on public.patient_tags for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists "patient_tags_insert_own" on public.patient_tags; +create policy "patient_tags_insert_own" +on public.patient_tags for insert +to authenticated +with check (owner_id = auth.uid()); + +drop policy if exists "patient_tags_update_own" on public.patient_tags; +create policy "patient_tags_update_own" +on public.patient_tags for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "patient_tags_delete_own" on public.patient_tags; +create policy "patient_tags_delete_own" +on public.patient_tags for delete +to authenticated +using (owner_id = auth.uid()); + +grant select, insert, update, delete on public.patient_tags to authenticated; + +-- --------------------------------------------------------- +-- 4) pivôs (patient_group_patient / patient_patient_tag) +-- --------------------------------------------------------- +create table if not exists public.patient_group_patient ( + patient_id uuid not null references public.patients(id) on delete cascade, + patient_group_id uuid not null references public.patient_groups(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (patient_id, patient_group_id) +); + +create index if not exists idx_pgp_patient on public.patient_group_patient(patient_id); +create index if not exists idx_pgp_group on public.patient_group_patient(patient_group_id); + +alter table public.patient_group_patient enable row level security; + +-- a pivot “herda” tenant via join; policy usando exists pra validar owner do patient +drop policy if exists "pgp_select_own" on public.patient_group_patient; +create policy "pgp_select_own" +on public.patient_group_patient for select +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +); + +drop policy if exists "pgp_write_own" on public.patient_group_patient; +create policy "pgp_write_own" +on public.patient_group_patient for all +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +) +with check ( + exists ( + select 1 from public.patients p + where p.id = patient_group_patient.patient_id + and p.owner_id = auth.uid() + ) +); + +grant select, insert, update, delete on public.patient_group_patient to authenticated; + +-- tags pivot (ATENÇÃO: coluna é tag_id, como teu Vue usa!) +create table if not exists public.patient_patient_tag ( + patient_id uuid not null references public.patients(id) on delete cascade, + tag_id uuid not null references public.patient_tags(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (patient_id, tag_id) +); + +create index if not exists idx_ppt_patient on public.patient_patient_tag(patient_id); +create index if not exists idx_ppt_tag on public.patient_patient_tag(tag_id); + +alter table public.patient_patient_tag enable row level security; + +drop policy if exists "ppt_select_own" on public.patient_patient_tag; +create policy "ppt_select_own" +on public.patient_patient_tag for select +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +); + +drop policy if exists "ppt_write_own" on public.patient_patient_tag; +create policy "ppt_write_own" +on public.patient_patient_tag for all +to authenticated +using ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +) +with check ( + exists ( + select 1 from public.patients p + where p.id = patient_patient_tag.patient_id + and p.owner_id = auth.uid() + ) +); + +grant select, insert, update, delete on public.patient_patient_tag to authenticated; + +-- ========================================================= +-- FIM PATCH +-- ========================================================= diff --git a/src/sql-arquivos/supabase_cadastros_recebidos(intakes).sql b/src/sql-arquivos/supabase_cadastros_recebidos(intakes).sql new file mode 100644 index 0000000..3e43d42 --- /dev/null +++ b/src/sql-arquivos/supabase_cadastros_recebidos(intakes).sql @@ -0,0 +1,105 @@ +-- ========================================================= +-- INTakes / Cadastros Recebidos - Supabase Local +-- ========================================================= + +-- 0) Extensões úteis (geralmente já existem no Supabase, mas é seguro) +create extension if not exists pgcrypto; + +-- 1) Função padrão para updated_at +create or replace function public.set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +-- 2) Tabela patient_intake_requests (espelhando nuvem) +create table if not exists public.patient_intake_requests ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + token text, + name text, + email text, + phone text, + notes text, + consent boolean not null default false, + status text not null default 'new', + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + payload jsonb +); + +-- 3) Índices (performance em listagem e filtros) +create index if not exists idx_intakes_owner_created + on public.patient_intake_requests (owner_id, created_at desc); + +create index if not exists idx_intakes_owner_status_created + on public.patient_intake_requests (owner_id, status, created_at desc); + +create index if not exists idx_intakes_status_created + on public.patient_intake_requests (status, created_at desc); + +-- 4) Trigger updated_at +drop trigger if exists trg_patient_intake_requests_updated_at on public.patient_intake_requests; + +create trigger trg_patient_intake_requests_updated_at +before update on public.patient_intake_requests +for each row execute function public.set_updated_at(); + +-- 5) RLS +alter table public.patient_intake_requests enable row level security; + +-- 6) Policies (iguais às que você mostrou na nuvem) +drop policy if exists intake_select_own on public.patient_intake_requests; +create policy intake_select_own +on public.patient_intake_requests +for select +to authenticated +using (owner_id = auth.uid()); + +drop policy if exists intake_update_own on public.patient_intake_requests; +create policy intake_update_own +on public.patient_intake_requests +for update +to authenticated +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists "delete own intake requests" on public.patient_intake_requests; +create policy "delete own intake requests" +on public.patient_intake_requests +for delete +to authenticated +using (owner_id = auth.uid()); + +-- ========================================================= +-- OPCIONAL (RECOMENDADO): registrar conversão +-- ========================================================= +-- Se você pretende marcar intake como convertido e guardar o patient_id: +alter table public.patient_intake_requests + add column if not exists converted_patient_id uuid; + +create index if not exists idx_intakes_converted_patient_id + on public.patient_intake_requests (converted_patient_id); + +-- Opcional: impedir delete de intakes convertidos (melhor para auditoria) +-- (Se quiser manter delete liberado como na nuvem, comente este bloco.) +drop policy if exists "delete own intake requests" on public.patient_intake_requests; +create policy "delete_own_intakes_not_converted" +on public.patient_intake_requests +for delete +to authenticated +using (owner_id = auth.uid() and status <> 'converted'); + +-- ========================================================= +-- OPCIONAL: check de status (evita status inválido) +-- ========================================================= +alter table public.patient_intake_requests + drop constraint if exists chk_intakes_status; + +alter table public.patient_intake_requests + add constraint chk_intakes_status + check (status in ('new', 'converted', 'rejected')); diff --git a/src/sql-arquivos/supabase_patient_groups.sql b/src/sql-arquivos/supabase_patient_groups.sql new file mode 100644 index 0000000..08070b4 --- /dev/null +++ b/src/sql-arquivos/supabase_patient_groups.sql @@ -0,0 +1,174 @@ +/* + patient_groups_setup.sql + Setup completo para: + - public.patient_groups + - public.patient_group_patient (tabela ponte) + - view public.v_patient_groups_with_counts + - índice único por owner + nome (case-insensitive) + - 3 grupos padrão do sistema (Crianças, Adolescentes, Idosos) NÃO editáveis / NÃO removíveis + - triggers de proteção + + Observação (importante): + - Os grupos padrão são criados com owner_id = '00000000-0000-0000-0000-000000000000' (SYSTEM_OWNER), + para ficarem "globais" e não dependerem de auth.uid() em migrations. + - Se você quiser que os grupos padrão pertençam a um owner específico (tenant), + basta trocar o SYSTEM_OWNER abaixo por esse UUID. +*/ + +begin; + +-- =========================== +-- 0) Constante de "dono do sistema" +-- =========================== +-- Troque aqui se você quiser que os grupos padrão pertençam a um owner específico. +-- Ex.: '816b24fe-a0c3-4409-b79b-c6c0a6935d03' +do $$ +begin + -- só para documentar; não cria nada +end $$; + +-- =========================== +-- 1) Tabela principal: patient_groups +-- =========================== +create table if not exists public.patient_groups ( + id uuid primary key default gen_random_uuid(), + name text not null, + description text, + color text, + is_active boolean not null default true, + is_system boolean not null default false, + owner_id uuid not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +-- (Opcional, mas recomendado) Garante que name não seja só espaços +-- e evita nomes vazios. +alter table public.patient_groups + drop constraint if exists patient_groups_name_not_blank_check; + +alter table public.patient_groups + add constraint patient_groups_name_not_blank_check + check (length(btrim(name)) > 0); + +-- =========================== +-- 2) Tabela ponte: patient_group_patient +-- =========================== +-- Se você já tiver essa tabela com FKs, ajuste aqui conforme seu schema. +create table if not exists public.patient_group_patient ( + patient_group_id uuid not null references public.patient_groups(id) on delete cascade, + patient_id uuid not null references public.patients(id) on delete cascade, + created_at timestamptz not null default now() +); + +-- Evita duplicar vínculo paciente<->grupo +create unique index if not exists patient_group_patient_unique +on public.patient_group_patient (patient_group_id, patient_id); + +-- =========================== +-- 3) View com contagem +-- =========================== +create or replace view public.v_patient_groups_with_counts as +select + g.*, + coalesce(count(distinct pgp.patient_id), 0)::int as patients_count +from public.patient_groups g +left join public.patient_group_patient pgp + on pgp.patient_group_id = g.id +group by g.id; + +-- =========================== +-- 4) Índice único: não permitir mesmo nome por owner (case-insensitive) +-- =========================== +-- Atenção: se já existirem duplicados, este índice pode falhar ao criar. +create unique index if not exists patient_groups_owner_name_unique +on public.patient_groups (owner_id, (lower(name))); + +-- =========================== +-- 5) Triggers de proteção: system não edita / não remove +-- =========================== +create or replace function public.prevent_system_group_changes() +returns trigger +language plpgsql +as $$ +begin + if old.is_system = true then + raise exception 'Grupos padrão do sistema não podem ser alterados ou excluídos.'; + end if; + + if tg_op = 'DELETE' then + return old; + end if; + + return new; +end; +$$; + +drop trigger if exists trg_prevent_system_group_changes on public.patient_groups; + +create trigger trg_prevent_system_group_changes +before update or delete on public.patient_groups +for each row +execute function public.prevent_system_group_changes(); + +-- Impede "promover" um grupo comum para system +create or replace function public.prevent_promoting_to_system() +returns trigger +language plpgsql +as $$ +begin + if new.is_system = true and old.is_system is distinct from true then + raise exception 'Não é permitido transformar um grupo comum em grupo do sistema.'; + end if; + return new; +end; +$$; + +drop trigger if exists trg_prevent_promoting_to_system on public.patient_groups; + +create trigger trg_prevent_promoting_to_system +before update on public.patient_groups +for each row +execute function public.prevent_promoting_to_system(); + +-- =========================== +-- 6) Inserir 3 grupos padrão (imutáveis) +-- =========================== +-- Dono "global" do sistema (mude se quiser): +-- 00000000-0000-0000-0000-000000000000 +with sys_owner as ( + select '00000000-0000-0000-0000-000000000000'::uuid as owner_id +) +insert into public.patient_groups (name, description, color, is_active, is_system, owner_id) +select v.name, v.description, v.color, v.is_active, v.is_system, s.owner_id +from sys_owner s +join (values + ('Crianças', 'Grupo padrão do sistema', null, true, true), + ('Adolescentes', 'Grupo padrão do sistema', null, true, true), + ('Idosos', 'Grupo padrão do sistema', null, true, true) +) as v(name, description, color, is_active, is_system) +on true +where not exists ( + select 1 + from public.patient_groups g + where g.owner_id = s.owner_id + and lower(g.name) = lower(v.name) +); + +commit; + +/* + Testes rápidos: + 1) Ver tudo: + select * from public.v_patient_groups_with_counts order by is_system desc, name; + + 2) Tentar editar um system (deve falhar): + update public.patient_groups set name='X' where name='Crianças'; + + 3) Tentar deletar um system (deve falhar): + delete from public.patient_groups where name='Crianças'; + + 4) Tentar duplicar nome no mesmo owner (deve falhar por índice único): + insert into public.patient_groups (name, is_active, is_system, owner_id) + values ('teste22', true, false, '816b24fe-a0c3-4409-b79b-c6c0a6935d03'); +*/ diff --git a/src/sql-arquivos/supabase_patient_index_page.sql b/src/sql-arquivos/supabase_patient_index_page.sql new file mode 100644 index 0000000..c8def53 --- /dev/null +++ b/src/sql-arquivos/supabase_patient_index_page.sql @@ -0,0 +1,147 @@ +-- ========================================================= +-- pacientesIndexPage.sql +-- Views + índices para a tela PatientsIndexPage +-- ========================================================= + +-- 0) Extensões úteis +create extension if not exists pg_trgm; + +-- 1) updated_at automático (se você quiser manter updated_at sempre correto) +create or replace function public.set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +drop trigger if exists trg_patients_set_updated_at on public.patients; +create trigger trg_patients_set_updated_at +before update on public.patients +for each row execute function public.set_updated_at(); + + +-- ========================================================= +-- 2) Views de contagem (usadas em KPIs e telas auxiliares) +-- ========================================================= + +-- 2.1) Grupos com contagem de pacientes +create or replace view public.v_patient_groups_with_counts as +select + g.id, + g.name, + g.color, + coalesce(count(pgp.patient_id), 0)::int as patients_count +from public.patient_groups g +left join public.patient_group_patient pgp + on pgp.patient_group_id = g.id +group by g.id, g.name, g.color; + +-- 2.2) Tags com contagem de pacientes +create or replace view public.v_tag_patient_counts as +select + t.id, + t.name, + t.color, + coalesce(count(ppt.patient_id), 0)::int as patients_count +from public.patient_tags t +left join public.patient_patient_tag ppt + on ppt.tag_id = t.id +group by t.id, t.name, t.color; + + +-- ========================================================= +-- 3) View principal da Index (pacientes + grupos/tags agregados) +-- ========================================================= + +create or replace view public.v_patients_index as +select + p.*, + + -- array JSON com os grupos do paciente + coalesce(gx.groups, '[]'::jsonb) as groups, + + -- array JSON com as tags do paciente + coalesce(tx.tags, '[]'::jsonb) as tags, + + -- contagens para UI/KPIs + coalesce(gx.groups_count, 0)::int as groups_count, + coalesce(tx.tags_count, 0)::int as tags_count + +from public.patients p + +left join lateral ( + select + jsonb_agg( + distinct jsonb_build_object( + 'id', g.id, + 'name', g.name, + 'color', g.color + ) + ) filter (where g.id is not null) as groups, + count(distinct g.id) as groups_count + from public.patient_group_patient pgp + join public.patient_groups g + on g.id = pgp.patient_group_id + where pgp.patient_id = p.id +) gx on true + +left join lateral ( + select + jsonb_agg( + distinct jsonb_build_object( + 'id', t.id, + 'name', t.name, + 'color', t.color + ) + ) filter (where t.id is not null) as tags, + count(distinct t.id) as tags_count + from public.patient_patient_tag ppt + join public.patient_tags t + on t.id = ppt.tag_id + where ppt.patient_id = p.id +) tx on true; + + +-- ========================================================= +-- 4) Índices recomendados (performance real na listagem/filtros) +-- ========================================================= + +-- Patients +create index if not exists idx_patients_owner_id + on public.patients (owner_id); + +create index if not exists idx_patients_created_at + on public.patients (created_at desc); + +create index if not exists idx_patients_status + on public.patients (status); + +create index if not exists idx_patients_last_attended_at + on public.patients (last_attended_at desc); + +-- Busca rápida (name/email/phone) +create index if not exists idx_patients_name_trgm + on public.patients using gin (name gin_trgm_ops); + +create index if not exists idx_patients_email_trgm + on public.patients using gin (email gin_trgm_ops); + +create index if not exists idx_patients_phone_trgm + on public.patients using gin (phone gin_trgm_ops); + +-- Pivot: grupos +create index if not exists idx_pgp_patient_id + on public.patient_group_patient (patient_id); + +create index if not exists idx_pgp_group_id + on public.patient_group_patient (patient_group_id); + +-- Pivot: tags +create index if not exists idx_ppt_patient_id + on public.patient_patient_tag (patient_id); + +create index if not exists idx_ppt_tag_id + on public.patient_patient_tag (tag_id); diff --git a/src/sql-arquivos/supabase_patients_populate.sql b/src/sql-arquivos/supabase_patients_populate.sql new file mode 100644 index 0000000..e69de29 diff --git a/src/sql-arquivos/supabase_tags.sql b/src/sql-arquivos/supabase_tags.sql new file mode 100644 index 0000000..42668af --- /dev/null +++ b/src/sql-arquivos/supabase_tags.sql @@ -0,0 +1,134 @@ +create extension if not exists pgcrypto; + +-- =============================== +-- TABELA: patient_tags +-- =============================== +create table if not exists public.patient_tags ( + id uuid primary key default gen_random_uuid(), + owner_id uuid not null, + name text not null, + color text, + is_native boolean not null default false, + created_at timestamptz not null default now(), + updated_at timestamptz +); + +create unique index if not exists patient_tags_owner_name_uq + on public.patient_tags (owner_id, lower(name)); + +-- =============================== +-- TABELA: patient_patient_tag (pivot) +-- =============================== +create table if not exists public.patient_patient_tag ( + owner_id uuid not null, + patient_id uuid not null, + tag_id uuid not null, + created_at timestamptz not null default now(), + primary key (patient_id, tag_id) +); + +create index if not exists ppt_owner_idx on public.patient_patient_tag(owner_id); +create index if not exists ppt_tag_idx on public.patient_patient_tag(tag_id); +create index if not exists ppt_patient_idx on public.patient_patient_tag(patient_id); + +-- =============================== +-- FOREIGN KEYS (com checagem) +-- =============================== +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'ppt_tag_fk' + and conrelid = 'public.patient_patient_tag'::regclass + ) then + alter table public.patient_patient_tag + add constraint ppt_tag_fk + foreign key (tag_id) + references public.patient_tags(id) + on delete cascade; + end if; +end $$; + +do $$ +begin + if not exists ( + select 1 from pg_constraint + where conname = 'ppt_patient_fk' + and conrelid = 'public.patient_patient_tag'::regclass + ) then + alter table public.patient_patient_tag + add constraint ppt_patient_fk + foreign key (patient_id) + references public.patients(id) + on delete cascade; + end if; +end $$; + +-- =============================== +-- VIEW: contagem por tag +-- =============================== +create or replace view public.v_tag_patient_counts as +select + t.id, + t.owner_id, + t.name, + t.color, + t.is_native, + t.created_at, + t.updated_at, + coalesce(count(ppt.patient_id), 0)::int as patient_count +from public.patient_tags t +left join public.patient_patient_tag ppt + on ppt.tag_id = t.id + and ppt.owner_id = t.owner_id +group by + t.id, t.owner_id, t.name, t.color, t.is_native, t.created_at, t.updated_at; + +-- =============================== +-- RLS +-- =============================== +alter table public.patient_tags enable row level security; +alter table public.patient_patient_tag enable row level security; + +drop policy if exists tags_select_own on public.patient_tags; +create policy tags_select_own +on public.patient_tags +for select +using (owner_id = auth.uid()); + +drop policy if exists tags_insert_own on public.patient_tags; +create policy tags_insert_own +on public.patient_tags +for insert +with check (owner_id = auth.uid()); + +drop policy if exists tags_update_own on public.patient_tags; +create policy tags_update_own +on public.patient_tags +for update +using (owner_id = auth.uid()) +with check (owner_id = auth.uid()); + +drop policy if exists tags_delete_own on public.patient_tags; +create policy tags_delete_own +on public.patient_tags +for delete +using (owner_id = auth.uid()); + +drop policy if exists ppt_select_own on public.patient_patient_tag; +create policy ppt_select_own +on public.patient_patient_tag +for select +using (owner_id = auth.uid()); + +drop policy if exists ppt_insert_own on public.patient_patient_tag; +create policy ppt_insert_own +on public.patient_patient_tag +for insert +with check (owner_id = auth.uid()); + +drop policy if exists ppt_delete_own on public.patient_patient_tag; +create policy ppt_delete_own +on public.patient_patient_tag +for delete +using (owner_id = auth.uid()); diff --git a/src/stores/entitlementsStore.js b/src/stores/entitlementsStore.js new file mode 100644 index 0000000..2aa8fd5 --- /dev/null +++ b/src/stores/entitlementsStore.js @@ -0,0 +1,107 @@ +// src/stores/entitlementsStore.js +import { defineStore } from 'pinia' +import { supabase } from '@/lib/supabase/client' + +function normalizeKey(k) { + return String(k || '').trim() +} + +export const useEntitlementsStore = defineStore('entitlements', { + state: () => ({ + loading: false, + loadedForTenant: null, + features: [], // array reativo de feature_key liberadas + raw: [], + error: null, + loadedAt: null + }), + + getters: { + can: (state) => (featureKey) => state.features.includes(featureKey), + has: (state) => (featureKey) => state.features.includes(featureKey) + }, + + actions: { + async fetch(tenantId, opts = {}) { + return this.loadForTenant(tenantId, opts) + }, + + clear() { + return this.invalidate() + }, + + /** + * Carrega entitlements do tenant. + * Importante: quando o plano muda, tenantId é o mesmo, + * então você DEVE chamar com { force: true }. + * + * opts: + * - force: ignora cache do tenant + * - maxAgeMs: se definido, recarrega quando loadedAt estiver velho + */ + async loadForTenant(tenantId, { force = false, maxAgeMs = 0 } = {}) { + if (!tenantId) { + this.invalidate() + return + } + + const sameTenant = this.loadedForTenant === tenantId + const hasLoadedAt = typeof this.loadedAt === 'number' + const isFresh = + sameTenant && + hasLoadedAt && + maxAgeMs > 0 && + Date.now() - this.loadedAt < maxAgeMs + + if (!force && sameTenant && (maxAgeMs === 0 || isFresh)) return + + this.loading = true + this.error = null + + try { + // ✅ Modelo B: entitlements por tenant (view) + const { data, error } = await supabase + .from('v_tenant_entitlements') + .select('feature_key') + .eq('tenant_id', tenantId) + + if (error) throw error + + const rows = data ?? [] + + // normaliza, remove vazios e duplicados + const list = [] + const seen = new Set() + for (const r of rows) { + const key = normalizeKey(r?.feature_key) + if (!key) continue + if (seen.has(key)) continue + seen.add(key) + list.push(key) + } + + this.raw = rows + this.features = list + this.loadedForTenant = tenantId + this.loadedAt = Date.now() + } catch (e) { + this.error = e + this.raw = [] + this.features = [] + this.loadedForTenant = tenantId + this.loadedAt = Date.now() + } finally { + this.loading = false + } + }, + + invalidate() { + this.loadedForTenant = null + this.features = [] + this.raw = [] + this.error = null + this.loadedAt = null + this.loading = false + } + } +}) diff --git a/src/stores/saasHealthStore.js b/src/stores/saasHealthStore.js new file mode 100644 index 0000000..3ac54e3 --- /dev/null +++ b/src/stores/saasHealthStore.js @@ -0,0 +1,31 @@ +// src/stores/saasHealthStore.js +import { defineStore } from 'pinia' +import { supabase } from '@/lib/supabase/client' + +export const useSaasHealthStore = defineStore('saasHealth', { + state: () => ({ + mismatchCount: 0, + loading: false, + lastLoadedAt: null + }), + + actions: { + async loadMismatchCount ({ force = false } = {}) { + if (this.loading) return + if (!force && this.lastLoadedAt && (Date.now() - this.lastLoadedAt) < 30_000) return // cache 30s + + this.loading = true + try { + const { count, error } = await supabase + .from('v_subscription_feature_mismatch') + .select('*', { count: 'exact', head: true }) + + if (error) throw error + this.mismatchCount = Number(count || 0) + this.lastLoadedAt = Date.now() + } finally { + this.loading = false + } + } + } +}) diff --git a/src/stores/tenantStore.js b/src/stores/tenantStore.js new file mode 100644 index 0000000..2fe13bf --- /dev/null +++ b/src/stores/tenantStore.js @@ -0,0 +1,86 @@ +// src/stores/tenantStore.js +import { defineStore } from 'pinia' +import { supabase } from '@/lib/supabase/client' + +export const useTenantStore = defineStore('tenant', { + state: () => ({ + loading: false, + loaded: false, + + user: null, // auth user + memberships: [], // [{ tenant_id, role, status }] + activeTenantId: null, + activeRole: null, + + needsTenantLink: false, + error: null + }), + + actions: { + async loadSessionAndTenant () { + if (this.loading) return + this.loading = true + this.error = null + + try { + // 1) auth user (estável) + const { data, error } = await supabase.auth.getSession() + if (error) throw error + + this.user = data?.session?.user ?? null + + // sem sessão -> não chama RPC, só marca estado + if (!this.user) { + this.memberships = [] + this.activeTenantId = null + this.activeRole = null + this.needsTenantLink = false + this.loaded = true + return + } + + // 2) memberships via RPC + const { data: mem, error: mErr } = await supabase.rpc('my_tenants') + if (mErr) throw mErr + + this.memberships = Array.isArray(mem) ? mem : [] + + // 3) define active tenant (primeiro active) + const firstActive = this.memberships.find(x => x.status === 'active') + this.activeTenantId = firstActive?.tenant_id ?? null + this.activeRole = firstActive?.role ?? null + + // se logou mas não tem vínculo ativo + this.needsTenantLink = !this.activeTenantId + + this.loaded = true + } catch (e) { + console.warn('[tenantStore] loadSessionAndTenant falhou:', e) + this.error = e + + // ⚠️ NÃO zera tudo agressivamente por erro transitório. + // Mantém o que já tinha (se tiver), mas marca loaded pra não travar o app. + // Se você preferir ser mais “duro”, só zere quando não houver sessão: + // (a sessão já foi lida acima; se der erro antes, user pode estar null) + if (!this.user) { + this.memberships = [] + this.activeTenantId = null + this.activeRole = null + this.needsTenantLink = false + } + + this.loaded = true + } finally { + this.loading = false + } +} +, + + setActiveTenant (tenantId) { + const found = this.memberships.find(x => x.tenant_id === tenantId && x.status === 'active') + this.activeTenantId = found?.tenant_id ?? null + this.activeRole = found?.role ?? null + this.needsTenantLink = !this.activeTenantId + } + } +}) diff --git a/src/theme/theme.options.js b/src/theme/theme.options.js new file mode 100644 index 0000000..a07ddd1 --- /dev/null +++ b/src/theme/theme.options.js @@ -0,0 +1,140 @@ +// src/theme/theme.options.js +import { $t, updatePreset, updateSurfacePalette } from '@primeuix/themes' +import Aura from '@primeuix/themes/aura' +import Lara from '@primeuix/themes/lara' +import Nora from '@primeuix/themes/nora' + +/** + * Presets + */ +export const presetsMap = { Aura, Lara, Nora } +export const presetOptions = Object.keys(presetsMap) + +/** + * Colors (Primary) + */ +export const primaryColors = [ + { name: 'noir', palette: {} }, + { name: 'emerald', palette: { 50: '#ecfdf5', 100: '#d1fae5', 200: '#a7f3d0', 300: '#6ee7b7', 400: '#34d399', 500: '#10b981', 600: '#059669', 700: '#047857', 800: '#065f46', 900: '#064e3b', 950: '#022c22' } }, + { name: 'green', palette: { 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac', 400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d', 800: '#166534', 900: '#14532d', 950: '#052e16' } }, + { name: 'lime', palette: { 50: '#f7fee7', 100: '#ecfccb', 200: '#d9f99d', 300: '#bef264', 400: '#a3e635', 500: '#84cc16', 600: '#65a30d', 700: '#4d7c0f', 800: '#3f6212', 900: '#365314', 950: '#1a2e05' } }, + { name: 'orange', palette: { 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12', 950: '#431407' } }, + { name: 'amber', palette: { 50: '#fffbeb', 100: '#fef3c7', 200: '#fde68a', 300: '#fcd34d', 400: '#fbbf24', 500: '#f59e0b', 600: '#d97706', 700: '#b45309', 800: '#92400e', 900: '#78350f', 950: '#451a03' } }, + { name: 'yellow', palette: { 50: '#fefce8', 100: '#fef9c3', 200: '#fef08a', 300: '#fde047', 400: '#facc15', 500: '#eab308', 600: '#ca8a04', 700: '#a16207', 800: '#854d0e', 900: '#713f12', 950: '#422006' } }, + { name: 'teal', palette: { 50: '#f0fdfa', 100: '#ccfbf1', 200: '#99f6e4', 300: '#5eead4', 400: '#2dd4bf', 500: '#14b8a6', 600: '#0d9488', 700: '#0f766e', 800: '#115e59', 900: '#134e4a', 950: '#042f2e' } }, + { name: 'cyan', palette: { 50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9', 400: '#22d3ee', 500: '#06b6d4', 600: '#0891b2', 700: '#0e7490', 800: '#155e75', 900: '#164e63', 950: '#083344' } }, + { name: 'sky', palette: { 50: '#f0f9ff', 100: '#e0e2fe', 200: '#bae6fd', 300: '#7dd3fc', 400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1', 800: '#075985', 900: '#0c4a6e', 950: '#082f49' } }, + { name: 'blue', palette: { 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a', 950: '#172554' } }, + { name: 'indigo', palette: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81', 950: '#1e1b4b' } }, + { name: 'violet', palette: { 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd', 400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9', 800: '#5b21b6', 900: '#4c1d95', 950: '#2e1065' } }, + { name: 'purple', palette: { 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe', 400: '#c084fc', 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce', 800: '#6b21a8', 900: '#581c87', 950: '#3b0764' } }, + { name: 'fuchsia', palette: { 50: '#fdf4ff', 100: '#fae8ff', 200: '#f5d0fe', 300: '#f0abfc', 400: '#e879f9', 500: '#d946ef', 600: '#c026d3', 700: '#a21caf', 800: '#86198f', 900: '#701a75', 950: '#4a044e' } }, + { name: 'pink', palette: { 50: '#fdf2f8', 100: '#fce7f3', 200: '#fbcfe8', 300: '#f9a8d4', 400: '#f472b6', 500: '#ec4899', 600: '#db2777', 700: '#be185d', 800: '#9d174d', 900: '#831843', 950: '#500724' } }, + { name: 'rose', palette: { 50: '#fff1f2', 100: '#ffe4e6', 200: '#fecdd3', 300: '#fda4af', 400: '#fb7185', 500: '#f43f5e', 600: '#e11d48', 700: '#be123c', 800: '#9f1239', 900: '#881337', 950: '#4c0519' } } +] + +/** + * Surfaces + */ +export const surfaces = [ + { name: 'slate', palette: { 0: '#ffffff', 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', 950: '#020617' } }, + { name: 'gray', palette: { 0: '#ffffff', 50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db', 400: '#9ca3af', 500: '#6b7280', 600: '#4b5563', 700: '#374151', 800: '#1f2937', 900: '#111827', 950: '#030712' } }, + { name: 'zinc', palette: { 0: '#ffffff', 50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8', 400: '#a1a1aa', 500: '#71717a', 600: '#52525b', 700: '#3f3f46', 800: '#27272a', 900: '#18181b', 950: '#09090b' } }, + { name: 'neutral', palette: { 0: '#ffffff', 50: '#fafafa', 100: '#f5f5f5', 200: '#e5e5e5', 300: '#d4d4d4', 400: '#a3a3a3', 500: '#737373', 600: '#525252', 700: '#404040', 800: '#262626', 900: '#171717', 950: '#0a0a0a' } }, + { name: 'stone', palette: { 0: '#ffffff', 50: '#fafaf9', 100: '#f5f5f4', 200: '#e7e5e4', 300: '#d6d3d1', 400: '#a8a29e', 500: '#78716c', 600: '#57534e', 700: '#44403c', 800: '#292524', 900: '#1c1917', 950: '#0c0a09' } }, + { name: 'soho', palette: { 0: '#ffffff', 50: '#f4f4f4', 100: '#e8e9e9', 200: '#d2d2d4', 300: '#bbbcbe', 400: '#a5a5a9', 500: '#8e8f93', 600: '#77787d', 700: '#616268', 800: '#4a4b52', 900: '#34343d', 950: '#1d1e27' } }, + { name: 'viva', palette: { 0: '#ffffff', 50: '#f3f3f3', 100: '#e7e7e8', 200: '#cfd0d0', 300: '#b7b8b9', 400: '#9fa1a1', 500: '#87898a', 600: '#6e7173', 700: '#565a5b', 800: '#3e4244', 900: '#262b2c', 950: '#0e1315' } }, + { name: 'ocean', palette: { 0: '#ffffff', 50: '#fbfcfc', 100: '#F7F9F8', 200: '#EFF3F2', 300: '#DADEDD', 400: '#B1B7B6', 500: '#828787', 600: '#5F7274', 700: '#415B61', 800: '#29444E', 900: '#183240', 950: '#0c1920' } } +] + +/** + * ✅ noir: primary “vira” surface (o bloco que você pediu pra ficar aqui) + */ +export const noirPrimaryFromSurface = { + 50: '{surface.50}', + 100: '{surface.100}', + 200: '{surface.200}', + 300: '{surface.300}', + 400: '{surface.400}', + 500: '{surface.500}', + 600: '{surface.600}', + 700: '{surface.700}', + 800: '{surface.800}', + 900: '{surface.900}', + 950: '{surface.950}' +} + +/** + * Helpers + */ +export function getSurfacePalette(surfaceName) { + return surfaces.find(s => s.name === surfaceName)?.palette +} + +/** + * ✅ Ponto único: “Preset Extension” baseado no layoutConfig atual + * Use assim: updatePreset(getPresetExt(layoutConfig)) + */ +export function getPresetExt(layoutConfig) { + const primaryName = layoutConfig?.primary || 'noir' + const color = primaryColors.find(c => c.name === primaryName) || { name: 'noir', palette: {} } + + if (color.name === 'noir') { + return { + semantic: { + primary: noirPrimaryFromSurface, + colorScheme: { + light: { + primary: { color: '{primary.950}', contrastColor: '#ffffff', hoverColor: '{primary.800}', activeColor: '{primary.700}' }, + highlight: { background: '{primary.950}', focusBackground: '{primary.700}', color: '#ffffff', focusColor: '#ffffff' } + }, + dark: { + primary: { color: '{primary.50}', contrastColor: '{primary.950}', hoverColor: '{primary.200}', activeColor: '{primary.300}' }, + highlight: { background: '{primary.50}', focusBackground: '{primary.300}', color: '{primary.950}', focusColor: '{primary.950}' } + } + } + } + } + } + + return { + semantic: { + primary: color.palette, + colorScheme: { + light: { + primary: { color: '{primary.500}', contrastColor: '#ffffff', hoverColor: '{primary.600}', activeColor: '{primary.700}' }, + highlight: { background: '{primary.50}', focusBackground: '{primary.100}', color: '{primary.700}', focusColor: '{primary.800}' } + }, + dark: { + primary: { color: '{primary.400}', contrastColor: '{surface.900}', hoverColor: '{primary.300}', activeColor: '{primary.200}' }, + highlight: { + background: 'color-mix(in srgb, {primary.400}, transparent 84%)', + focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)', + color: 'rgba(255,255,255,.87)', + focusColor: 'rgba(255,255,255,.87)' + } + } + } + } + } +} + +export function applyThemeEngine(layoutConfig) { + const presetValue = presetsMap?.[layoutConfig?.preset] || presetsMap.Aura + const surfacePalette = getSurfacePalette(layoutConfig?.surface) + + const ext = getPresetExt(layoutConfig) + + // 1) motor principal + $t() + .preset(presetValue) + .preset(ext) + .surfacePalette(surfacePalette) + .use({ useDefaultOptions: true }) + + // 2) redundante/seguro + updatePreset(ext) + if (surfacePalette) updateSurfacePalette(surfacePalette) + + return { presetValue, surfacePalette, ext } +} diff --git a/src/utils/dateBR.js b/src/utils/dateBR.js new file mode 100644 index 0000000..d835f28 --- /dev/null +++ b/src/utils/dateBR.js @@ -0,0 +1,24 @@ +// src/utils/dateBR.js + +export function pad2(n) { + return String(n).padStart(2, '0') +} + +// ISO (YYYY-MM-DD) -> BR (DD-MM-YYYY) +export function isoToBR(iso) { + if (!iso) return '' + const s = String(iso).slice(0, 10) + const [y, m, d] = s.split('-') + if (!y || !m || !d) return '' + return `${pad2(d)}-${pad2(m)}-${y}` +} + +// BR (DD-MM-YYYY) -> ISO (YYYY-MM-DD) +export function brToISO(br) { + if (!br) return null + const s = String(br).trim() + const m = s.match(/^(\d{2})-(\d{2})-(\d{4})$/) + if (!m) return null + const [, dd, mm, yyyy] = m + return `${yyyy}-${mm}-${dd}` +} diff --git a/src/utils/slotsGenerator.js b/src/utils/slotsGenerator.js new file mode 100644 index 0000000..232ab8c --- /dev/null +++ b/src/utils/slotsGenerator.js @@ -0,0 +1,51 @@ +// src/utils/slotsGenerator.js + +function toMinutes(hhmm) { + const [h, m] = String(hhmm).slice(0, 5).split(':').map(Number) + return (h * 60) + m +} +function toHHMM(min) { + const h = Math.floor(min / 60) + const m = min % 60 + return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}` +} + +/** + * Gera lista de horários (HH:MM) a partir: + * - janelas: [{hora_inicio:'08:00', hora_fim:'12:00', ativo:true}] + * - regra: {passo_minutos:60, offset_minutos:30, ativo:true} + * + * Retorna horários de INÍCIO (igual Altegio) + */ +export function gerarSlotsDoDia(janelas, regra) { + const passo = Number(regra?.passo_minutos || 60) + const offset = Number(regra?.offset_minutos || 0) + + const ativos = (janelas || []).filter(j => j?.ativo !== false) + + const out = [] + + for (const j of ativos) { + const start = toMinutes(j.hora_inicio) + const end = toMinutes(j.hora_fim) + + // encontra o primeiro t >= start que respeita offset + // condição: t % passo == offset (mod passo), mas offset é dentro da hora. + // Implementação simples: alinhar pelo minuto do dia: + // alvo: t ≡ offset (mod passo) quando offset é interpretado no ciclo do passo. + // Para seu uso (passo 60, offset 30), funciona perfeito. + let t = start + const mod = ((t % passo) + passo) % passo + const need = ((offset - mod) + passo) % passo + t = t + need + + while (t + 1 <= end) { + // só inclui se dentro do intervalo + if (t >= start && t < end) out.push(toHHMM(t)) + t += passo + } + } + + // unique + sort + return Array.from(new Set(out)).sort() +} diff --git a/src/utils/upgradeContext.js b/src/utils/upgradeContext.js new file mode 100644 index 0000000..32ae4aa --- /dev/null +++ b/src/utils/upgradeContext.js @@ -0,0 +1,58 @@ +// src/utils/upgradeContext.js + +/** + * Parse "missing" query param into array of unique feature keys. + * Accepts: + * - "feature_a" + * - "feature_a,feature_b" + * - ["feature_a", "feature_b"] (vue-router pode entregar array) + */ +export function parseMissingKeys (missing) { + if (!missing) return [] + + const raw = Array.isArray(missing) ? missing.join(',') : String(missing) + const keys = raw + .split(',') + .map(s => s.trim()) + .filter(Boolean) + + // unique preserving order + const seen = new Set() + const unique = [] + for (const k of keys) { + if (!seen.has(k)) { + seen.add(k) + unique.push(k) + } + } + return unique +} + +/** + * Parse redirect param. Only allow internal app paths to avoid open-redirect. + * - Must start with "/" + * - Must NOT start with "//" + */ +export function parseRedirectTo (redirect) { + if (!redirect) return null + const s = Array.isArray(redirect) ? redirect[0] : String(redirect) + const trimmed = s.trim() + if (!trimmed) return null + if (!trimmed.startsWith('/')) return null + if (trimmed.startsWith('//')) return null + return trimmed +} + +/** + * Build /upgrade URL with missing feature and redirect target. + */ +export function buildUpgradeUrl ({ missingKeys = [], redirectTo = null } = {}) { + const keys = Array.isArray(missingKeys) ? missingKeys.filter(Boolean) : [] + const q = new URLSearchParams() + + if (keys.length) q.set('missing', keys.join(',')) + if (redirectTo) q.set('redirect', redirectTo) + + const qs = q.toString() + return qs ? `/upgrade?${qs}` : '/upgrade' +} diff --git a/src/views/pages/Crud.vue b/src/views/pages/Crud.vue index 772e6af..3dce360 100644 --- a/src/views/pages/Crud.vue +++ b/src/views/pages/Crud.vue @@ -1,5 +1,5 @@ + + \ No newline at end of file diff --git a/src/views/pages/NotFound.vue b/src/views/pages/NotFound.vue index f7f7650..2e3edeb 100644 --- a/src/views/pages/NotFound.vue +++ b/src/views/pages/NotFound.vue @@ -1,63 +1,121 @@ diff --git a/src/views/Dashboard.vue b/src/views/pages/admin/AdminDashboard.vue similarity index 97% rename from src/views/Dashboard.vue rename to src/views/pages/admin/AdminDashboard.vue index 86ed269..b4d3adb 100644 --- a/src/views/Dashboard.vue +++ b/src/views/pages/admin/AdminDashboard.vue @@ -7,6 +7,7 @@ import StatsWidget from '@/components/dashboard/StatsWidget.vue';