-
-
Buscar Usuário
-
Digite a matrícula do usuário para personalizar suas permissões
-
-
-
-
- e.key === "Enter" && buscarUsuario()}
- />
-
-
-
-
-
- {#if usuarioEncontrado}
-
- {/if}
-
-
-
+
+
+
+ A personalização por usuário foi substituída por permissões por ação
+ por perfil. Utilize o
+ Painel de Permissões para configurar.
+
-
-
- {#if usuarioEncontrado}
-
-
-
-
-
- {usuarioEncontrado.nome.charAt(0)}
-
-
-
-
-
{usuarioEncontrado.nome}
-
-
-
- Matrícula: {usuarioEncontrado.matricula}
-
-
-
- Email: {usuarioEncontrado.email}
-
-
-
-
-
-
- Nível {usuarioEncontrado.role.nivel}
-
-
{usuarioEncontrado.role.descricao}
-
- {usuarioEncontrado.ativo ? "Ativo" : "Inativo"}
-
-
-
-
-
-
-
-
-
-
Permissões Personalizadas
-
-
-
-
- Permissões personalizadas sobrepõem as permissões da função.
- Configure apenas os menus que deseja personalizar para este usuário.
-
-
-
-
- {#if menusQuery.isLoading}
-
-
-
- {:else if menusQuery.data}
-
- {/if}
-
-
- {/if}
-
diff --git a/apps/web/src/routes/api/auth/[...all]/+server.ts b/apps/web/src/routes/api/auth/[...all]/+server.ts
deleted file mode 100644
index dd7705e..0000000
--- a/apps/web/src/routes/api/auth/[...all]/+server.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { createSvelteKitHandler } from "@mmailaender/convex-better-auth-svelte/sveltekit";
-
-export const { GET, POST } = createSvelteKitHandler();
diff --git a/bun.lock b/bun.lock
index 624b413..4317cd3 100644
--- a/bun.lock
+++ b/bun.lock
@@ -6,12 +6,11 @@
"dependencies": {
"@tanstack/svelte-form": "^1.23.8",
"chart.js": "^4.5.1",
- "lucide-svelte": "^0.546.0",
+ "lucide-svelte": "^0.548.0",
"svelte-chartjs": "^3.1.5",
},
"devDependencies": {
- "@biomejs/biome": "^2.2.0",
- "fdir": "^6.5.0",
+ "@biomejs/biome": "^2.3.2",
"turbo": "^2.5.4",
},
"optionalDependencies": {
@@ -22,7 +21,6 @@
"name": "web",
"version": "0.0.1",
"dependencies": {
- "@convex-dev/better-auth": "^0.9.6",
"@dicebear/collection": "^9.2.4",
"@dicebear/core": "^9.2.4",
"@fullcalendar/core": "^6.1.19",
@@ -31,11 +29,9 @@
"@fullcalendar/list": "^6.1.19",
"@fullcalendar/multimonth": "^6.1.19",
"@internationalized/date": "^3.10.0",
- "@mmailaender/convex-better-auth-svelte": "^0.2.0",
"@sgse-app/backend": "*",
"@tanstack/svelte-form": "^1.19.2",
"@types/papaparse": "^5.3.14",
- "better-auth": "1.3.27",
"convex": "^1.28.0",
"convex-svelte": "^0.0.11",
"date-fns": "^4.1.0",
@@ -62,25 +58,11 @@
"vite": "^7.1.2",
},
},
- "packages/auth": {
- "name": "@sgse-app/auth",
- "version": "1.0.0",
- "dependencies": {
- "better-auth": "1.3.27",
- "convex": "^1.28.0",
- },
- "devDependencies": {
- "@types/node": "^24.3.0",
- "typescript": "^5.9.2",
- },
- },
"packages/backend": {
"name": "@sgse-app/backend",
"version": "1.0.0",
"dependencies": {
- "@convex-dev/better-auth": "^0.9.6",
"@dicebear/avataaars": "^9.2.4",
- "better-auth": "1.3.27",
"convex": "^1.28.0",
"nodemailer": "^7.0.10",
},
@@ -162,31 +144,23 @@
"@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="],
- "@better-auth/core": ["@better-auth/core@1.3.27", "", { "dependencies": { "better-call": "1.0.19", "zod": "^4.1.5" } }, "sha512-3Sfdax6MQyronY+znx7bOsfQHI6m1SThvJWb0RDscFEAhfqLy95k1sl+/PgGyg0cwc2cUXoEiAOSqYdFYrg3vA=="],
+ "@biomejs/biome": ["@biomejs/biome@2.3.2", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.2", "@biomejs/cli-darwin-x64": "2.3.2", "@biomejs/cli-linux-arm64": "2.3.2", "@biomejs/cli-linux-arm64-musl": "2.3.2", "@biomejs/cli-linux-x64": "2.3.2", "@biomejs/cli-linux-x64-musl": "2.3.2", "@biomejs/cli-win32-arm64": "2.3.2", "@biomejs/cli-win32-x64": "2.3.2" }, "bin": { "biome": "bin/biome" } }, "sha512-8e9tzamuDycx7fdrcJ/F/GDZ8SYukc5ud6tDicjjFqURKYFSWMl0H0iXNXZEGmcmNUmABgGuHThPykcM41INgg=="],
- "@better-auth/utils": ["@better-auth/utils@0.3.0", "", {}, "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw=="],
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4LECm4kc3If0JISai4c3KWQzukoUdpxy4fRzlrPcrdMSRFksR9ZoXK7JBcPuLBmd2SoT4/d7CQS33VnZpgBjew=="],
- "@better-fetch/fetch": ["@better-fetch/fetch@1.1.18", "", {}, "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="],
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-jNMnfwHT4N3wi+ypRfMTjLGnDmKYGzxVr1EYAPBcauRcDnICFXN81wD6wxJcSUrLynoyyYCdfW6vJHS/IAoTDA=="],
- "@biomejs/biome": ["@biomejs/biome@2.3.1", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.1", "@biomejs/cli-darwin-x64": "2.3.1", "@biomejs/cli-linux-arm64": "2.3.1", "@biomejs/cli-linux-arm64-musl": "2.3.1", "@biomejs/cli-linux-x64": "2.3.1", "@biomejs/cli-linux-x64-musl": "2.3.1", "@biomejs/cli-win32-arm64": "2.3.1", "@biomejs/cli-win32-x64": "2.3.1" }, "bin": { "biome": "bin/biome" } }, "sha512-A29evf1R72V5bo4o2EPxYMm5mtyGvzp2g+biZvRFx29nWebGyyeOSsDWGx3tuNNMFRepGwxmA9ZQ15mzfabK2w=="],
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-amnqvk+gWybbQleRRq8TMe0rIv7GHss8mFJEaGuEZYWg1Tw14YKOkeo8h6pf1c+d3qR+JU4iT9KXnBKGON4klw=="],
- "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ombSf3MnTUueiYGN1SeI9tBCsDUhpWzOwS63Dove42osNh0PfE1cUtHFx6eZ1+MYCCLwXzlFlYFdrJ+U7h6LcA=="],
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-2Zz4usDG1GTTPQnliIeNx6eVGGP2ry5vE/v39nT73a3cKN6t5H5XxjcEoZZh62uVZvED7hXXikclvI64vZkYqw=="],
- "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-pcOfwyoQkrkbGvXxRvZNe5qgD797IowpJPovPX5biPk2FwMEV+INZqfCaz4G5bVq9hYnjwhRMamg11U4QsRXrQ=="],
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8BG/vRAhFz1pmuyd24FQPhNeueLqPtwvZk6yblABY2gzL2H8fLQAF/Z2OPIc+BPIVPld+8cSiKY/KFh6k81xfA=="],
- "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-td5O8pFIgLs8H1sAZsD6v+5quODihyEw4nv2R8z7swUfIK1FKk+15e4eiYVLcAE4jUqngvh4j3JCNgg0Y4o4IQ=="],
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-gzB19MpRdTuOuLtPpFBGrV3Lq424gHyq2lFj8wfX9tvLMLdmA/R9C7k/mqBp/spcbWuHeIEKgEs3RviOPcWGBA=="],
- "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+DZYv8l7FlUtTrWs1Tdt1KcNCAmRO87PyOnxKGunbWm5HKg1oZBSbIIPkjrCtDZaeqSG1DiGx7qF+CPsquQRcg=="],
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCruqQlfWjhMlOdyf5pDHOxoNm4WoyY2vZ4YN33/nuZBRstVDuqPPjS0yBkbUlLEte11FbpW+wWSlfnZfSIZvg=="],
- "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-PYWgEO7up7XYwSAArOpzsVCiqxBCXy53gsReAb1kKYIyXaoAlhBaBMvxR/k2Rm9aTuZ662locXUmPk/Aj+Xu+Q=="],
-
- "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Y3Ob4nqgv38Mh+6EGHltuN+Cq8aj/gyMTJYzkFZV2AEj+9XzoXB9VNljz9pjfFNHUxvLEV4b55VWyxozQTBaUQ=="],
-
- "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RHIG/zgo+69idUqVvV3n8+j58dKYABRpMyDmfWu2TITC+jwGPiEaT0Q3RKD+kQHiS80mpBrST0iUGeEXT0bU9A=="],
-
- "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.1", "", { "os": "win32", "cpu": "x64" }, "sha512-izl30JJ5Dp10mi90Eko47zhxE6pYyWPcnX1NQxKpL/yMhXxf95oLTzfpu4q+MDBh/gemNqyJEwjBpe0MT5iWPA=="],
-
- "@convex-dev/better-auth": ["@convex-dev/better-auth@0.9.6", "", { "dependencies": { "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "remeda": "^2.32.0", "semver": "^7.7.3", "type-fest": "^4.39.1", "zod": "^3.24.4" }, "peerDependencies": { "better-auth": "1.3.27", "convex": "^1.26.2", "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-wqwGnvjJmy5WZeRK3nO+o0P95brdIfBbCFzIlJeRoXOP4CgYPaDBZNFZY+W5Zx6Zvnai8WZ2wjTr+jvd9bzJ2A=="],
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.2", "", { "os": "win32", "cpu": "x64" }, "sha512-6Ee9P26DTb4D8sN9nXxgbi9Dw5vSOfH98M7UlmkjKB2vtUbrRqCbZiNfryGiwnPIpd6YUoTl7rLVD2/x1CyEHQ=="],
"@dicebear/adventurer": ["@dicebear/adventurer@9.2.4", "", { "peerDependencies": { "@dicebear/core": "^9.0.0" } }, "sha512-Xvboay3VH1qe7lH17T+bA3qPawf5EjccssDiyhCX/VT0P21c65JyjTIUJV36Nsv08HKeyDscyP0kgt9nPTRKvA=="],
@@ -314,8 +288,6 @@
"@fullcalendar/multimonth": ["@fullcalendar/multimonth@6.1.19", "", { "dependencies": { "@fullcalendar/daygrid": "~6.1.19" }, "peerDependencies": { "@fullcalendar/core": "~6.1.19" } }, "sha512-YYP8o/tjNLFRKhelwiq5ja3Jm3WDf3bfOUHf32JvAWwfotCvZjD7tYv66Nj02mQ8OWWJINa2EQGJxFHgIs14aA=="],
- "@hexagon/base64": ["@hexagon/base64@1.1.28", "", {}, "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw=="],
-
"@internationalized/date": ["@internationalized/date@3.10.0", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
@@ -330,38 +302,6 @@
"@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="],
- "@levischuck/tiny-cbor": ["@levischuck/tiny-cbor@0.2.11", "", {}, "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow=="],
-
- "@mmailaender/convex-better-auth-svelte": ["@mmailaender/convex-better-auth-svelte@0.2.0", "", { "dependencies": { "is-network-error": "^1.1.0" }, "peerDependencies": { "@convex-dev/better-auth": "^0.9.0", "better-auth": "^1.3.27", "convex": "^1.27.0", "convex-svelte": "^0.0.11", "svelte": "^5.0.0" } }, "sha512-qzahOJg30xErb4ZW+aeszQw4ydhCmKFXn8CeRSA77YxR/dDMgZl+vdWLE4EKsDN0Jd748ecWMnk1fDNNUdgDcg=="],
-
- "@noble/ciphers": ["@noble/ciphers@2.0.1", "", {}, "sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g=="],
-
- "@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
-
- "@peculiar/asn1-android": ["@peculiar/asn1-android@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-t8A83hgghWQkcneRsgGs2ebAlRe54ns88p7ouv8PW2tzF1nAW4yHcL4uZKrFpIU+uszIRzTkcCuie37gpkId0A=="],
-
- "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "@peculiar/asn1-x509-attr": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-p0SjJ3TuuleIvjPM4aYfvYw8Fk1Hn/zAVyPJZTtZ2eE9/MIer6/18ROxX6N/e6edVSfvuZBqhxAj3YgsmSjQ/A=="],
-
- "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-ioigvA6WSYN9h/YssMmmoIwgl3RvZlAYx4A/9jD2qaqXZwGcNlAxaw54eSx2QG1Yu7YyBC5Rku3nNoHrQ16YsQ=="],
-
- "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-t4eYGNhXtLRxaP50h3sfO6aJebUCDGQACoeexcelL4roMFRRVgB20yBIu2LxsPh/tdW9I282gNgMOyg3ywg/mg=="],
-
- "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.5.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.5.0", "@peculiar/asn1-pkcs8": "^2.5.0", "@peculiar/asn1-rsa": "^2.5.0", "@peculiar/asn1-schema": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-Vj0d0wxJZA+Ztqfb7W+/iu8Uasw6hhKtCdLKXLG/P3kEPIQpqGI4P4YXlROfl7gOCqFIbgsj1HzFIFwQ5s20ug=="],
-
- "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-L7599HTI2SLlitlpEP8oAPaJgYssByI4eCwQq2C9eC90otFpm8MRn66PpbKviweAlhinWQ3ZjDD2KIVtx7PaVw=="],
-
- "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.5.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.5.0", "@peculiar/asn1-pfx": "^2.5.0", "@peculiar/asn1-pkcs8": "^2.5.0", "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "@peculiar/asn1-x509-attr": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-UgqSMBLNLR5TzEZ5ZzxR45Nk6VJrammxd60WMSkofyNzd3DQLSNycGWSK5Xg3UTYbXcDFyG8pA/7/y/ztVCa6A=="],
-
- "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-qMZ/vweiTHy9syrkkqWFvbT3eLoedvamcUdnnvwyyUNv5FgFXA3KP8td+ATibnlZ0EANW5PYRm8E6MJzEB/72Q=="],
-
- "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.5.0", "", { "dependencies": { "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-YM/nFfskFJSlHqv59ed6dZlLZqtZQwjRVJ4bBAiWV08Oc+1rSd5lDZcBEx0lGDHfSoH3UziI2pXt2UM33KerPQ=="],
-
- "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-CpwtMCTJvfvYTFMuiME5IH+8qmDe3yEWzKHe7OOADbGfq7ohxeLaXwQo0q4du3qs0AII3UbLCvb9NF/6q0oTKQ=="],
-
- "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-9f0hPOxiJDoG/bfNLAFven+Bd4gwz/VzrCIIWc1025LEI4BXO0U5fOCTNDPbbp2ll+UzqKsZ3g61mpBp74gk9A=="],
-
- "@peculiar/x509": ["@peculiar/x509@1.14.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.5.0", "@peculiar/asn1-csr": "^2.5.0", "@peculiar/asn1-ecc": "^2.5.0", "@peculiar/asn1-pkcs9": "^2.5.0", "@peculiar/asn1-rsa": "^2.5.0", "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", "tslib": "^2.8.1", "tsyringe": "^4.10.0" } }, "sha512-Yc4PDxN3OrxUPiXgU63c+ZRXKGE8YKF2McTciYhUHFtHVB0KMnjeFSU0qpztGhsp4P0uKix4+J2xEpIEDu8oXg=="],
-
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.5", "", { "os": "android", "cpu": "arm" }, "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ=="],
@@ -408,63 +348,57 @@
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg=="],
- "@sgse-app/auth": ["@sgse-app/auth@workspace:packages/auth"],
-
"@sgse-app/backend": ["@sgse-app/backend@workspace:packages/backend"],
- "@simplewebauthn/browser": ["@simplewebauthn/browser@13.2.2", "", {}, "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA=="],
+ "@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
- "@simplewebauthn/server": ["@simplewebauthn/server@13.2.2", "", { "dependencies": { "@hexagon/base64": "^1.1.27", "@levischuck/tiny-cbor": "^0.2.2", "@peculiar/asn1-android": "^2.3.10", "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-rsa": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", "@peculiar/asn1-x509": "^2.3.8", "@peculiar/x509": "^1.13.0" } }, "sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA=="],
+ "@smithy/config-resolver": ["@smithy/config-resolver@4.4.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-BciDJ5hkyYEGBBKMbjGB1A/Zq8bYZ41Zo9BMnGdKF6QD1fY4zIkYx6zui/0CHaVGnv6h0iy8y4rnPX9CPCAPyQ=="],
- "@smithy/abort-controller": ["@smithy/abort-controller@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-xWL9Mf8b7tIFuAlpjKtRPnHrR8XVrwTj5NPYO/QwZPtc0SDLsPxb56V5tzi5yspSMytISHybifez+4jlrx0vkQ=="],
+ "@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
- "@smithy/config-resolver": ["@smithy/config-resolver@4.4.0", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/types": "^4.8.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.3", "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" } }, "sha512-Kkmz3Mup2PGp/HNJxhCWkLNdlajJORLSjwkcfrj0E7nu6STAEdcMR1ir5P9/xOmncx8xXfru0fbUYLlZog/cFg=="],
+ "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw=="],
- "@smithy/core": ["@smithy/core@3.17.1", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.3", "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.3", "@smithy/util-stream": "^4.5.4", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-V4Qc2CIb5McABYfaGiIYLTmo/vwNIK7WXI5aGveBd9UcdhbOMwcvIMxIw/DJj1S9QgOMa/7FBkarMdIC0EOTEQ=="],
+ "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
- "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/property-provider": "^4.2.3", "@smithy/types": "^4.8.0", "@smithy/url-parser": "^4.2.3", "tslib": "^2.6.2" } }, "sha512-hA1MQ/WAHly4SYltJKitEsIDVsNmXcQfYBRv2e+q04fnqtAX5qXaybxy/fhUeAMCnQIdAjaGDb04fMHQefWRhw=="],
+ "@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
- "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.3", "@smithy/querystring-builder": "^4.2.3", "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-bwigPylvivpRLCm+YK9I5wRIYjFESSVwl8JQ1vVx/XhCw0PtCi558NwTnT2DaVCl5pYlImGuQTSwMsZ+pIavRw=="],
-
- "@smithy/hash-node": ["@smithy/hash-node@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6+NOdZDbfuU6s1ISp3UOk5Rg953RJ2aBLNLLBEcamLjHAg1Po9Ha7QIB5ZWhdRUVuOUrT8BVFR+O2KIPmw027g=="],
-
- "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-Cc9W5DwDuebXEDMpOpl4iERo8I0KFjTnomK2RMdhhR87GwrSmUmwMxS4P5JdRf+LsjOdIqumcerwRgYMr/tZ9Q=="],
+ "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.3", "", { "dependencies": { "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-/atXLsT88GwKtfp5Jr0Ks1CSa4+lB+IgRnkNrrYP0h1wL4swHNb0YONEvTceNKNdZGJsye+W2HH8W7olbcPUeA=="],
+ "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
- "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.5", "", { "dependencies": { "@smithy/core": "^3.17.1", "@smithy/middleware-serde": "^4.2.3", "@smithy/node-config-provider": "^4.3.3", "@smithy/shared-ini-file-loader": "^4.3.3", "@smithy/types": "^4.8.0", "@smithy/url-parser": "^4.2.3", "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" } }, "sha512-SIzKVTvEudFWJbxAaq7f2GvP3jh2FHDpIFI6/VAf4FOWGFZy0vnYMPSRj8PGYI8Hjt29mvmwSRgKuO3bK4ixDw=="],
+ "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
- "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/protocol-http": "^5.3.3", "@smithy/service-error-classification": "^4.2.3", "@smithy/smithy-client": "^4.9.1", "@smithy/types": "^4.8.0", "@smithy/util-middleware": "^4.2.3", "@smithy/util-retry": "^4.2.3", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-DCaXbQqcZ4tONMvvdz+zccDE21sLcbwWoNqzPLFlZaxt1lDtOE2tlVpRSwcTOJrjJSUThdgEYn7HrX5oLGlK9A=="],
+ "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
- "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.3", "", { "dependencies": { "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-8g4NuUINpYccxiCXM5s1/V+uLtts8NcX4+sPEbvYQDZk4XoJfDpq5y2FQxfmUL89syoldpzNzA0R9nhzdtdKnQ=="],
+ "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
- "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-iGuOJkH71faPNgOj/gWuEGS6xvQashpLwWB1HjHq1lNNiVfbiJLpZVbhddPuDbx9l4Cgl0vPLq5ltRfSaHfspA=="],
+ "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
- "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.3", "", { "dependencies": { "@smithy/property-provider": "^4.2.3", "@smithy/shared-ini-file-loader": "^4.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-NzI1eBpBSViOav8NVy1fqOlSfkLgkUjUTlohUSgAEhHaFWA3XJiLditvavIP7OpvTjDp5u2LhtlBhkBlEisMwA=="],
+ "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
- "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.3", "", { "dependencies": { "@smithy/abort-controller": "^4.2.3", "@smithy/protocol-http": "^5.3.3", "@smithy/querystring-builder": "^4.2.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-MAwltrDB0lZB/H6/2M5PIsISSwdI5yIh6DaBB9r0Flo9nx3y0dzl/qTMJPd7tJvPdsx6Ks/cwVzheGNYzXyNbQ=="],
+ "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
- "@smithy/property-provider": ["@smithy/property-provider@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-+1EZ+Y+njiefCohjlhyOcy1UNYjT+1PwGFHCxA/gYctjg3DQWAU19WigOXAco/Ql8hZokNehpzLd0/+3uCreqQ=="],
+ "@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
- "@smithy/protocol-http": ["@smithy/protocol-http@5.3.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-Mn7f/1aN2/jecywDcRDvWWWJF4uwg/A0XjFMJtj72DsgHTByfjRltSqcT9NyE9RTdBSN6X1RSXrhn/YWQl8xlw=="],
+ "@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
- "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-LOVCGCmwMahYUM/P0YnU/AlDQFjcu+gWbFJooC417QRB/lDJlWSn8qmPSDp+s4YVAHOgtgbNG4sR+SxF/VOcJQ=="],
+ "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
- "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-cYlSNHcTAX/wc1rpblli3aUlLMGgKZ/Oqn8hhjFASXMCXjIqeuQBei0cnq2JR8t4RtU9FpG6uyl6PxyArTiwKA=="],
+ "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
- "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0" } }, "sha512-NkxsAxFWwsPsQiwFG2MzJ/T7uIR6AQNh1SzcxSUnmmIqIQMlLRQDKhc17M7IYjiuBXhrQRjQTo3CxX+DobS93g=="],
+ "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
- "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-9f9Ixej0hFhroOK2TxZfUUDR13WVa8tQzhSzPDgXe5jGL3KmaM9s8XN7RQwqtEypI82q9KHnKS71CJ+q/1xLtQ=="],
+ "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
- "@smithy/signature-v4": ["@smithy/signature-v4@5.3.3", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.3", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-CmSlUy+eEYbIEYN5N3vvQTRfqt0lJlQkaQUIf+oizu7BbDut0pozfDjBGecfcfWf7c62Yis4JIEgqQ/TCfodaA=="],
+ "@smithy/signature-v4": ["@smithy/signature-v4@5.3.4", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ScDCpasxH7w1HXHYbtk3jcivjvdA1VICyAdgvVqKhKKwxi+MTwZEqFw0minE+oZ7F07oF25xh4FGJxgqgShz0A=="],
- "@smithy/smithy-client": ["@smithy/smithy-client@4.9.1", "", { "dependencies": { "@smithy/core": "^3.17.1", "@smithy/middleware-endpoint": "^4.3.5", "@smithy/middleware-stack": "^4.2.3", "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "@smithy/util-stream": "^4.5.4", "tslib": "^2.6.2" } }, "sha512-Ngb95ryR5A9xqvQFT5mAmYkCwbXvoLavLFwmi7zVg/IowFPCfiqRfkOKnbc/ZRL8ZKJ4f+Tp6kSu6wjDQb8L/g=="],
+ "@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
- "@smithy/types": ["@smithy/types@4.8.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QpELEHLO8SsQVtqP+MkEgCYTFW0pleGozfs3cZ183ZBj9z3VC1CX1/wtFMK64p+5bhtZo41SeLK1rBRtd25nHQ=="],
+ "@smithy/types": ["@smithy/types@4.8.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-N0Zn0OT1zc+NA+UVfkYqQzviRh5ucWwO7mBV3TmHHprMnfcJNfhlPicDkBHi0ewbh+y3evR6cNAW0Raxvb01NA=="],
- "@smithy/url-parser": ["@smithy/url-parser@4.2.3", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-I066AigYvY3d9VlU3zG9XzZg1yT10aNqvCaBTw9EPgu5GrsEl1aUkcMvhkIXascYH1A8W0LQo3B1Kr1cJNcQEw=="],
+ "@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
"@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
@@ -476,19 +410,19 @@
"@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
- "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.3", "@smithy/smithy-client": "^4.9.1", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-qI5PJSW52rnutos8Bln8nwQZRpyoSRN6k2ajyoUHNMUzmWqHnOJCnDELJuV6m5PML0VkHI+XcXzdB+6awiqYUw=="],
+ "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
- "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.6", "", { "dependencies": { "@smithy/config-resolver": "^4.4.0", "@smithy/credential-provider-imds": "^4.2.3", "@smithy/node-config-provider": "^4.3.3", "@smithy/property-provider": "^4.2.3", "@smithy/smithy-client": "^4.9.1", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-c6M/ceBTm31YdcFpgfgQAJaw3KbaLuRKnAz91iMWFLSrgxRpYm03c3bu5cpYojNMfkV9arCUelelKA7XQT36SQ=="],
+ "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.7", "", { "dependencies": { "@smithy/config-resolver": "^4.4.1", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-6hinjVqec0WYGsqN7h9hL/ywfULmJJNXGXnNZW7jrIn/cFuC/aVlVaiDfBIJEvKcOrmN8/EgsW69eY0gXABeHw=="],
- "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-aCfxUOVv0CzBIkU10TubdgKSx5uRvzH064kaiPEWfNIvKOtNpu642P4FP1hgOFkjQIkDObrfIDnKMKkeyrejvQ=="],
+ "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
"@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
- "@smithy/util-middleware": ["@smithy/util-middleware@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-v5ObKlSe8PWUHCqEiX2fy1gNv6goiw6E5I/PN2aXg3Fb/hse0xeaAnSpXDiWl7x6LamVKq7senB+m5LOYHUAHw=="],
+ "@smithy/util-middleware": ["@smithy/util-middleware@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-fKGQAPAn8sgV0plRikRVo6g6aR0KyKvgzNrPuM74RZKy/wWVzx3BMk+ZWEueyN3L5v5EDg+P582mKU+sH5OAsg=="],
- "@smithy/util-retry": ["@smithy/util-retry@4.2.3", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-lLPWnakjC0q9z+OtiXk+9RPQiYPNAovt2IXD3CP4LkOnd9NpUsxOjMx1SnoUVB7Orb7fZp67cQMtTBKMFDvOGg=="],
+ "@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
- "@smithy/util-stream": ["@smithy/util-stream@4.5.4", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.4", "@smithy/node-http-handler": "^4.4.3", "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-+qDxSkiErejw1BAIXUFBSfM5xh3arbz1MmxlbMCKanDDZtVEQ7PSKW9FQS0Vud1eI/kYn0oCTVKyNzRlq+9MUw=="],
+ "@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
"@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
@@ -502,7 +436,7 @@
"@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@6.1.1", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-cBNt4jgH4KuaNO5gRSB2CZKkGtz+OCZ8lPjRQGjhvVUD4akotnj2weUia6imLl2v07K3IgsQRyM36909miSwoQ=="],
- "@sveltejs/kit": ["@sveltejs/kit@2.48.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.3.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-CuwgzfHyc8OGI0HNa7ISQHN8u8XyLGM4jeP8+PYig2B15DD9H39KvwQJiUbGU44VsLx3NfwH4OXavIjvp7/6Ww=="],
+ "@sveltejs/kit": ["@sveltejs/kit@2.48.3", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.3.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-jf8mx3yctRXE9hvixgcqqK94YI2hDnbxI/12Upkz99XFMvxnJKCMzvz0j7lmbXSyBSNEycWO5xHvi7b73y9qkQ=="],
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "debug": "^4.4.1", "deepmerge": "^4.3.1", "magic-string": "^0.30.17", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ=="],
@@ -532,7 +466,7 @@
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.16", "", { "os": "linux", "cpu": "x64" }, "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw=="],
- "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.16", "", { "cpu": "none" }, "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q=="],
+ "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.16", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A=="],
@@ -540,7 +474,7 @@
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.16", "", { "dependencies": { "@tailwindcss/node": "4.1.16", "@tailwindcss/oxide": "4.1.16", "tailwindcss": "4.1.16" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg=="],
- "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.3.3", "", {}, "sha512-RfV+OPV/M3CGryYqTue684u10jUt55PEqeBOnOtCe6tAmHI9Iqyc8nHeDhWPEV9715gShuauFVaMc9RiUVNdwg=="],
+ "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.3.4", "", {}, "sha512-eq+PpuutUyubXu+ycC1GIiVwBs86NF/8yYJJAKSpPcJLWl6R/761F1H4F/9ziX6zKezltFUH1ah3Cz8Ah+KJrw=="],
"@tanstack/form-core": ["@tanstack/form-core@1.24.4", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.3.3", "@tanstack/pacer": "^0.15.3", "@tanstack/store": "^0.7.7" } }, "sha512-+eIR7DiDamit1zvTVgaHxuIRA02YFgJaXMUGxsLRJoBpUjGl/g/nhUocQoNkRyfXqOlh8OCMTanjwDprWSRq6w=="],
@@ -558,7 +492,7 @@
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
- "@types/node": ["@types/node@24.9.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg=="],
+ "@types/node": ["@types/node@24.9.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA=="],
"@types/nodemailer": ["@types/nodemailer@7.0.3", "", { "dependencies": { "@aws-sdk/client-sesv2": "^3.839.0", "@types/node": "*" } }, "sha512-fC8w49YQ868IuPWRXqPfLf+MuTRex5Z1qxMoG8rr70riqqbOp2F5xgOKE9fODEBPzpnvjkJXFgK6IL2xgMSTnA=="],
@@ -570,27 +504,21 @@
"@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
- "acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
+ "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
- "asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="],
-
- "autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": "bin/autoprefixer" }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="],
+ "autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
"base64-arraybuffer": ["base64-arraybuffer@1.0.2", "", {}, "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="],
- "baseline-browser-mapping": ["baseline-browser-mapping@2.8.20", "", { "bin": "dist/cli.js" }, "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ=="],
-
- "better-auth": ["better-auth@1.3.27", "", { "dependencies": { "@better-auth/core": "1.3.27", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18", "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/server": "^13.1.2", "better-call": "1.0.19", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1", "zod": "^4.1.5" } }, "sha512-SwiGAJ7yU6dBhNg0NdV1h5M8T5sa7/AszZVc4vBfMDrLLmvUfbt9JoJ0uRUJUEdKRAAxTyl9yA+F3+GhtAD80w=="],
-
- "better-call": ["better-call@1.0.19", "", { "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-sI3GcA1SCVa3H+CDHl8W8qzhlrckwXOTKhqq3OOPXjgn5aTOMIqGY34zLY/pHA6tRRMjTUC3lz5Mi7EbDA24Kw=="],
+ "baseline-browser-mapping": ["baseline-browser-mapping@2.8.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q=="],
"bowser": ["bowser@2.12.1", "", {}, "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw=="],
- "browserslist": ["browserslist@4.27.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", "electron-to-chromium": "^1.5.238", "node-releases": "^2.0.26", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw=="],
+ "browserslist": ["browserslist@4.27.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", "electron-to-chromium": "^1.5.238", "node-releases": "^2.0.26", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw=="],
"caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="],
@@ -602,15 +530,11 @@
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
- "common-tags": ["common-tags@1.8.2", "", {}, "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA=="],
-
- "convex": ["convex@1.28.0", "", { "dependencies": { "esbuild": "0.25.4", "prettier": "^3.0.0" }, "peerDependencies": { "@auth0/auth0-react": "^2.0.1", "@clerk/clerk-react": "^4.12.8 || ^5.0.0", "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" }, "optionalPeers": ["@auth0/auth0-react", "@clerk/clerk-react"], "bin": "bin/main.js" }, "sha512-40FgeJ/LxP9TxnkDDztU/A5gcGTdq1klcTT5mM0Ak+kSlQiDktMpjNX1TfkWLxXaE3lI4qvawKH95v2RiYgFxA=="],
-
- "convex-helpers": ["convex-helpers@0.1.104", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "convex": "^1.24.0", "hono": "^4.0.5", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "typescript": "^5.5", "zod": "^3.22.4 || ^4.0.15" }, "optionalPeers": ["hono"], "bin": "bin.cjs" }, "sha512-7CYvx7T3K6n+McDTK4ZQaQNNGBzq5aWezpjzsKbOxPXx7oNcTP9wrpef3JxeXWFzkByJv5hRCjseh9B7eNJ7Ig=="],
+ "convex": ["convex@1.28.0", "", { "dependencies": { "esbuild": "0.25.4", "prettier": "^3.0.0" }, "peerDependencies": { "@auth0/auth0-react": "^2.0.1", "@clerk/clerk-react": "^4.12.8 || ^5.0.0", "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" }, "optionalPeers": ["@auth0/auth0-react", "@clerk/clerk-react", "react"], "bin": { "convex": "bin/main.js" } }, "sha512-40FgeJ/LxP9TxnkDDztU/A5gcGTdq1klcTT5mM0Ak+kSlQiDktMpjNX1TfkWLxXaE3lI4qvawKH95v2RiYgFxA=="],
"convex-svelte": ["convex-svelte@0.0.11", "", { "peerDependencies": { "convex": "^1.10.0", "svelte": "^5.0.0" } }, "sha512-N/29gg5Zqy72vKL4xHSLk3jGwXVKIWXPs6xzq6KxGL84y/D6hG85pG2CPOzn08EzMmByts5FTkJ5p3var6yDng=="],
- "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
+ "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"core-js": ["core-js@3.46.0", "", {}, "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA=="],
@@ -624,33 +548,31 @@
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
- "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
-
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"devalue": ["devalue@5.4.2", "", {}, "sha512-MwPZTKEPK2k8Qgfmqrd48ZKVvzSQjgW0lXLxiIBA8dQjtf/6mw6pggHNLcyDKyf+fI6eXxlQwPsfaCMTU5U+Bw=="],
"dompurify": ["dompurify@3.3.0", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ=="],
- "electron-to-chromium": ["electron-to-chromium@1.5.241", "", {}, "sha512-ILMvKX/ZV5WIJzzdtuHg8xquk2y0BOGlFOxBVwTpbiXqWIH0hamG45ddU4R3PQ0gYu+xgo0vdHXHli9sHIGb4w=="],
+ "electron-to-chromium": ["electron-to-chromium@1.5.243", "", {}, "sha512-ZCphxFW3Q1TVhcgS9blfut1PX8lusVi2SvXQgmEEnK4TCmE1JhH2JkjJN+DNt0pJJwfBri5AROBnz2b/C+YU9g=="],
"emoji-picker-element": ["emoji-picker-element@1.27.0", "", {}, "sha512-CeN9g5/kq41+BfYPDpAbE2ejZRHbs1faFDmU9+E9wGA4JWLkok9zo1hwcAFnUhV4lPR3ZuLHiJxNG1mpjoF4TQ=="],
"enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
- "esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": "bin/esbuild" }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="],
+ "esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
- "esrap": ["esrap@2.1.1", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-ebTT9B6lOtZGMgJ3o5r12wBacHctG7oEWazIda8UlPfA3HD/Wrv8FdXoVo73vzdpwCxNyXjPauyN2bbJzMkB9A=="],
+ "esrap": ["esrap@2.1.2", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-DgvlIQeowRNyvLPWW4PT7Gu13WznY288Du086E751mwwbsgr29ytBiYeLzAGIo0qk3Ujob0SDk8TiSaM5WQzNg=="],
"fast-png": ["fast-png@6.4.0", "", { "dependencies": { "@types/pako": "^2.0.3", "iobuffer": "^5.3.2", "pako": "^2.1.0" } }, "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q=="],
"fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
- "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
+ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
@@ -664,13 +586,9 @@
"iobuffer": ["iobuffer@5.4.0", "", {}, "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA=="],
- "is-network-error": ["is-network-error@1.3.0", "", {}, "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw=="],
-
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
- "jiti": ["jiti@2.6.1", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
-
- "jose": ["jose@6.1.0", "", {}, "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA=="],
+ "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"jspdf": ["jspdf@3.0.3", "", { "dependencies": { "@babel/runtime": "^7.26.9", "fast-png": "^6.2.0", "fflate": "^0.8.1" }, "optionalDependencies": { "canvg": "^3.0.11", "core-js": "^3.6.0", "dompurify": "^3.2.4", "html2canvas": "^1.0.0-rc.5" } }, "sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ=="],
@@ -678,8 +596,6 @@
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
- "kysely": ["kysely@0.28.8", "", {}, "sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA=="],
-
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
@@ -706,7 +622,7 @@
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
- "lucide-svelte": ["lucide-svelte@0.546.0", "", { "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "sha512-vCvBUlFapD59ivX1b/i7wdUadSgC/3gQGvrGEZjSecOlThT+UR+X5UxdVEakHuhniTrSX0nJ2WrY5r25SVDtyQ=="],
+ "lucide-svelte": ["lucide-svelte@0.548.0", "", { "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "sha512-aW2BfHWBLWf/XPSKytTPV16AWfFeFIJeUyOg7eHY2rhzVQ0u0LIvoS4pm2oskr+OJVw+NsS8fPvlBVqPfUO1XQ=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
@@ -716,11 +632,9 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
- "nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
+ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
- "nanostores": ["nanostores@1.0.1", "", {}, "sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw=="],
-
- "node-releases": ["node-releases@2.0.26", "", {}, "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA=="],
+ "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
"nodemailer": ["nodemailer@7.0.10", "", {}, "sha512-Us/Se1WtT0ylXgNFfyFSx4LElllVLJXQjWi2Xz17xWw7amDKO2MLtFnVp1WACy7GkVGs+oBlRopVNUzlrGSw1w=="],
@@ -742,40 +656,22 @@
"preact": ["preact@10.12.1", "", {}, "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg=="],
- "prettier": ["prettier@3.6.2", "", { "bin": "bin/prettier.cjs" }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
-
- "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="],
-
- "pvutils": ["pvutils@1.1.5", "", {}, "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA=="],
+ "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"raf": ["raf@3.4.1", "", { "dependencies": { "performance-now": "^2.1.0" } }, "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA=="],
- "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
-
- "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
-
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
- "reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="],
-
"regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="],
- "remeda": ["remeda@2.32.0", "", { "dependencies": { "type-fest": "^4.41.0" } }, "sha512-BZx9DsT4FAgXDTOdgJIc5eY6ECIXMwtlSPQoPglF20ycSWigttDDe88AozEsPPT4OWk5NujroGSBC1phw5uU+w=="],
-
"rgbcolor": ["rgbcolor@1.0.1", "", {}, "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw=="],
- "rollup": ["rollup@4.52.5", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.5", "@rollup/rollup-android-arm64": "4.52.5", "@rollup/rollup-darwin-arm64": "4.52.5", "@rollup/rollup-darwin-x64": "4.52.5", "@rollup/rollup-freebsd-arm64": "4.52.5", "@rollup/rollup-freebsd-x64": "4.52.5", "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", "@rollup/rollup-linux-arm-musleabihf": "4.52.5", "@rollup/rollup-linux-arm64-gnu": "4.52.5", "@rollup/rollup-linux-arm64-musl": "4.52.5", "@rollup/rollup-linux-loong64-gnu": "4.52.5", "@rollup/rollup-linux-ppc64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-musl": "4.52.5", "@rollup/rollup-linux-s390x-gnu": "4.52.5", "@rollup/rollup-linux-x64-gnu": "4.52.5", "@rollup/rollup-linux-x64-musl": "4.52.5", "@rollup/rollup-openharmony-arm64": "4.52.5", "@rollup/rollup-win32-arm64-msvc": "4.52.5", "@rollup/rollup-win32-ia32-msvc": "4.52.5", "@rollup/rollup-win32-x64-gnu": "4.52.5", "@rollup/rollup-win32-x64-msvc": "4.52.5", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw=="],
-
- "rou3": ["rou3@0.5.1", "", {}, "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ=="],
+ "rollup": ["rollup@4.52.5", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.5", "@rollup/rollup-android-arm64": "4.52.5", "@rollup/rollup-darwin-arm64": "4.52.5", "@rollup/rollup-darwin-x64": "4.52.5", "@rollup/rollup-freebsd-arm64": "4.52.5", "@rollup/rollup-freebsd-x64": "4.52.5", "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", "@rollup/rollup-linux-arm-musleabihf": "4.52.5", "@rollup/rollup-linux-arm64-gnu": "4.52.5", "@rollup/rollup-linux-arm64-musl": "4.52.5", "@rollup/rollup-linux-loong64-gnu": "4.52.5", "@rollup/rollup-linux-ppc64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-musl": "4.52.5", "@rollup/rollup-linux-s390x-gnu": "4.52.5", "@rollup/rollup-linux-x64-gnu": "4.52.5", "@rollup/rollup-linux-x64-musl": "4.52.5", "@rollup/rollup-openharmony-arm64": "4.52.5", "@rollup/rollup-win32-arm64-msvc": "4.52.5", "@rollup/rollup-win32-ia32-msvc": "4.52.5", "@rollup/rollup-win32-x64-gnu": "4.52.5", "@rollup/rollup-win32-x64-msvc": "4.52.5", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw=="],
"runed": ["runed@0.28.0", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ=="],
"sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
- "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
-
- "semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
-
"set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
"sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="],
@@ -786,11 +682,11 @@
"strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
- "svelte": ["svelte@5.42.3", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-+8dUmdJGvKSWEfbAgIaUmpD97s1bBAGxEf6s7wQonk+HNdMmrBZtpStzRypRqrYBFUmmhaUgBHUjraE8gLqWAw=="],
+ "svelte": ["svelte@5.43.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-ro1umEzX8rT5JpCmlf0PPv7ncD8MdVob9e18bhwqTKNoLjS8kDvhVpaoYVPc+qMwDAOfcwJtyY7ZFSDbOaNPgA=="],
"svelte-chartjs": ["svelte-chartjs@3.1.5", "", { "peerDependencies": { "chart.js": "^3.5.0 || ^4.0.0", "svelte": "^4.0.0" } }, "sha512-ka2zh7v5FiwfAX1oMflZ0HkNkgjHjFqANgRyC+vNYXfxtx2ku68Zo+2KgbKeBH2nS1ThDqkIACPzGxy4T0UaoA=="],
- "svelte-check": ["svelte-check@4.3.3", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": "bin/svelte-check" }, "sha512-RYP0bEwenDXzfv0P1sKAwjZSlaRyqBn0Fz1TVni58lqyEiqgwztTpmodJrGzP6ZT2aHl4MbTvWP6gbmQ3FOnBg=="],
+ "svelte-check": ["svelte-check@4.3.3", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-RYP0bEwenDXzfv0P1sKAwjZSlaRyqBn0Fz1TVni58lqyEiqgwztTpmodJrGzP6ZT2aHl4MbTvWP6gbmQ3FOnBg=="],
"svelte-sonner": ["svelte-sonner@1.0.5", "", { "dependencies": { "runed": "^0.28.0" }, "peerDependencies": { "svelte": "^5.0.0" } }, "sha512-9dpGPFqKb/QWudYqGnEz93vuY+NgCEvyNvxoCLMVGw6sDN/3oVeKV1xiEirW2E1N3vJEyj5imSBNOGltQHA7mg=="],
@@ -808,9 +704,7 @@
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
- "tsyringe": ["tsyringe@4.10.0", "", { "dependencies": { "tslib": "^1.9.3" } }, "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw=="],
-
- "turbo": ["turbo@2.5.8", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.8", "turbo-darwin-arm64": "2.5.8", "turbo-linux-64": "2.5.8", "turbo-linux-arm64": "2.5.8", "turbo-windows-64": "2.5.8", "turbo-windows-arm64": "2.5.8" }, "bin": "bin/turbo" }, "sha512-5c9Fdsr9qfpT3hA0EyYSFRZj1dVVsb6KIWubA9JBYZ/9ZEAijgUEae0BBR/Xl/wekt4w65/lYLTFaP3JmwSO8w=="],
+ "turbo": ["turbo@2.5.8", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.8", "turbo-darwin-arm64": "2.5.8", "turbo-linux-64": "2.5.8", "turbo-linux-arm64": "2.5.8", "turbo-windows-64": "2.5.8", "turbo-windows-arm64": "2.5.8" }, "bin": { "turbo": "bin/turbo" } }, "sha512-5c9Fdsr9qfpT3hA0EyYSFRZj1dVVsb6KIWubA9JBYZ/9ZEAijgUEae0BBR/Xl/wekt4w65/lYLTFaP3JmwSO8w=="],
"turbo-darwin-64": ["turbo-darwin-64@2.5.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ=="],
@@ -824,21 +718,17 @@
"turbo-windows-arm64": ["turbo-windows-arm64@2.5.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-eFC5XzLmgXJfnAK3UMTmVECCwuBcORrWdewoiXBnUm934DY6QN8YowC/srhNnROMpaKaqNeRpoB5FxCww3eteQ=="],
- "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
-
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
- "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
-
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
- "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+ "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
"utrie": ["utrie@1.0.2", "", { "dependencies": { "base64-arraybuffer": "^1.0.2" } }, "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw=="],
- "vite": ["vite@7.1.12", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": "bin/vite.js" }, "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug=="],
+ "vite": ["vite@7.1.12", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug=="],
- "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" } }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
+ "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
"web": ["web@workspace:apps/web"],
@@ -850,13 +740,23 @@
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
- "@convex-dev/better-auth/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
-
"@sveltejs/kit/@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
- "convex/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": "bin/esbuild" }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
+ "@sveltejs/kit/cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
- "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="],
+
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
+
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
+
+ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="],
+
+ "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
+
+ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+ "convex/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
diff --git a/package.json b/package.json
index af3612c..ab4b2b9 100644
--- a/package.json
+++ b/package.json
@@ -17,14 +17,13 @@
"dev:setup": "turbo -F @sgse-app/backend dev:setup"
},
"devDependencies": {
- "@biomejs/biome": "^2.2.0",
- "fdir": "^6.5.0",
+ "@biomejs/biome": "^2.3.2",
"turbo": "^2.5.4"
},
"dependencies": {
"@tanstack/svelte-form": "^1.23.8",
"chart.js": "^4.5.1",
- "lucide-svelte": "^0.546.0",
+ "lucide-svelte": "^0.548.0",
"svelte-chartjs": "^3.1.5"
},
"optionalDependencies": {
diff --git a/packages/auth/package.json b/packages/auth/package.json
deleted file mode 100644
index 0cc2388..0000000
--- a/packages/auth/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "@sgse-app/auth",
- "version": "1.0.0",
- "scripts": {},
- "author": "",
- "license": "ISC",
- "description": "",
- "devDependencies": {
- "@types/node": "^24.3.0",
- "typescript": "^5.9.2"
- },
- "dependencies": {
- "convex": "^1.28.0",
- "better-auth": "1.3.27"
- }
-}
diff --git a/packages/backend/convex/_generated/api.d.ts b/packages/backend/convex/_generated/api.d.ts
index 3a168f3..efdf934 100644
--- a/packages/backend/convex/_generated/api.d.ts
+++ b/packages/backend/convex/_generated/api.d.ts
@@ -10,11 +10,8 @@
import type * as autenticacao from "../autenticacao.js";
import type * as auth_utils from "../auth/utils.js";
-import type * as auth from "../auth.js";
import type * as betterAuth__generated_api from "../betterAuth/_generated/api.js";
import type * as betterAuth__generated_server from "../betterAuth/_generated/server.js";
-import type * as betterAuth_adapter from "../betterAuth/adapter.js";
-import type * as betterAuth_auth from "../betterAuth/auth.js";
import type * as chat from "../chat.js";
import type * as configuracaoEmail from "../configuracaoEmail.js";
import type * as criarFuncionarioTeste from "../criarFuncionarioTeste.js";
@@ -37,6 +34,7 @@ import type * as migrarParaTimes from "../migrarParaTimes.js";
import type * as migrarUsuariosAdmin from "../migrarUsuariosAdmin.js";
import type * as monitoramento from "../monitoramento.js";
import type * as perfisCustomizados from "../perfisCustomizados.js";
+import type * as permissoesAcoes from "../permissoesAcoes.js";
import type * as roles from "../roles.js";
import type * as saldoFerias from "../saldoFerias.js";
import type * as seed from "../seed.js";
@@ -65,11 +63,8 @@ import type {
declare const fullApi: ApiFromModules<{
autenticacao: typeof autenticacao;
"auth/utils": typeof auth_utils;
- auth: typeof auth;
"betterAuth/_generated/api": typeof betterAuth__generated_api;
"betterAuth/_generated/server": typeof betterAuth__generated_server;
- "betterAuth/adapter": typeof betterAuth_adapter;
- "betterAuth/auth": typeof betterAuth_auth;
chat: typeof chat;
configuracaoEmail: typeof configuracaoEmail;
criarFuncionarioTeste: typeof criarFuncionarioTeste;
@@ -92,6 +87,7 @@ declare const fullApi: ApiFromModules<{
migrarUsuariosAdmin: typeof migrarUsuariosAdmin;
monitoramento: typeof monitoramento;
perfisCustomizados: typeof perfisCustomizados;
+ permissoesAcoes: typeof permissoesAcoes;
roles: typeof roles;
saldoFerias: typeof saldoFerias;
seed: typeof seed;
@@ -114,952 +110,4 @@ export declare const internal: FilterApi<
FunctionReference
>;
-export declare const components: {
- betterAuth: {
- adapter: {
- create: FunctionReference<
- "mutation",
- "internal",
- {
- input:
- | {
- data: {
- createdAt: number;
- email: string;
- emailVerified: boolean;
- image?: null | string;
- name: string;
- updatedAt: number;
- userId?: null | string;
- };
- model: "user";
- }
- | {
- data: {
- createdAt: number;
- expiresAt: number;
- ipAddress?: null | string;
- token: string;
- updatedAt: number;
- userAgent?: null | string;
- userId: string;
- };
- model: "session";
- }
- | {
- data: {
- accessToken?: null | string;
- accessTokenExpiresAt?: null | number;
- accountId: string;
- createdAt: number;
- idToken?: null | string;
- password?: null | string;
- providerId: string;
- refreshToken?: null | string;
- refreshTokenExpiresAt?: null | number;
- scope?: null | string;
- updatedAt: number;
- userId: string;
- };
- model: "account";
- }
- | {
- data: {
- createdAt: number;
- expiresAt: number;
- identifier: string;
- updatedAt: number;
- value: string;
- };
- model: "verification";
- }
- | {
- data: {
- createdAt: number;
- privateKey: string;
- publicKey: string;
- };
- model: "jwks";
- };
- onCreateHandle?: string;
- select?: Array;
- },
- any
- >;
- deleteMany: FunctionReference<
- "mutation",
- "internal",
- {
- input:
- | {
- model: "user";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "name"
- | "email"
- | "emailVerified"
- | "image"
- | "createdAt"
- | "updatedAt"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "session";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "expiresAt"
- | "token"
- | "createdAt"
- | "updatedAt"
- | "ipAddress"
- | "userAgent"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "account";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "accountId"
- | "providerId"
- | "userId"
- | "accessToken"
- | "refreshToken"
- | "idToken"
- | "accessTokenExpiresAt"
- | "refreshTokenExpiresAt"
- | "scope"
- | "password"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "verification";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "identifier"
- | "value"
- | "expiresAt"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "jwks";
- where?: Array<{
- connector?: "AND" | "OR";
- field: "publicKey" | "privateKey" | "createdAt" | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- };
- onDeleteHandle?: string;
- paginationOpts: {
- cursor: string | null;
- endCursor?: string | null;
- id?: number;
- maximumBytesRead?: number;
- maximumRowsRead?: number;
- numItems: number;
- };
- },
- any
- >;
- deleteOne: FunctionReference<
- "mutation",
- "internal",
- {
- input:
- | {
- model: "user";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "name"
- | "email"
- | "emailVerified"
- | "image"
- | "createdAt"
- | "updatedAt"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "session";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "expiresAt"
- | "token"
- | "createdAt"
- | "updatedAt"
- | "ipAddress"
- | "userAgent"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "account";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "accountId"
- | "providerId"
- | "userId"
- | "accessToken"
- | "refreshToken"
- | "idToken"
- | "accessTokenExpiresAt"
- | "refreshTokenExpiresAt"
- | "scope"
- | "password"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "verification";
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "identifier"
- | "value"
- | "expiresAt"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "jwks";
- where?: Array<{
- connector?: "AND" | "OR";
- field: "publicKey" | "privateKey" | "createdAt" | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- };
- onDeleteHandle?: string;
- },
- any
- >;
- findMany: FunctionReference<
- "query",
- "internal",
- {
- limit?: number;
- model: "user" | "session" | "account" | "verification" | "jwks";
- offset?: number;
- paginationOpts: {
- cursor: string | null;
- endCursor?: string | null;
- id?: number;
- maximumBytesRead?: number;
- maximumRowsRead?: number;
- numItems: number;
- };
- sortBy?: { direction: "asc" | "desc"; field: string };
- where?: Array<{
- connector?: "AND" | "OR";
- field: string;
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- },
- any
- >;
- findOne: FunctionReference<
- "query",
- "internal",
- {
- model: "user" | "session" | "account" | "verification" | "jwks";
- select?: Array;
- where?: Array<{
- connector?: "AND" | "OR";
- field: string;
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- },
- any
- >;
- updateMany: FunctionReference<
- "mutation",
- "internal",
- {
- input:
- | {
- model: "user";
- update: {
- createdAt?: number;
- email?: string;
- emailVerified?: boolean;
- image?: null | string;
- name?: string;
- updatedAt?: number;
- userId?: null | string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "name"
- | "email"
- | "emailVerified"
- | "image"
- | "createdAt"
- | "updatedAt"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "session";
- update: {
- createdAt?: number;
- expiresAt?: number;
- ipAddress?: null | string;
- token?: string;
- updatedAt?: number;
- userAgent?: null | string;
- userId?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "expiresAt"
- | "token"
- | "createdAt"
- | "updatedAt"
- | "ipAddress"
- | "userAgent"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "account";
- update: {
- accessToken?: null | string;
- accessTokenExpiresAt?: null | number;
- accountId?: string;
- createdAt?: number;
- idToken?: null | string;
- password?: null | string;
- providerId?: string;
- refreshToken?: null | string;
- refreshTokenExpiresAt?: null | number;
- scope?: null | string;
- updatedAt?: number;
- userId?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "accountId"
- | "providerId"
- | "userId"
- | "accessToken"
- | "refreshToken"
- | "idToken"
- | "accessTokenExpiresAt"
- | "refreshTokenExpiresAt"
- | "scope"
- | "password"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "verification";
- update: {
- createdAt?: number;
- expiresAt?: number;
- identifier?: string;
- updatedAt?: number;
- value?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "identifier"
- | "value"
- | "expiresAt"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "jwks";
- update: {
- createdAt?: number;
- privateKey?: string;
- publicKey?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field: "publicKey" | "privateKey" | "createdAt" | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- };
- onUpdateHandle?: string;
- paginationOpts: {
- cursor: string | null;
- endCursor?: string | null;
- id?: number;
- maximumBytesRead?: number;
- maximumRowsRead?: number;
- numItems: number;
- };
- },
- any
- >;
- updateOne: FunctionReference<
- "mutation",
- "internal",
- {
- input:
- | {
- model: "user";
- update: {
- createdAt?: number;
- email?: string;
- emailVerified?: boolean;
- image?: null | string;
- name?: string;
- updatedAt?: number;
- userId?: null | string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "name"
- | "email"
- | "emailVerified"
- | "image"
- | "createdAt"
- | "updatedAt"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "session";
- update: {
- createdAt?: number;
- expiresAt?: number;
- ipAddress?: null | string;
- token?: string;
- updatedAt?: number;
- userAgent?: null | string;
- userId?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "expiresAt"
- | "token"
- | "createdAt"
- | "updatedAt"
- | "ipAddress"
- | "userAgent"
- | "userId"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "account";
- update: {
- accessToken?: null | string;
- accessTokenExpiresAt?: null | number;
- accountId?: string;
- createdAt?: number;
- idToken?: null | string;
- password?: null | string;
- providerId?: string;
- refreshToken?: null | string;
- refreshTokenExpiresAt?: null | number;
- scope?: null | string;
- updatedAt?: number;
- userId?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "accountId"
- | "providerId"
- | "userId"
- | "accessToken"
- | "refreshToken"
- | "idToken"
- | "accessTokenExpiresAt"
- | "refreshTokenExpiresAt"
- | "scope"
- | "password"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "verification";
- update: {
- createdAt?: number;
- expiresAt?: number;
- identifier?: string;
- updatedAt?: number;
- value?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field:
- | "identifier"
- | "value"
- | "expiresAt"
- | "createdAt"
- | "updatedAt"
- | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- }
- | {
- model: "jwks";
- update: {
- createdAt?: number;
- privateKey?: string;
- publicKey?: string;
- };
- where?: Array<{
- connector?: "AND" | "OR";
- field: "publicKey" | "privateKey" | "createdAt" | "_id";
- operator?:
- | "lt"
- | "lte"
- | "gt"
- | "gte"
- | "eq"
- | "in"
- | "not_in"
- | "ne"
- | "contains"
- | "starts_with"
- | "ends_with";
- value:
- | string
- | number
- | boolean
- | Array
- | Array
- | null;
- }>;
- };
- onUpdateHandle?: string;
- },
- any
- >;
- };
- };
-};
+export declare const components: {};
diff --git a/packages/backend/convex/autenticacao.ts b/packages/backend/convex/autenticacao.ts
index 5ae4621..9a8b2a8 100644
--- a/packages/backend/convex/autenticacao.ts
+++ b/packages/backend/convex/autenticacao.ts
@@ -1,6 +1,12 @@
import { v } from "convex/values";
import { mutation, query } from "./_generated/server";
-import { hashPassword, verifyPassword, generateToken, validarMatricula, validarSenha } from "./auth/utils";
+import {
+ hashPassword,
+ verifyPassword,
+ generateToken,
+ validarMatricula,
+ validarSenha,
+} from "./auth/utils";
import { registrarLogin } from "./logsLogin";
import { Id } from "./_generated/dataModel";
@@ -10,7 +16,7 @@ import { Id } from "./_generated/dataModel";
async function verificarBloqueioUsuario(ctx: any, usuarioId: Id<"usuarios">) {
const bloqueio = await ctx.db
.query("bloqueiosUsuarios")
- .withIndex("by_usuario", (q) => q.eq("usuarioId", usuarioId))
+ .withIndex("by_usuario", (q: any) => q.eq("usuarioId", usuarioId))
.filter((q: any) => q.eq(q.field("ativo"), true))
.first();
@@ -23,7 +29,7 @@ async function verificarBloqueioUsuario(ctx: any, usuarioId: Id<"usuarios">) {
async function verificarRateLimitIP(ctx: any, ipAddress: string) {
// Últimas 15 minutos
const dataLimite = Date.now() - 15 * 60 * 1000;
-
+
const tentativas = await ctx.db
.query("logsLogin")
.withIndex("by_ip", (q: any) => q.eq("ipAddress", ipAddress))
@@ -31,7 +37,7 @@ async function verificarRateLimitIP(ctx: any, ipAddress: string) {
.collect();
const falhas = tentativas.filter((t: any) => !t.sucesso).length;
-
+
// Bloquear se 5 ou mais tentativas falhas em 15 minutos
return falhas >= 5;
}
@@ -102,7 +108,9 @@ export const login = mutation({
} else {
usuario = await ctx.db
.query("usuarios")
- .withIndex("by_matricula", (q) => q.eq("matricula", args.matriculaOuEmail))
+ .withIndex("by_matricula", (q) =>
+ q.eq("matricula", args.matriculaOuEmail)
+ )
.first();
}
@@ -122,7 +130,10 @@ export const login = mutation({
}
// Verificar se usuário está bloqueado
- if (usuario.bloqueado || (await verificarBloqueioUsuario(ctx, usuario._id))) {
+ if (
+ usuario.bloqueado ||
+ (await verificarBloqueioUsuario(ctx, usuario._id))
+ ) {
await registrarLogin(ctx, {
usuarioId: usuario._id,
matriculaOuEmail: args.matriculaOuEmail,
@@ -172,7 +183,9 @@ export const login = mutation({
userAgent: args.userAgent,
});
- const minutosRestantes = Math.ceil((TEMPO_BLOQUEIO - tempoDecorrido) / 60000);
+ const minutosRestantes = Math.ceil(
+ (TEMPO_BLOQUEIO - tempoDecorrido) / 60000
+ );
return {
sucesso: false as const,
erro: `Conta temporariamente bloqueada. Tente novamente em ${minutosRestantes} minutos.`,
@@ -192,8 +205,9 @@ export const login = mutation({
if (!senhaValida) {
// Incrementar tentativas
- const novasTentativas = tempoDecorrido > TEMPO_BLOQUEIO ? 1 : tentativasRecentes + 1;
-
+ const novasTentativas =
+ tempoDecorrido > TEMPO_BLOQUEIO ? 1 : tentativasRecentes + 1;
+
await ctx.db.patch(usuario._id, {
tentativasLogin: novasTentativas,
ultimaTentativaLogin: Date.now(),
@@ -367,7 +381,10 @@ export const verificarSessao = query({
.first();
if (!sessao || !sessao.ativo) {
- return { valido: false as const, motivo: "Sessão não encontrada ou inativa" };
+ return {
+ valido: false as const,
+ motivo: "Sessão não encontrada ou inativa",
+ };
}
// Verificar se sessão expirou
@@ -380,7 +397,10 @@ export const verificarSessao = query({
// Buscar usuário
const usuario = await ctx.db.get(sessao.usuarioId);
if (!usuario || !usuario.ativo) {
- return { valido: false as const, motivo: "Usuário não encontrado ou inativo" };
+ return {
+ valido: false as const,
+ motivo: "Usuário não encontrado ou inativo",
+ };
}
// Buscar role
@@ -428,7 +448,7 @@ export const limparSessoesExpiradas = mutation({
for (const sessao of sessoes) {
if (sessao.expiraEm < agora) {
await ctx.db.patch(sessao._id, { ativo: false });
-
+
await ctx.db.insert("logsAcesso", {
usuarioId: sessao.usuarioId,
tipo: "sessao_expirada",
@@ -511,4 +531,3 @@ export const alterarSenha = mutation({
return { sucesso: true as const };
},
});
-
diff --git a/packages/backend/convex/auth.ts b/packages/backend/convex/auth.ts
deleted file mode 100644
index f4be2ec..0000000
--- a/packages/backend/convex/auth.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { createClient, type GenericCtx } from "@convex-dev/better-auth";
-import { convex } from "@convex-dev/better-auth/plugins";
-import { components } from "./_generated/api";
-import { type DataModel } from "./_generated/dataModel";
-import { query } from "./_generated/server";
-import { betterAuth } from "better-auth";
-import schema from "./betterAuth/schema";
-
-// Configurações de ambiente para produção
-const siteUrl = process.env.SITE_URL || process.env.CONVEX_SITE_URL || "http://localhost:5173";
-const authSecret = process.env.BETTER_AUTH_SECRET;
-
-// The component client has methods needed for integrating Convex with Better Auth,
-// as well as helper methods for general use.
-export const authComponent = createClient(components.betterAuth, {
- local: {
- schema: schema as any,
- },
-});
-
-export const createAuth = (
- ctx: GenericCtx,
- { optionsOnly } = { optionsOnly: false }
-) => {
- return betterAuth({
- // Secret para criptografia de tokens - OBRIGATÓRIO em produção
- secret: authSecret,
- // disable logging when createAuth is called just to generate options.
- // this is not required, but there's a lot of noise in logs without it.
- logger: {
- disabled: optionsOnly,
- },
- baseURL: siteUrl,
- database: authComponent.adapter(ctx),
- // Configure simple, non-verified email/password to get started
- emailAndPassword: {
- enabled: true,
- requireEmailVerification: false,
- },
- plugins: [
- // The Convex plugin is required for Convex compatibility
- convex(),
- ],
- });
-};
-
-// Example function for getting the current user
-// Feel free to edit, omit, etc.
-export const getCurrentUser = query({
- args: {},
- handler: async (ctx) => {
- return authComponent.getAuthUser(ctx as any);
- },
-});
diff --git a/packages/backend/convex/betterAuth/adapter.ts b/packages/backend/convex/betterAuth/adapter.ts
deleted file mode 100644
index 0741d37..0000000
--- a/packages/backend/convex/betterAuth/adapter.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { createApi } from "@convex-dev/better-auth";
-import schema from "./schema";
-import { createAuth } from "../auth";
-
-export const {
- create,
- findOne,
- findMany,
- updateOne,
- updateMany,
- deleteOne,
- deleteMany,
-} = createApi(schema, createAuth);
diff --git a/packages/backend/convex/betterAuth/auth.ts b/packages/backend/convex/betterAuth/auth.ts
deleted file mode 100644
index be7e455..0000000
--- a/packages/backend/convex/betterAuth/auth.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { createAuth } from "../auth";
-import { getStaticAuth } from "@convex-dev/better-auth";
-
-// Export a static instance for Better Auth schema generation
-export const auth = getStaticAuth(createAuth);
diff --git a/packages/backend/convex/betterAuth/convex.config.ts b/packages/backend/convex/betterAuth/convex.config.ts
deleted file mode 100644
index fe8c88e..0000000
--- a/packages/backend/convex/betterAuth/convex.config.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { defineComponent } from "convex/server";
-
-const component = defineComponent("betterAuth");
-
-export default component;
diff --git a/packages/backend/convex/betterAuth/schema.ts b/packages/backend/convex/betterAuth/schema.ts
deleted file mode 100644
index 167d19f..0000000
--- a/packages/backend/convex/betterAuth/schema.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-// This file is auto-generated. Do not edit this file manually.
-// To regenerate the schema, run:
-// `npx @better-auth/cli generate --output undefined -y`
-
-import { defineSchema, defineTable } from "convex/server";
-import { v } from "convex/values";
-
-export const tables = {
- user: defineTable({
- name: v.string(),
- email: v.string(),
- emailVerified: v.boolean(),
- image: v.optional(v.union(v.null(), v.string())),
- createdAt: v.number(),
- updatedAt: v.number(),
- userId: v.optional(v.union(v.null(), v.string())),
- })
- .index("email_name", ["email","name"])
- .index("name", ["name"])
- .index("userId", ["userId"]),
- session: defineTable({
- expiresAt: v.number(),
- token: v.string(),
- createdAt: v.number(),
- updatedAt: v.number(),
- ipAddress: v.optional(v.union(v.null(), v.string())),
- userAgent: v.optional(v.union(v.null(), v.string())),
- userId: v.string(),
- })
- .index("expiresAt", ["expiresAt"])
- .index("expiresAt_userId", ["expiresAt","userId"])
- .index("token", ["token"])
- .index("userId", ["userId"]),
- account: defineTable({
- accountId: v.string(),
- providerId: v.string(),
- userId: v.string(),
- accessToken: v.optional(v.union(v.null(), v.string())),
- refreshToken: v.optional(v.union(v.null(), v.string())),
- idToken: v.optional(v.union(v.null(), v.string())),
- accessTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
- refreshTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
- scope: v.optional(v.union(v.null(), v.string())),
- password: v.optional(v.union(v.null(), v.string())),
- createdAt: v.number(),
- updatedAt: v.number(),
- })
- .index("accountId", ["accountId"])
- .index("accountId_providerId", ["accountId","providerId"])
- .index("providerId_userId", ["providerId","userId"])
- .index("userId", ["userId"]),
- verification: defineTable({
- identifier: v.string(),
- value: v.string(),
- expiresAt: v.number(),
- createdAt: v.number(),
- updatedAt: v.number(),
- })
- .index("expiresAt", ["expiresAt"])
- .index("identifier", ["identifier"]),
- jwks: defineTable({
- publicKey: v.string(),
- privateKey: v.string(),
- createdAt: v.number(),
- }),
-};
-
-const schema = defineSchema(tables);
-
-export default schema;
diff --git a/packages/backend/convex/convex.config.ts b/packages/backend/convex/convex.config.ts
index f2d05fb..3367024 100644
--- a/packages/backend/convex/convex.config.ts
+++ b/packages/backend/convex/convex.config.ts
@@ -1,7 +1,4 @@
import { defineApp } from "convex/server";
-import betterAuth from "./betterAuth/convex.config";
-
const app = defineApp();
-app.use(betterAuth);
export default app;
diff --git a/packages/backend/convex/email.ts b/packages/backend/convex/email.ts
index 96b4e08..fa58c37 100644
--- a/packages/backend/convex/email.ts
+++ b/packages/backend/convex/email.ts
@@ -1,7 +1,14 @@
import { v } from "convex/values";
-import { mutation, query, action, internalMutation } from "./_generated/server";
+import {
+ mutation,
+ query,
+ action,
+ internalMutation,
+ internalQuery,
+} from "./_generated/server";
import { Id } from "./_generated/dataModel";
import { renderizarTemplate } from "./templatesMensagens";
+import { internal } from "./_generated/api";
/**
* Enfileirar email para envio
@@ -15,7 +22,10 @@ export const enfileirarEmail = mutation({
templateId: v.optional(v.id("templatesMensagens")),
enviadoPorId: v.id("usuarios"),
},
- returns: v.object({ sucesso: v.boolean(), emailId: v.optional(v.id("notificacoesEmail")) }),
+ returns: v.object({
+ sucesso: v.boolean(),
+ emailId: v.optional(v.id("notificacoesEmail")),
+ }),
handler: async (ctx, args) => {
// Validar email
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -51,7 +61,10 @@ export const enviarEmailComTemplate = mutation({
variaveis: v.any(), // Record
enviadoPorId: v.id("usuarios"),
},
- returns: v.object({ sucesso: v.boolean(), emailId: v.optional(v.id("notificacoesEmail")) }),
+ returns: v.object({
+ sucesso: v.boolean(),
+ emailId: v.optional(v.id("notificacoesEmail")),
+ }),
handler: async (ctx, args) => {
// Buscar template
const template = await ctx.db
@@ -90,26 +103,32 @@ export const enviarEmailComTemplate = mutation({
*/
export const listarFilaEmails = query({
args: {
- status: v.optional(v.union(
- v.literal("pendente"),
- v.literal("enviando"),
- v.literal("enviado"),
- v.literal("falha")
- )),
+ status: v.optional(
+ v.union(
+ v.literal("pendente"),
+ v.literal("enviando"),
+ v.literal("enviado"),
+ v.literal("falha")
+ )
+ ),
limite: v.optional(v.number()),
},
returns: v.array(v.any()),
handler: async (ctx, args) => {
- let query = ctx.db.query("notificacoesEmail");
-
if (args.status) {
- query = query.withIndex("by_status", (q) => q.eq("status", args.status));
- } else {
- query = query.withIndex("by_criado_em");
+ const emails = await ctx.db
+ .query("notificacoesEmail")
+ .withIndex("by_status", (q) => q.eq("status", args.status!))
+ .order("desc")
+ .take(args.limite ?? 100);
+ return emails;
}
- const emails = await query.order("desc").take(args.limite || 100);
-
+ const emails = await ctx.db
+ .query("notificacoesEmail")
+ .withIndex("by_criado_em")
+ .order("desc")
+ .take(args.limite ?? 100);
return emails;
},
});
@@ -141,8 +160,69 @@ export const reenviarEmail = mutation({
});
/**
- * Action para enviar email REAL usando nodemailer
+ * Action para enviar email (será implementado com nodemailer)
+ *
+ * NOTA: Este é um placeholder. Implementação real requer nodemailer.
*/
+export const getEmailById = internalQuery({
+ args: { emailId: v.id("notificacoesEmail") },
+ returns: v.union(v.any(), v.null()),
+ handler: async (ctx, args) => {
+ return await ctx.db.get(args.emailId);
+ },
+});
+
+export const getActiveEmailConfig = internalQuery({
+ args: {},
+ returns: v.union(v.any(), v.null()),
+ handler: async (ctx) => {
+ return await ctx.db
+ .query("configuracaoEmail")
+ .withIndex("by_ativo", (q) => q.eq("ativo", true))
+ .first();
+ },
+});
+
+export const markEmailEnviando = internalMutation({
+ args: { emailId: v.id("notificacoesEmail") },
+ returns: v.null(),
+ handler: async (ctx, args) => {
+ const email = await ctx.db.get(args.emailId);
+ await ctx.db.patch(args.emailId, {
+ status: "enviando",
+ tentativas: ((email as any)?.tentativas || 0) + 1,
+ ultimaTentativa: Date.now(),
+ });
+ return null;
+ },
+});
+
+export const markEmailEnviado = internalMutation({
+ args: { emailId: v.id("notificacoesEmail") },
+ returns: v.null(),
+ handler: async (ctx, args) => {
+ await ctx.db.patch(args.emailId, {
+ status: "enviado",
+ enviadoEm: Date.now(),
+ });
+ return null;
+ },
+});
+
+export const markEmailFalha = internalMutation({
+ args: { emailId: v.id("notificacoesEmail"), erro: v.string() },
+ returns: v.null(),
+ handler: async (ctx, args) => {
+ const email = await ctx.db.get(args.emailId);
+ await ctx.db.patch(args.emailId, {
+ status: "falha",
+ erroDetalhes: args.erro,
+ tentativas: ((email as any)?.tentativas || 0) + 1,
+ });
+ return null;
+ },
+});
+
export const enviarEmailAction = action({
args: {
emailId: v.id("notificacoesEmail"),
@@ -150,13 +230,13 @@ export const enviarEmailAction = action({
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
handler: async (ctx, args) => {
"use node";
-
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
const nodemailer = require("nodemailer");
-
+
try {
// Buscar email da fila
- const email = await ctx.runQuery(async (ctx) => {
- return await ctx.db.get(args.emailId);
+ const email = await ctx.runQuery(internal.email.getEmailById, {
+ emailId: args.emailId,
});
if (!email) {
@@ -164,78 +244,70 @@ export const enviarEmailAction = action({
}
// Buscar configuração SMTP
- const config = await ctx.runQuery(async (ctx) => {
- return await ctx.db
- .query("configuracaoEmail")
- .withIndex("by_ativo", (q) => q.eq("ativo", true))
- .first();
- });
+ const config = await ctx.runQuery(
+ internal.email.getActiveEmailConfig,
+ {}
+ );
if (!config) {
- return { sucesso: false, erro: "Configuração de email não encontrada ou inativa" };
+ return {
+ sucesso: false,
+ erro: "Configuração de email não encontrada ou inativa",
+ };
}
- if (!config.testado) {
- return { sucesso: false, erro: "Configuração SMTP não foi testada. Teste a conexão primeiro!" };
+ if (!config.testadoEm) {
+ return {
+ sucesso: false,
+ erro: "Configuração SMTP não foi testada. Teste a conexão primeiro!",
+ };
}
// Marcar como enviando
- await ctx.runMutation(async (ctx) => {
- await ctx.db.patch(args.emailId, {
- status: "enviando",
- tentativas: (email.tentativas || 0) + 1,
- ultimaTentativa: Date.now(),
- });
+ await ctx.runMutation(internal.email.markEmailEnviando, {
+ emailId: args.emailId,
});
// Criar transporter do nodemailer
const transporter = nodemailer.createTransport({
- host: config.smtpHost,
- port: config.smtpPort,
- secure: config.smtpSecure, // true para 465, false para outros
+ host: (config as any).smtpHost,
+ port: (config as any).smtpPort,
+ secure: (config as any).smtpSecure,
auth: {
- user: config.smtpUser,
- pass: config.smtpPassword,
+ user: (config as any).smtpUser,
+ pass: (config as any).smtpPassword,
},
tls: {
- // Não rejeitar certificados não autorizados (útil para testes)
- rejectUnauthorized: false
- }
+ rejectUnauthorized: false,
+ },
});
// Enviar email REAL
const info = await transporter.sendMail({
- from: `"${config.remetenteNome}" <${config.remetenteEmail}>`,
- to: email.destinatario,
- subject: email.assunto,
- html: email.corpo,
+ from: `"${(config as any).remetenteNome}" <${(config as any).remetenteEmail}>`,
+ to: (email as any).destinatario,
+ subject: (email as any).assunto,
+ html: (email as any).corpo,
});
console.log("✅ Email enviado com sucesso!");
- console.log(" Para:", email.destinatario);
- console.log(" Assunto:", email.assunto);
+ console.log(" Para:", (email as any).destinatario);
+ console.log(" Assunto:", (email as any).assunto);
console.log(" Message ID:", info.messageId);
// Marcar como enviado
- await ctx.runMutation(async (ctx) => {
- await ctx.db.patch(args.emailId, {
- status: "enviado",
- enviadoEm: Date.now(),
- });
+ await ctx.runMutation(internal.email.markEmailEnviado, {
+ emailId: args.emailId,
});
return { sucesso: true };
} catch (error: any) {
console.error("❌ Erro ao enviar email:", error.message);
-
+
// Marcar como falha
- await ctx.runMutation(async (ctx) => {
- const email = await ctx.db.get(args.emailId);
- await ctx.db.patch(args.emailId, {
- status: "falha",
- erroDetalhes: error.message || "Erro desconhecido",
- tentativas: (email?.tentativas || 0) + 1,
- });
+ await ctx.runMutation(internal.email.markEmailFalha, {
+ emailId: args.emailId,
+ erro: error.message || "Erro ao enviar email",
});
return { sucesso: false, erro: error.message || "Erro ao enviar email" };
@@ -278,10 +350,10 @@ export const processarFilaEmails = internalMutation({
processados++;
}
- console.log(`📧 Fila de emails processada: ${processados} emails agendados para envio`);
+ console.log(
+ `📧 Fila de emails processada: ${processados} emails agendados para envio`
+ );
return { processados };
},
});
-
-
diff --git a/packages/backend/convex/funcionarios.ts b/packages/backend/convex/funcionarios.ts
index baa02fd..6d6a7ad 100644
--- a/packages/backend/convex/funcionarios.ts
+++ b/packages/backend/convex/funcionarios.ts
@@ -1,19 +1,50 @@
import { v } from "convex/values";
import { query, mutation } from "./_generated/server";
+import { internal } from "./_generated/api";
import { simboloTipo } from "./schema";
// Validadores para campos opcionais
-const sexoValidator = v.optional(v.union(v.literal("masculino"), v.literal("feminino"), v.literal("outro")));
-const estadoCivilValidator = v.optional(v.union(v.literal("solteiro"), v.literal("casado"), v.literal("divorciado"), v.literal("viuvo"), v.literal("uniao_estavel")));
-const grauInstrucaoValidator = v.optional(v.union(v.literal("fundamental"), v.literal("medio"), v.literal("superior"), v.literal("pos_graduacao"), v.literal("mestrado"), v.literal("doutorado")));
-const grupoSanguineoValidator = v.optional(v.union(v.literal("A"), v.literal("B"), v.literal("AB"), v.literal("O")));
-const fatorRHValidator = v.optional(v.union(v.literal("positivo"), v.literal("negativo")));
-const aposentadoValidator = v.optional(v.union(v.literal("nao"), v.literal("funape_ipsep"), v.literal("inss")));
+const sexoValidator = v.optional(
+ v.union(v.literal("masculino"), v.literal("feminino"), v.literal("outro"))
+);
+const estadoCivilValidator = v.optional(
+ v.union(
+ v.literal("solteiro"),
+ v.literal("casado"),
+ v.literal("divorciado"),
+ v.literal("viuvo"),
+ v.literal("uniao_estavel")
+ )
+);
+const grauInstrucaoValidator = v.optional(
+ v.union(
+ v.literal("fundamental"),
+ v.literal("medio"),
+ v.literal("superior"),
+ v.literal("pos_graduacao"),
+ v.literal("mestrado"),
+ v.literal("doutorado")
+ )
+);
+const grupoSanguineoValidator = v.optional(
+ v.union(v.literal("A"), v.literal("B"), v.literal("AB"), v.literal("O"))
+);
+const fatorRHValidator = v.optional(
+ v.union(v.literal("positivo"), v.literal("negativo"))
+);
+const aposentadoValidator = v.optional(
+ v.union(v.literal("nao"), v.literal("funape_ipsep"), v.literal("inss"))
+);
export const getAll = query({
args: {},
returns: v.array(v.any()),
handler: async (ctx) => {
+ // Autorização: listar funcionários
+ await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
+ recurso: "funcionarios",
+ acao: "listar",
+ });
const funcionarios = await ctx.db.query("funcionarios").collect();
// Retornar apenas os campos necessários para listagem
return funcionarios.map((f: any) => ({
@@ -42,6 +73,11 @@ export const getById = query({
args: { id: v.id("funcionarios") },
returns: v.union(v.any(), v.null()),
handler: async (ctx, args) => {
+ // Autorização: ver funcionário
+ await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
+ recurso: "funcionarios",
+ acao: "ver",
+ });
return await ctx.db.get(args.id);
},
});
@@ -64,7 +100,7 @@ export const create = mutation({
admissaoData: v.optional(v.string()),
desligamentoData: v.optional(v.string()),
simboloTipo: simboloTipo,
-
+
// Dados Pessoais Adicionais
nomePai: v.optional(v.string()),
nomeMae: v.optional(v.string()),
@@ -73,7 +109,7 @@ export const create = mutation({
sexo: sexoValidator,
estadoCivil: estadoCivilValidator,
nacionalidade: v.optional(v.string()),
-
+
// Documentos Pessoais
rgOrgaoExpedidor: v.optional(v.string()),
rgDataEmissao: v.optional(v.string()),
@@ -86,14 +122,14 @@ export const create = mutation({
tituloEleitorZona: v.optional(v.string()),
tituloEleitorSecao: v.optional(v.string()),
pisNumero: v.optional(v.string()),
-
+
// Formação e Saúde
grauInstrucao: grauInstrucaoValidator,
formacao: v.optional(v.string()),
formacaoRegistro: v.optional(v.string()),
grupoSanguineo: grupoSanguineoValidator,
fatorRH: fatorRHValidator,
-
+
// Cargo e Vínculo
descricaoCargo: v.optional(v.string()),
nomeacaoPortaria: v.optional(v.string()),
@@ -102,12 +138,12 @@ export const create = mutation({
pertenceOrgaoPublico: v.optional(v.boolean()),
orgaoOrigem: v.optional(v.string()),
aposentado: aposentadoValidator,
-
+
// Dados Bancários
contaBradescoNumero: v.optional(v.string()),
contaBradescoDV: v.optional(v.string()),
contaBradescoAgencia: v.optional(v.string()),
-
+
// Documentos Anexos (Storage IDs)
certidaoAntecedentesPF: v.optional(v.id("_storage")),
certidaoAntecedentesJFPE: v.optional(v.id("_storage")),
@@ -132,7 +168,7 @@ export const create = mutation({
comprovanteEscolaridade: v.optional(v.id("_storage")),
comprovanteResidencia: v.optional(v.id("_storage")),
comprovanteContaBradesco: v.optional(v.id("_storage")),
-
+
// Declarações (Storage IDs)
declaracaoAcumulacaoCargo: v.optional(v.id("_storage")),
declaracaoDependentesIR: v.optional(v.id("_storage")),
@@ -142,6 +178,11 @@ export const create = mutation({
},
returns: v.id("funcionarios"),
handler: async (ctx, args) => {
+ // Autorização: criar
+ await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
+ recurso: "funcionarios",
+ acao: "criar",
+ });
// Unicidade: CPF
const cpfExists = await ctx.db
.query("funcionarios")
@@ -186,7 +227,7 @@ export const update = mutation({
admissaoData: v.optional(v.string()),
desligamentoData: v.optional(v.string()),
simboloTipo: simboloTipo,
-
+
// Dados Pessoais Adicionais
nomePai: v.optional(v.string()),
nomeMae: v.optional(v.string()),
@@ -195,7 +236,7 @@ export const update = mutation({
sexo: sexoValidator,
estadoCivil: estadoCivilValidator,
nacionalidade: v.optional(v.string()),
-
+
// Documentos Pessoais
rgOrgaoExpedidor: v.optional(v.string()),
rgDataEmissao: v.optional(v.string()),
@@ -208,14 +249,14 @@ export const update = mutation({
tituloEleitorZona: v.optional(v.string()),
tituloEleitorSecao: v.optional(v.string()),
pisNumero: v.optional(v.string()),
-
+
// Formação e Saúde
grauInstrucao: grauInstrucaoValidator,
formacao: v.optional(v.string()),
formacaoRegistro: v.optional(v.string()),
grupoSanguineo: grupoSanguineoValidator,
fatorRH: fatorRHValidator,
-
+
// Cargo e Vínculo
descricaoCargo: v.optional(v.string()),
nomeacaoPortaria: v.optional(v.string()),
@@ -224,12 +265,12 @@ export const update = mutation({
pertenceOrgaoPublico: v.optional(v.boolean()),
orgaoOrigem: v.optional(v.string()),
aposentado: aposentadoValidator,
-
+
// Dados Bancários
contaBradescoNumero: v.optional(v.string()),
contaBradescoDV: v.optional(v.string()),
contaBradescoAgencia: v.optional(v.string()),
-
+
// Documentos Anexos (Storage IDs)
certidaoAntecedentesPF: v.optional(v.id("_storage")),
certidaoAntecedentesJFPE: v.optional(v.id("_storage")),
@@ -254,7 +295,7 @@ export const update = mutation({
comprovanteEscolaridade: v.optional(v.id("_storage")),
comprovanteResidencia: v.optional(v.id("_storage")),
comprovanteContaBradesco: v.optional(v.id("_storage")),
-
+
// Declarações (Storage IDs)
declaracaoAcumulacaoCargo: v.optional(v.id("_storage")),
declaracaoDependentesIR: v.optional(v.id("_storage")),
@@ -264,6 +305,11 @@ export const update = mutation({
},
returns: v.null(),
handler: async (ctx, args) => {
+ // Autorização: editar
+ await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
+ recurso: "funcionarios",
+ acao: "editar",
+ });
// Unicidade: CPF (excluindo o próprio registro)
const cpfExists = await ctx.db
.query("funcionarios")
@@ -294,6 +340,11 @@ export const remove = mutation({
args: { id: v.id("funcionarios") },
returns: v.null(),
handler: async (ctx, args) => {
+ // Autorização: excluir
+ await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
+ recurso: "funcionarios",
+ acao: "excluir",
+ });
// TODO: Talvez queiramos também remover os arquivos do storage
await ctx.db.delete(args.id);
return null;
@@ -305,20 +356,24 @@ export const getFichaCompleta = query({
args: { id: v.id("funcionarios") },
returns: v.union(v.any(), v.null()),
handler: async (ctx, args) => {
+ await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
+ recurso: "funcionarios",
+ acao: "ver",
+ });
const funcionario = await ctx.db.get(args.id);
if (!funcionario) {
return null;
}
-
+
// Buscar informações do símbolo
const simbolo = await ctx.db.get(funcionario.simboloId);
-
+
// Buscar cursos do funcionário
const cursos = await ctx.db
.query("cursos")
.withIndex("by_funcionario", (q) => q.eq("funcionarioId", args.id))
.collect();
-
+
// Buscar URLs dos certificados
const cursosComUrls = await Promise.all(
cursos.map(async (curso) => {
@@ -332,17 +387,20 @@ export const getFichaCompleta = query({
};
})
);
-
+
return {
...funcionario,
- simbolo: simbolo ? {
- nome: simbolo.nome,
- descricao: simbolo.descricao,
- tipo: simbolo.tipo,
- vencValor: simbolo.vencValor,
- repValor: simbolo.repValor,
- valor: simbolo.valor,
- } : null,
+ simbolo: simbolo
+ ? {
+ nome: simbolo.nome,
+ descricao: simbolo.descricao,
+ // campos adicionais, se existirem no símbolo
+ tipo: (simbolo as any).tipo,
+ vencValor: (simbolo as any).vencValor,
+ repValor: (simbolo as any).repValor,
+ valor: (simbolo as any).valor,
+ }
+ : null,
cursos: cursosComUrls,
};
},
diff --git a/packages/backend/convex/http.ts b/packages/backend/convex/http.ts
index bcd0024..185d69c 100644
--- a/packages/backend/convex/http.ts
+++ b/packages/backend/convex/http.ts
@@ -1,8 +1,5 @@
import { httpRouter } from "convex/server";
-import { authComponent, createAuth } from "./auth";
const http = httpRouter();
-authComponent.registerRoutes(http, createAuth);
-
export default http;
diff --git a/packages/backend/convex/limparPerfisAntigos.ts b/packages/backend/convex/limparPerfisAntigos.ts
index 61a145f..9ed3797 100644
--- a/packages/backend/convex/limparPerfisAntigos.ts
+++ b/packages/backend/convex/limparPerfisAntigos.ts
@@ -13,7 +13,7 @@ export const listarTodosRoles = query({
descricao: v.string(),
nivel: v.number(),
setor: v.optional(v.string()),
- customizado: v.boolean(),
+ customizado: v.optional(v.boolean()),
editavel: v.optional(v.boolean()),
_creationTime: v.number(),
})
@@ -35,7 +35,7 @@ export const listarTodosRoles = query({
/**
* Limpar perfis antigos/duplicados
- *
+ *
* CRITÉRIOS:
* - Manter apenas: ti_master (nível 0), admin (nível 2), ti_usuario (nível 2)
* - Remover: admin antigo (nível 0), ti genérico (nível 1), outros duplicados
@@ -61,14 +61,14 @@ export const limparPerfisAntigos = internalMutation({
}),
handler: async (ctx) => {
const roles = await ctx.db.query("roles").collect();
-
+
const removidos: Array<{
nome: string;
descricao: string;
nivel: number;
motivo: string;
}> = [];
-
+
const mantidos: Array<{
nome: string;
descricao: string;
@@ -91,9 +91,10 @@ export const limparPerfisAntigos = internalMutation({
deveManter = true;
perfisCorretos.set("ti_master", true);
} else {
- motivo = role.nivel !== 0
- ? "TI_MASTER deve ser nível 0, este é nível " + role.nivel
- : "TI_MASTER duplicado";
+ motivo =
+ role.nivel !== 0
+ ? "TI_MASTER deve ser nível 0, este é nível " + role.nivel
+ : "TI_MASTER duplicado";
}
}
// ADMIN - Manter apenas o de nível 2
@@ -102,9 +103,10 @@ export const limparPerfisAntigos = internalMutation({
deveManter = true;
perfisCorretos.set("admin", true);
} else {
- motivo = role.nivel !== 2
- ? "ADMIN deve ser nível 2, este é nível " + role.nivel
- : "ADMIN duplicado";
+ motivo =
+ role.nivel !== 2
+ ? "ADMIN deve ser nível 2, este é nível " + role.nivel
+ : "ADMIN duplicado";
}
}
// TI_USUARIO - Manter apenas o de nível 2
@@ -113,14 +115,16 @@ export const limparPerfisAntigos = internalMutation({
deveManter = true;
perfisCorretos.set("ti_usuario", true);
} else {
- motivo = role.nivel !== 2
- ? "TI_USUARIO deve ser nível 2, este é nível " + role.nivel
- : "TI_USUARIO duplicado";
+ motivo =
+ role.nivel !== 2
+ ? "TI_USUARIO deve ser nível 2, este é nível " + role.nivel
+ : "TI_USUARIO duplicado";
}
}
// Perfis genéricos antigos (remover)
else if (role.nome === "ti") {
- motivo = "Perfil genérico 'ti' obsoleto - usar 'ti_master' ou 'ti_usuario'";
+ motivo =
+ "Perfil genérico 'ti' obsoleto - usar 'ti_master' ou 'ti_usuario'";
}
// Outros perfis específicos de setores (manter se forem nível >= 2)
else if (
@@ -157,7 +161,9 @@ export const limparPerfisAntigos = internalMutation({
descricao: role.descricao,
nivel: role.nivel,
});
- console.log(`✅ MANTIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel}`);
+ console.log(
+ `✅ MANTIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel}`
+ );
} else {
// Verificar se há usuários usando este perfil
const usuariosComRole = await ctx.db
@@ -286,6 +292,3 @@ export const verificarNiveisIncorretos = query({
return problemas;
},
});
-
-
-
diff --git a/packages/backend/convex/logsAtividades.ts b/packages/backend/convex/logsAtividades.ts
index 1c8109d..2a87b16 100644
--- a/packages/backend/convex/logsAtividades.ts
+++ b/packages/backend/convex/logsAtividades.ts
@@ -7,7 +7,7 @@ import { Doc, Id } from "./_generated/dataModel";
* Use em todas as mutations que modificam dados
*/
export async function registrarAtividade(
- ctx: QueryCtx | MutationCtx,
+ ctx: MutationCtx,
usuarioId: Id<"usuarios">,
acao: string,
recurso: string,
@@ -37,21 +37,34 @@ export const listarAtividades = query({
limite: v.optional(v.number()),
},
handler: async (ctx, args) => {
- let query = ctx.db.query("logsAtividades");
+ let atividades;
- // Aplicar filtros
if (args.usuarioId) {
- query = query.withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId));
+ atividades = await ctx.db
+ .query("logsAtividades")
+ .withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId!))
+ .order("desc")
+ .take(args.limite || 100);
} else if (args.acao) {
- query = query.withIndex("by_acao", (q) => q.eq("acao", args.acao));
+ atividades = await ctx.db
+ .query("logsAtividades")
+ .withIndex("by_acao", (q) => q.eq("acao", args.acao!))
+ .order("desc")
+ .take(args.limite || 100);
} else if (args.recurso) {
- query = query.withIndex("by_recurso", (q) => q.eq("recurso", args.recurso));
+ atividades = await ctx.db
+ .query("logsAtividades")
+ .withIndex("by_recurso", (q) => q.eq("recurso", args.recurso!))
+ .order("desc")
+ .take(args.limite || 100);
} else {
- query = query.withIndex("by_timestamp");
+ atividades = await ctx.db
+ .query("logsAtividades")
+ .withIndex("by_timestamp")
+ .order("desc")
+ .take(args.limite || 100);
}
- let atividades = await query.order("desc").take(args.limite || 100);
-
// Filtrar por range de datas se fornecido
if (args.dataInicio || args.dataFim) {
atividades = atividades.filter((log) => {
@@ -155,5 +168,3 @@ export const obterHistoricoRecurso = query({
return atividadesComUsuarios;
},
});
-
-
diff --git a/packages/backend/convex/logsLogin.ts b/packages/backend/convex/logsLogin.ts
index 4a9a1fa..acb377d 100644
--- a/packages/backend/convex/logsLogin.ts
+++ b/packages/backend/convex/logsLogin.ts
@@ -6,7 +6,7 @@ import { Doc, Id } from "./_generated/dataModel";
* Helper para registrar tentativas de login
*/
export async function registrarLogin(
- ctx: QueryCtx | MutationCtx,
+ ctx: MutationCtx,
dados: {
usuarioId?: Id<"usuarios">;
matriculaOuEmail: string;
@@ -170,26 +170,32 @@ export const obterEstatisticasLogin = query({
// Logins por horário (hora do dia)
const porHorario: Record = {};
- logs.filter((l) => l.sucesso).forEach((log) => {
- const hora = new Date(log.timestamp).getHours();
- porHorario[hora] = (porHorario[hora] || 0) + 1;
- });
+ logs
+ .filter((l) => l.sucesso)
+ .forEach((log) => {
+ const hora = new Date(log.timestamp).getHours();
+ porHorario[hora] = (porHorario[hora] || 0) + 1;
+ });
// Browser mais usado
const porBrowser: Record = {};
- logs.filter((l) => l.sucesso).forEach((log) => {
- if (log.browser) {
- porBrowser[log.browser] = (porBrowser[log.browser] || 0) + 1;
- }
- });
+ logs
+ .filter((l) => l.sucesso)
+ .forEach((log) => {
+ if (log.browser) {
+ porBrowser[log.browser] = (porBrowser[log.browser] || 0) + 1;
+ }
+ });
// Dispositivos mais usados
const porDevice: Record = {};
- logs.filter((l) => l.sucesso).forEach((log) => {
- if (log.device) {
- porDevice[log.device] = (porDevice[log.device] || 0) + 1;
- }
- });
+ logs
+ .filter((l) => l.sucesso)
+ .forEach((log) => {
+ if (log.device) {
+ porDevice[log.device] = (porDevice[log.device] || 0) + 1;
+ }
+ });
return {
total: logs.length,
@@ -231,4 +237,3 @@ export const verificarIPSuspeito = query({
};
},
});
-
diff --git a/packages/backend/convex/menuPermissoes.ts b/packages/backend/convex/menuPermissoes.ts
deleted file mode 100644
index 3b1aaa3..0000000
--- a/packages/backend/convex/menuPermissoes.ts
+++ /dev/null
@@ -1,529 +0,0 @@
-import { v } from "convex/values";
-import { mutation, query } from "./_generated/server";
-import type { Id } from "./_generated/dataModel";
-
-/**
- * Lista de menus do sistema
- */
-export const MENUS_SISTEMA = [
- { path: "/recursos-humanos", nome: "Recursos Humanos", descricao: "Gestão de funcionários e símbolos" },
- { path: "/recursos-humanos/funcionarios", nome: "Funcionários", descricao: "Cadastro e gestão de funcionários" },
- { path: "/recursos-humanos/simbolos", nome: "Símbolos", descricao: "Cadastro e gestão de símbolos" },
- { path: "/financeiro", nome: "Financeiro", descricao: "Gestão financeira" },
- { path: "/controladoria", nome: "Controladoria", descricao: "Controle e auditoria" },
- { path: "/licitacoes", nome: "Licitações", descricao: "Gestão de licitações" },
- { path: "/compras", nome: "Compras", descricao: "Gestão de compras" },
- { path: "/juridico", nome: "Jurídico", descricao: "Departamento jurídico" },
- { path: "/comunicacao", nome: "Comunicação", descricao: "Gestão de comunicação" },
- { path: "/programas-esportivos", nome: "Programas Esportivos", descricao: "Gestão de programas esportivos" },
- { path: "/secretaria-executiva", nome: "Secretaria Executiva", descricao: "Secretaria executiva" },
- { path: "/gestao-pessoas", nome: "Gestão de Pessoas", descricao: "Gestão de recursos humanos" },
- { path: "/ti", nome: "Tecnologia da Informação", descricao: "TI e suporte técnico" },
- { path: "/ti/painel-administrativo", nome: "Painel Administrativo TI", descricao: "Painel de administração do sistema" },
- { path: "/ti/monitoramento", nome: "Monitoramento SGSE", descricao: "Monitoramento técnico do sistema em tempo real" },
-] as const;
-
-/**
- * Listar todas as permissões de menu para uma role
- */
-export const listarPorRole = query({
- args: { roleId: v.id("roles") },
- returns: v.array(
- v.object({
- _id: v.id("menuPermissoes"),
- roleId: v.id("roles"),
- menuPath: v.string(),
- podeAcessar: v.boolean(),
- podeConsultar: v.boolean(),
- podeGravar: v.boolean(),
- })
- ),
- handler: async (ctx, args) => {
- return await ctx.db
- .query("menuPermissoes")
- .withIndex("by_role", (q) => q.eq("roleId", args.roleId))
- .collect();
- },
-});
-
-/**
- * Verificar se um usuário tem permissão para acessar um menu
- * Prioridade: Permissão personalizada > Permissão da role
- */
-export const verificarAcesso = query({
- args: {
- usuarioId: v.id("usuarios"),
- menuPath: v.string(),
- },
- returns: v.object({
- podeAcessar: v.boolean(),
- podeConsultar: v.boolean(),
- podeGravar: v.boolean(),
- motivo: v.optional(v.string()),
- }),
- handler: async (ctx, args) => {
- // Buscar o usuário
- const usuario = await ctx.db.get(args.usuarioId);
- if (!usuario) {
- return {
- podeAcessar: false,
- podeConsultar: false,
- podeGravar: false,
- motivo: "Usuário não encontrado",
- };
- }
-
- // Verificar se o usuário está ativo
- if (!usuario.ativo) {
- return {
- podeAcessar: false,
- podeConsultar: false,
- podeGravar: false,
- motivo: "Usuário inativo",
- };
- }
-
- // Buscar a role do usuário
- const role = await ctx.db.get(usuario.roleId);
- if (!role) {
- return {
- podeAcessar: false,
- podeConsultar: false,
- podeGravar: false,
- motivo: "Role não encontrada",
- };
- }
-
- // Apenas TI_MASTER (nível 0) tem acesso total irrestrito
- // Admin, TI_USUARIO e outros (nível >= 1) têm permissões configuráveis
- if (role.nivel === 0) {
- return {
- podeAcessar: true,
- podeConsultar: true,
- podeGravar: true,
- };
- }
-
- // Dashboard e Solicitar Acesso são públicos
- if (args.menuPath === "/" || args.menuPath === "/solicitar-acesso") {
- return {
- podeAcessar: true,
- podeConsultar: true,
- podeGravar: false,
- };
- }
-
- // 1. Verificar se existe permissão personalizada para este usuário
- const permissaoPersonalizada = await ctx.db
- .query("menuPermissoesPersonalizadas")
- .withIndex("by_usuario_and_menu", (q) =>
- q.eq("usuarioId", args.usuarioId).eq("menuPath", args.menuPath)
- )
- .first();
-
- if (permissaoPersonalizada) {
- return {
- podeAcessar: permissaoPersonalizada.podeAcessar,
- podeConsultar: permissaoPersonalizada.podeConsultar,
- podeGravar: permissaoPersonalizada.podeGravar,
- };
- }
-
- // 2. Se não houver permissão personalizada, verificar permissão da role
- const permissaoRole = await ctx.db
- .query("menuPermissoes")
- .withIndex("by_role_and_menu", (q) =>
- q.eq("roleId", usuario.roleId).eq("menuPath", args.menuPath)
- )
- .first();
-
- if (!permissaoRole) {
- return {
- podeAcessar: false,
- podeConsultar: false,
- podeGravar: false,
- motivo: "Sem permissão configurada para este menu",
- };
- }
-
- return {
- podeAcessar: permissaoRole.podeAcessar,
- podeConsultar: permissaoRole.podeConsultar,
- podeGravar: permissaoRole.podeGravar,
- };
- },
-});
-
-/**
- * Atualizar ou criar permissão de menu para uma role
- */
-export const atualizarPermissao = mutation({
- args: {
- roleId: v.id("roles"),
- menuPath: v.string(),
- podeAcessar: v.boolean(),
- podeConsultar: v.boolean(),
- podeGravar: v.boolean(),
- },
- returns: v.id("menuPermissoes"),
- handler: async (ctx, args) => {
- // Verificar se já existe uma permissão
- const existente = await ctx.db
- .query("menuPermissoes")
- .withIndex("by_role_and_menu", (q) =>
- q.eq("roleId", args.roleId).eq("menuPath", args.menuPath)
- )
- .first();
-
- if (existente) {
- // Atualizar permissão existente
- await ctx.db.patch(existente._id, {
- podeAcessar: args.podeAcessar,
- podeConsultar: args.podeConsultar,
- podeGravar: args.podeGravar,
- });
- return existente._id;
- } else {
- // Criar nova permissão
- return await ctx.db.insert("menuPermissoes", {
- roleId: args.roleId,
- menuPath: args.menuPath,
- podeAcessar: args.podeAcessar,
- podeConsultar: args.podeConsultar,
- podeGravar: args.podeGravar,
- });
- }
- },
-});
-
-/**
- * Remover permissão de menu
- */
-export const removerPermissao = mutation({
- args: {
- permissaoId: v.id("menuPermissoes"),
- },
- returns: v.null(),
- handler: async (ctx, args) => {
- await ctx.db.delete(args.permissaoId);
- return null;
- },
-});
-
-/**
- * Inicializar permissões padrão para uma role
- */
-export const inicializarPermissoesRole = mutation({
- args: {
- roleId: v.id("roles"),
- },
- returns: v.null(),
- handler: async (ctx, args) => {
- // Buscar a role
- const role = await ctx.db.get(args.roleId);
- if (!role) {
- throw new Error("Role não encontrada");
- }
-
- // Admin e TI não precisam de permissões específicas (acesso total)
- if (role.nivel <= 1) {
- return null;
- }
-
- // Para outras roles, criar permissões básicas (apenas consulta)
- for (const menu of MENUS_SISTEMA) {
- // Verificar se já existe permissão
- const existente = await ctx.db
- .query("menuPermissoes")
- .withIndex("by_role_and_menu", (q) =>
- q.eq("roleId", args.roleId).eq("menuPath", menu.path)
- )
- .first();
-
- if (!existente) {
- // Criar permissão padrão (sem acesso)
- await ctx.db.insert("menuPermissoes", {
- roleId: args.roleId,
- menuPath: menu.path,
- podeAcessar: false,
- podeConsultar: false,
- podeGravar: false,
- });
- }
- }
-
- return null;
- },
-});
-
-/**
- * Listar todos os menus do sistema
- */
-export const listarMenus = query({
- args: {},
- returns: v.array(
- v.object({
- path: v.string(),
- nome: v.string(),
- descricao: v.string(),
- })
- ),
- handler: async (ctx) => {
- return MENUS_SISTEMA.map((menu) => ({
- path: menu.path,
- nome: menu.nome,
- descricao: menu.descricao,
- }));
- },
-});
-
-/**
- * Obter matriz de permissões (role x menu) para o painel de controle
- */
-export const obterMatrizPermissoes = query({
- args: {},
- returns: v.array(
- v.object({
- role: v.object({
- _id: v.id("roles"),
- nome: v.string(),
- nivel: v.number(),
- descricao: v.string(),
- }),
- permissoes: v.array(
- v.object({
- menuPath: v.string(),
- menuNome: v.string(),
- podeAcessar: v.boolean(),
- podeConsultar: v.boolean(),
- podeGravar: v.boolean(),
- permissaoId: v.optional(v.id("menuPermissoes")),
- })
- ),
- })
- ),
- handler: async (ctx) => {
- // Buscar todas as roles
- // TI_MASTER (nível 0) aparece mas não é editável
- // Admin, TI_USUARIO e outros (nível >= 1) são configuráveis
- const roles = await ctx.db.query("roles").collect();
-
- const matriz = [];
-
- for (const role of roles) {
- const permissoes = [];
-
- for (const menu of MENUS_SISTEMA) {
- // Buscar permissão específica
- const permissao = await ctx.db
- .query("menuPermissoes")
- .withIndex("by_role_and_menu", (q) =>
- q.eq("roleId", role._id).eq("menuPath", menu.path)
- )
- .first();
-
- // Admin e TI têm acesso total automático
- if (role.nivel <= 1) {
- permissoes.push({
- menuPath: menu.path,
- menuNome: menu.nome,
- podeAcessar: true,
- podeConsultar: true,
- podeGravar: true,
- permissaoId: permissao?._id,
- });
- } else {
- permissoes.push({
- menuPath: menu.path,
- menuNome: menu.nome,
- podeAcessar: permissao?.podeAcessar ?? false,
- podeConsultar: permissao?.podeConsultar ?? false,
- podeGravar: permissao?.podeGravar ?? false,
- permissaoId: permissao?._id,
- });
- }
- }
-
- matriz.push({
- role: {
- _id: role._id,
- nome: role.nome,
- nivel: role.nivel,
- descricao: role.descricao,
- },
- permissoes,
- });
- }
-
- return matriz;
- },
-});
-
-/**
- * Criar ou atualizar permissão personalizada por matrícula
- */
-export const atualizarPermissaoPersonalizada = mutation({
- args: {
- matricula: v.string(),
- menuPath: v.string(),
- podeAcessar: v.boolean(),
- podeConsultar: v.boolean(),
- podeGravar: v.boolean(),
- },
- returns: v.union(v.id("menuPermissoesPersonalizadas"), v.null()),
- handler: async (ctx, args) => {
- // Buscar usuário pela matrícula
- const usuario = await ctx.db
- .query("usuarios")
- .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
- .first();
-
- if (!usuario) {
- throw new Error("Usuário não encontrado com esta matrícula");
- }
-
- // Verificar se já existe permissão personalizada
- const existente = await ctx.db
- .query("menuPermissoesPersonalizadas")
- .withIndex("by_usuario_and_menu", (q) =>
- q.eq("usuarioId", usuario._id).eq("menuPath", args.menuPath)
- )
- .first();
-
- if (existente) {
- // Atualizar permissão existente
- await ctx.db.patch(existente._id, {
- podeAcessar: args.podeAcessar,
- podeConsultar: args.podeConsultar,
- podeGravar: args.podeGravar,
- });
- return existente._id;
- } else {
- // Criar nova permissão
- return await ctx.db.insert("menuPermissoesPersonalizadas", {
- usuarioId: usuario._id,
- matricula: args.matricula,
- menuPath: args.menuPath,
- podeAcessar: args.podeAcessar,
- podeConsultar: args.podeConsultar,
- podeGravar: args.podeGravar,
- });
- }
- },
-});
-
-/**
- * Remover permissão personalizada
- */
-export const removerPermissaoPersonalizada = mutation({
- args: {
- permissaoId: v.id("menuPermissoesPersonalizadas"),
- },
- returns: v.null(),
- handler: async (ctx, args) => {
- await ctx.db.delete(args.permissaoId);
- return null;
- },
-});
-
-/**
- * Listar permissões personalizadas de um usuário por matrícula
- */
-export const listarPermissoesPersonalizadas = query({
- args: {
- matricula: v.string(),
- },
- returns: v.array(
- v.object({
- _id: v.id("menuPermissoesPersonalizadas"),
- menuPath: v.string(),
- menuNome: v.string(),
- podeAcessar: v.boolean(),
- podeConsultar: v.boolean(),
- podeGravar: v.boolean(),
- })
- ),
- handler: async (ctx, args) => {
- // Buscar usuário
- const usuario = await ctx.db
- .query("usuarios")
- .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
- .first();
-
- if (!usuario) {
- return [];
- }
-
- // Buscar permissões personalizadas
- const permissoes = await ctx.db
- .query("menuPermissoesPersonalizadas")
- .withIndex("by_usuario", (q) => q.eq("usuarioId", usuario._id))
- .collect();
-
- // Mapear com nomes dos menus
- return permissoes.map((p) => {
- const menu = MENUS_SISTEMA.find((m) => m.path === p.menuPath);
- return {
- _id: p._id,
- menuPath: p.menuPath,
- menuNome: menu?.nome || p.menuPath,
- podeAcessar: p.podeAcessar,
- podeConsultar: p.podeConsultar,
- podeGravar: p.podeGravar,
- };
- });
- },
-});
-
-/**
- * Buscar usuário por matrícula para o painel de personalização
- */
-export const buscarUsuarioPorMatricula = query({
- args: {
- matricula: v.string(),
- },
- returns: v.union(
- v.object({
- _id: v.id("usuarios"),
- matricula: v.string(),
- nome: v.string(),
- email: v.string(),
- role: v.object({
- nome: v.string(),
- nivel: v.number(),
- descricao: v.string(),
- }),
- ativo: v.boolean(),
- }),
- v.null()
- ),
- handler: async (ctx, args) => {
- const usuario = await ctx.db
- .query("usuarios")
- .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
- .first();
-
- if (!usuario) {
- return null;
- }
-
- const role = await ctx.db.get(usuario.roleId);
- if (!role) {
- return null;
- }
-
- return {
- _id: usuario._id,
- matricula: usuario.matricula,
- nome: usuario.nome,
- email: usuario.email,
- role: {
- nome: role.nome,
- nivel: role.nivel,
- descricao: role.descricao,
- },
- ativo: usuario.ativo,
- };
- },
-});
-
diff --git a/packages/backend/convex/perfisCustomizados.ts b/packages/backend/convex/perfisCustomizados.ts
index 87c89ca..34529bc 100644
--- a/packages/backend/convex/perfisCustomizados.ts
+++ b/packages/backend/convex/perfisCustomizados.ts
@@ -1,12 +1,15 @@
import { v } from "convex/values";
import { mutation, query } from "./_generated/server";
import { registrarAtividade } from "./logsAtividades";
+import { api } from "./_generated/api";
+import { Id } from "./_generated/dataModel";
/**
* Listar todos os perfis customizados
*/
export const listarPerfisCustomizados = query({
args: {},
+ returns: v.array(v.any()),
handler: async (ctx) => {
const perfis = await ctx.db.query("perfisCustomizados").collect();
@@ -15,7 +18,7 @@ export const listarPerfisCustomizados = query({
perfis.map(async (perfil) => {
const role = await ctx.db.get(perfil.roleId);
const criador = await ctx.db.get(perfil.criadoPor);
-
+
// Contar usuários usando este perfil
const usuarios = await ctx.db
.query("usuarios")
@@ -42,6 +45,16 @@ export const obterPerfilComPermissoes = query({
args: {
perfilId: v.id("perfisCustomizados"),
},
+ returns: v.union(
+ v.object({
+ perfil: v.any(),
+ role: v.any(),
+ permissoes: v.array(v.any()),
+ menuPermissoes: v.array(v.any()),
+ usuarios: v.array(v.any()),
+ }),
+ v.null()
+ ),
handler: async (ctx, args) => {
const perfil = await ctx.db.get(args.perfilId);
if (!perfil) {
@@ -99,20 +112,31 @@ export const criarPerfilCustomizado = mutation({
criadoPorId: v.id("usuarios"),
},
returns: v.union(
- v.object({ sucesso: v.literal(true), perfilId: v.id("perfisCustomizados") }),
+ v.object({
+ sucesso: v.literal(true),
+ perfilId: v.id("perfisCustomizados"),
+ }),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args) => {
// Validar nível (deve ser >= 3)
if (args.nivel < 3) {
- return { sucesso: false as const, erro: "Perfis customizados devem ter nível >= 3" };
+ return {
+ sucesso: false as const,
+ erro: "Perfis customizados devem ter nível >= 3",
+ };
}
// Verificar se nome já existe
const roles = await ctx.db.query("roles").collect();
- const nomeExiste = roles.some((r) => r.nome.toLowerCase() === args.nome.toLowerCase());
+ const nomeExiste = roles.some(
+ (r) => r.nome.toLowerCase() === args.nome.toLowerCase()
+ );
if (nomeExiste) {
- return { sucesso: false as const, erro: "Já existe um perfil com este nome" };
+ return {
+ sucesso: false as const,
+ erro: "Já existe um perfil com este nome",
+ };
}
// Criar role correspondente
@@ -130,7 +154,7 @@ export const criarPerfilCustomizado = mutation({
// Copiar permissões gerais
const permissoesClonar = await ctx.db
.query("rolePermissoes")
- .withIndex("by_role", (q) => q.eq("roleId", args.clonarDeRoleId))
+ .withIndex("by_role", (q) => q.eq("roleId", args.clonarDeRoleId!))
.collect();
for (const perm of permissoesClonar) {
@@ -143,7 +167,7 @@ export const criarPerfilCustomizado = mutation({
// Copiar permissões de menu
const menuPermsClonar = await ctx.db
.query("menuPermissoes")
- .withIndex("by_role", (q) => q.eq("roleId", args.clonarDeRoleId))
+ .withIndex("by_role", (q) => q.eq("roleId", args.clonarDeRoleId!))
.collect();
for (const menuPerm of menuPermsClonar) {
@@ -321,7 +345,10 @@ export const clonarPerfil = mutation({
criadoPorId: v.id("usuarios"),
},
returns: v.union(
- v.object({ sucesso: v.literal(true), perfilId: v.id("perfisCustomizados") }),
+ v.object({
+ sucesso: v.literal(true),
+ perfilId: v.id("perfisCustomizados"),
+ }),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args) => {
@@ -330,17 +357,80 @@ export const clonarPerfil = mutation({
return { sucesso: false as const, erro: "Perfil origem não encontrado" };
}
- // Criar novo perfil clonando o original
- const resultado = await criarPerfilCustomizado(ctx, {
+ // Verificar se nome já existe
+ const roles = await ctx.db.query("roles").collect();
+ const nomeExiste = roles.some(
+ (r) => r.nome.toLowerCase() === args.novoNome.toLowerCase()
+ );
+ if (nomeExiste) {
+ return {
+ sucesso: false as const,
+ erro: "Já existe um perfil com este nome",
+ };
+ }
+
+ // Criar role correspondente
+ const roleId = await ctx.db.insert("roles", {
+ nome: args.novoNome.toLowerCase().replace(/\s+/g, "_"),
+ descricao: args.novaDescricao,
+ nivel: perfilOrigem.nivel,
+ customizado: true,
+ criadoPor: args.criadoPorId,
+ editavel: true,
+ });
+
+ // Copiar permissões gerais do perfil de origem
+ const permissoesClonar = await ctx.db
+ .query("rolePermissoes")
+ .withIndex("by_role", (q) => q.eq("roleId", perfilOrigem.roleId))
+ .collect();
+ for (const perm of permissoesClonar) {
+ await ctx.db.insert("rolePermissoes", {
+ roleId,
+ permissaoId: perm.permissaoId,
+ });
+ }
+
+ // Copiar permissões de menu
+ const menuPermsClonar = await ctx.db
+ .query("menuPermissoes")
+ .withIndex("by_role", (q) => q.eq("roleId", perfilOrigem.roleId))
+ .collect();
+ for (const menuPerm of menuPermsClonar) {
+ await ctx.db.insert("menuPermissoes", {
+ roleId,
+ menuPath: menuPerm.menuPath,
+ podeAcessar: menuPerm.podeAcessar,
+ podeConsultar: menuPerm.podeConsultar,
+ podeGravar: menuPerm.podeGravar,
+ });
+ }
+
+ // Criar perfil customizado
+ const perfilId = await ctx.db.insert("perfisCustomizados", {
nome: args.novoNome,
descricao: args.novaDescricao,
nivel: perfilOrigem.nivel,
- clonarDeRoleId: perfilOrigem.roleId,
- criadoPorId: args.criadoPorId,
+ roleId,
+ criadoPor: args.criadoPorId,
+ criadoEm: Date.now(),
+ atualizadoEm: Date.now(),
});
- return resultado;
+ // Log de atividade
+ await registrarAtividade(
+ ctx as any,
+ args.criadoPorId,
+ "criar",
+ "perfis",
+ JSON.stringify({
+ perfilId,
+ nome: args.novoNome,
+ nivel: perfilOrigem.nivel,
+ }),
+ perfilId
+ );
+
+ return { sucesso: true as const, perfilId };
},
});
-
-
diff --git a/packages/backend/convex/permissoesAcoes.ts b/packages/backend/convex/permissoesAcoes.ts
new file mode 100644
index 0000000..25820e4
--- /dev/null
+++ b/packages/backend/convex/permissoesAcoes.ts
@@ -0,0 +1,210 @@
+import { query, mutation, internalQuery } from "./_generated/server";
+import { v } from "convex/values";
+
+// Catálogo base de recursos e ações
+// Ajuste/expanda conforme os módulos disponíveis no sistema
+export const CATALOGO_RECURSOS = [
+ {
+ recurso: "funcionarios",
+ acoes: ["dashboard", "ver", "listar", "criar", "editar", "excluir"],
+ },
+ {
+ recurso: "simbolos",
+ acoes: ["dashboard", "ver", "listar", "criar", "editar", "excluir"],
+ },
+] as const;
+
+export const listarRecursosEAcoes = query({
+ args: {},
+ returns: v.array(
+ v.object({
+ recurso: v.string(),
+ acoes: v.array(v.string()),
+ })
+ ),
+ handler: async () => {
+ return CATALOGO_RECURSOS.map((r) => ({
+ recurso: r.recurso,
+ acoes: [...r.acoes],
+ }));
+ },
+});
+
+export const listarPermissoesAcoesPorRole = query({
+ args: { roleId: v.id("roles") },
+ returns: v.array(
+ v.object({
+ recurso: v.string(),
+ acoes: v.array(v.string()),
+ })
+ ),
+ handler: async (ctx, args) => {
+ // Buscar vínculos permissao<-role
+ const rolePerms = await ctx.db
+ .query("rolePermissoes")
+ .withIndex("by_role", (q) => q.eq("roleId", args.roleId))
+ .collect();
+
+ // Carregar documentos de permissões
+ const actionsByResource: Record> = {};
+ for (const rp of rolePerms) {
+ const perm = await ctx.db.get(rp.permissaoId);
+ if (!perm) continue;
+ const set = (actionsByResource[perm.recurso] ||= new Set());
+ set.add(perm.acao);
+ }
+
+ // Normalizar para todos os recursos do catálogo
+ const result: Array<{ recurso: string; acoes: Array }> = [];
+ for (const item of CATALOGO_RECURSOS) {
+ const granted = Array.from(
+ actionsByResource[item.recurso] ?? new Set()
+ );
+ result.push({ recurso: item.recurso, acoes: granted });
+ }
+ return result;
+ },
+});
+
+export const atualizarPermissaoAcao = mutation({
+ args: {
+ roleId: v.id("roles"),
+ recurso: v.string(),
+ acao: v.string(),
+ conceder: v.boolean(),
+ },
+ returns: v.null(),
+ handler: async (ctx, args) => {
+ // Garantir documento de permissão (recurso+acao)
+ let permissao = await ctx.db
+ .query("permissoes")
+ .withIndex("by_recurso_e_acao", (q) =>
+ q.eq("recurso", args.recurso).eq("acao", args.acao)
+ )
+ .first();
+
+ if (!permissao) {
+ const nome = `${args.recurso}.${args.acao}`;
+ const descricao = `Permite ${args.acao} em ${args.recurso}`;
+ const id = await ctx.db.insert("permissoes", {
+ nome,
+ descricao,
+ recurso: args.recurso,
+ acao: args.acao,
+ });
+ permissao = await ctx.db.get(id);
+ }
+
+ if (!permissao) return null;
+
+ // Verificar vínculo atual
+ const existente = await ctx.db
+ .query("rolePermissoes")
+ .withIndex("by_role", (q) => q.eq("roleId", args.roleId))
+ .collect();
+
+ const vinculo = existente.find((rp) => rp.permissaoId === permissao!._id);
+
+ if (args.conceder) {
+ if (!vinculo) {
+ await ctx.db.insert("rolePermissoes", {
+ roleId: args.roleId,
+ permissaoId: permissao._id,
+ });
+ }
+ } else {
+ if (vinculo) {
+ await ctx.db.delete(vinculo._id);
+ }
+ }
+ return null;
+ },
+});
+
+export const verificarAcao = query({
+ args: {
+ usuarioId: v.id("usuarios"),
+ recurso: v.string(),
+ acao: v.string(),
+ },
+ returns: v.null(),
+ handler: async (ctx, args) => {
+ const usuario = await ctx.db.get(args.usuarioId);
+ if (!usuario) throw new Error("acesso_negado");
+
+ const role = await ctx.db.get(usuario.roleId);
+ if (!role) throw new Error("acesso_negado");
+
+ // Níveis administrativos têm acesso total
+ if (role.nivel <= 1) return null;
+
+ // Encontrar permissão
+ const permissao = await ctx.db
+ .query("permissoes")
+ .withIndex("by_recurso_e_acao", (q) =>
+ q.eq("recurso", args.recurso).eq("acao", args.acao)
+ )
+ .first();
+ if (!permissao) throw new Error("acesso_negado");
+
+ const hasLink = await ctx.db
+ .query("rolePermissoes")
+ .withIndex("by_role", (q) => q.eq("roleId", usuario.roleId))
+ .collect();
+ const permitido = hasLink.some((rp) => rp.permissaoId === permissao!._id);
+ if (!permitido) throw new Error("acesso_negado");
+ return null;
+ },
+});
+
+export const assertPermissaoAcaoAtual = internalQuery({
+ args: {
+ recurso: v.string(),
+ acao: v.string(),
+ },
+ returns: v.null(),
+ handler: async (ctx, args) => {
+ const identity = await ctx.auth.getUserIdentity();
+ let usuarioAtual: any = null;
+
+ if (identity && identity.email) {
+ usuarioAtual = await ctx.db
+ .query("usuarios")
+ .withIndex("by_email", (q) => q.eq("email", identity.email!))
+ .first();
+ }
+
+ if (!usuarioAtual) {
+ const sessaoAtiva = await ctx.db
+ .query("sessoes")
+ .filter((q) => q.eq(q.field("ativo"), true))
+ .order("desc")
+ .first();
+ if (sessaoAtiva) {
+ usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
+ }
+ }
+
+ if (!usuarioAtual) throw new Error("acesso_negado");
+
+ const role: any = await ctx.db.get(usuarioAtual.roleId as any);
+ if (!role) throw new Error("acesso_negado");
+ if ((role as any).nivel <= 1) return null;
+
+ const permissao = await ctx.db
+ .query("permissoes")
+ .withIndex("by_recurso_e_acao", (q) =>
+ q.eq("recurso", args.recurso).eq("acao", args.acao)
+ )
+ .first();
+ if (!permissao) throw new Error("acesso_negado");
+
+ const links = await ctx.db
+ .query("rolePermissoes")
+ .withIndex("by_role", (q) => q.eq("roleId", (role as any)._id as any))
+ .collect();
+ const ok = links.some((rp) => rp.permissaoId === permissao!._id);
+ if (!ok) throw new Error("acesso_negado");
+ return null;
+ },
+});
diff --git a/packages/backend/convex/roles.ts b/packages/backend/convex/roles.ts
index ba840db..d4f2d48 100644
--- a/packages/backend/convex/roles.ts
+++ b/packages/backend/convex/roles.ts
@@ -14,7 +14,7 @@ export const listar = query({
descricao: v.string(),
nivel: v.number(),
setor: v.optional(v.string()),
- customizado: v.boolean(),
+ customizado: v.optional(v.boolean()),
editavel: v.optional(v.boolean()),
criadoPor: v.optional(v.id("usuarios")),
})
@@ -45,4 +45,3 @@ export const buscarPorId = query({
return await ctx.db.get(args.roleId);
},
});
-
diff --git a/packages/backend/convex/schema.ts b/packages/backend/convex/schema.ts
index 768db81..744de8e 100644
--- a/packages/backend/convex/schema.ts
+++ b/packages/backend/convex/schema.ts
@@ -1,7 +1,5 @@
import { defineSchema, defineTable } from "convex/server";
import { Infer, v } from "convex/values";
-import { tables } from "./betterAuth/schema";
-import { cidrv4 } from "better-auth";
export const simboloTipo = v.union(
v.literal("cargo_comissionado"),
@@ -358,6 +356,7 @@ export default defineSchema({
acao: v.string(), // "criar", "ler", "editar", "excluir"
})
.index("by_recurso", ["recurso"])
+ .index("by_recurso_e_acao", ["recurso", "acao"])
.index("by_nome", ["nome"]),
rolePermissoes: defineTable({
diff --git a/packages/backend/convex/seed.ts b/packages/backend/convex/seed.ts
index 4b43a3b..29ec545 100644
--- a/packages/backend/convex/seed.ts
+++ b/packages/backend/convex/seed.ts
@@ -337,7 +337,7 @@ export const seedDatabase = internalMutation({
// 2. Criar usuários iniciais
console.log("👤 Criando usuários iniciais...");
-
+
// TI Master
const senhaTIMaster = await hashPassword("TI@123");
await ctx.db.insert("usuarios", {
@@ -370,10 +370,59 @@ export const seedDatabase = internalMutation({
});
console.log(" ✅ Admin criado (matrícula: 2000, senha: Admin@123)");
+ // 2.1 Criar catálogo de permissões por ação e conceder a Admin/TI
+ console.log("🔐 Criando permissões por ação...");
+ const CATALOGO_RECURSOS = [
+ { recurso: "dashboard", acoes: ["ver"] },
+ {
+ recurso: "funcionarios",
+ acoes: ["ver", "listar", "criar", "editar", "excluir"],
+ },
+ {
+ recurso: "simbolos",
+ acoes: ["ver", "listar", "criar", "editar", "excluir"],
+ },
+ {
+ recurso: "usuarios",
+ acoes: ["ver", "listar", "criar", "editar", "excluir"],
+ },
+ {
+ recurso: "perfis",
+ acoes: ["ver", "listar", "criar", "editar", "excluir"],
+ },
+ ] as const;
+
+ const permissaoKeyToId = new Map();
+ for (const item of CATALOGO_RECURSOS) {
+ for (const acao of item.acoes) {
+ const nome = `${item.recurso}.${acao}`;
+ const id = await ctx.db.insert("permissoes", {
+ nome,
+ descricao: `Permite ${acao} em ${item.recurso}`,
+ recurso: item.recurso,
+ acao,
+ });
+ permissaoKeyToId.set(nome, id);
+ }
+ }
+ console.log(` ✅ ${permissaoKeyToId.size} permissões criadas`);
+
+ // Conceder todas permissões a Admin e TI
+ const rolesParaConceder = [roleAdmin, roleTIUsuario, roleTIMaster];
+ for (const roleId of rolesParaConceder) {
+ for (const [, permId] of permissaoKeyToId) {
+ await ctx.db.insert("rolePermissoes", {
+ roleId: roleId as any,
+ permissaoId: permId as any,
+ });
+ }
+ }
+ console.log(" ✅ Todas as permissões concedidas a Admin e TI");
+
// 3. Inserir símbolos
console.log("📝 Inserindo símbolos...");
const simbolosMap = new Map();
-
+
for (const simbolo of simbolosData) {
const id = await ctx.db.insert("simbolos", {
descricao: simbolo.descricao,
@@ -393,7 +442,9 @@ export const seedDatabase = internalMutation({
for (const funcionario of funcionariosData) {
const simboloId = simbolosMap.get(funcionario.simboloNome);
if (!simboloId) {
- console.error(` ❌ Símbolo não encontrado: ${funcionario.simboloNome}`);
+ console.error(
+ ` ❌ Símbolo não encontrado: ${funcionario.simboloNome}`
+ );
continue;
}
@@ -436,7 +487,9 @@ export const seedDatabase = internalMutation({
criadoEm: Date.now(),
atualizadoEm: Date.now(),
});
- console.log(` ✅ Usuário criado: ${funcionario.nome} (senha: Mudar@123)`);
+ console.log(
+ ` ✅ Usuário criado: ${funcionario.nome} (senha: Mudar@123)`
+ );
}
// 6. Inserir solicitações de acesso
@@ -462,28 +515,32 @@ export const seedDatabase = internalMutation({
codigo: "USUARIO_BLOQUEADO",
nome: "Usuário Bloqueado",
titulo: "Sua conta foi bloqueada",
- corpo: "Sua conta no SGSE foi bloqueada.\\n\\nMotivo: {{motivo}}\\n\\nPara mais informações, entre em contato com a TI.",
+ corpo:
+ "Sua conta no SGSE foi bloqueada.\\n\\nMotivo: {{motivo}}\\n\\nPara mais informações, entre em contato com a TI.",
variaveis: ["motivo"],
},
{
codigo: "USUARIO_DESBLOQUEADO",
nome: "Usuário Desbloqueado",
titulo: "Sua conta foi desbloqueada",
- corpo: "Sua conta no SGSE foi desbloqueada e você já pode acessar o sistema normalmente.",
+ corpo:
+ "Sua conta no SGSE foi desbloqueada e você já pode acessar o sistema normalmente.",
variaveis: [],
},
{
codigo: "SENHA_RESETADA",
nome: "Senha Resetada",
titulo: "Sua senha foi resetada",
- corpo: "Sua senha foi resetada pela equipe de TI.\\n\\nNova senha temporária: {{senha}}\\n\\nPor favor, altere sua senha no próximo login.",
+ corpo:
+ "Sua senha foi resetada pela equipe de TI.\\n\\nNova senha temporária: {{senha}}\\n\\nPor favor, altere sua senha no próximo login.",
variaveis: ["senha"],
},
{
codigo: "PERMISSAO_ALTERADA",
nome: "Permissão Alterada",
titulo: "Suas permissões foram atualizadas",
- corpo: "Suas permissões de acesso ao sistema foram atualizadas.\\n\\nPara verificar suas novas permissões, acesse o menu de perfil.",
+ corpo:
+ "Suas permissões de acesso ao sistema foram atualizadas.\\n\\nPara verificar suas novas permissões, acesse o menu de perfil.",
variaveis: [],
},
{
@@ -497,7 +554,8 @@ export const seedDatabase = internalMutation({
codigo: "BEM_VINDO",
nome: "Boas-vindas",
titulo: "Bem-vindo ao SGSE",
- corpo: "Olá {{nome}},\\n\\nSeja bem-vindo ao Sistema de Gestão da Secretaria de Esportes!\\n\\nSuas credenciais de acesso:\\nMatrícula: {{matricula}}\\nSenha temporária: {{senha}}\\n\\nPor favor, altere sua senha no primeiro acesso.\\n\\nEquipe de TI",
+ corpo:
+ "Olá {{nome}},\\n\\nSeja bem-vindo ao Sistema de Gestão da Secretaria de Esportes!\\n\\nSuas credenciais de acesso:\\nMatrícula: {{matricula}}\\nSenha temporária: {{senha}}\\n\\nPor favor, altere sua senha no primeiro acesso.\\n\\nEquipe de TI",
variaveis: ["nome", "matricula", "senha"],
},
];
@@ -584,11 +642,15 @@ export const clearDatabase = internalMutation({
console.log(` ✅ ${menuPermissoes.length} menu-permissões removidas`);
// Limpar menu-permissões personalizadas
- const menuPermissoesPersonalizadas = await ctx.db.query("menuPermissoesPersonalizadas").collect();
+ const menuPermissoesPersonalizadas = await ctx.db
+ .query("menuPermissoesPersonalizadas")
+ .collect();
for (const mpp of menuPermissoesPersonalizadas) {
await ctx.db.delete(mpp._id);
}
- console.log(` ✅ ${menuPermissoesPersonalizadas.length} menu-permissões personalizadas removidas`);
+ console.log(
+ ` ✅ ${menuPermissoesPersonalizadas.length} menu-permissões personalizadas removidas`
+ );
// Limpar role-permissões
const rolePermissoes = await ctx.db.query("rolePermissoes").collect();
@@ -615,4 +677,3 @@ export const clearDatabase = internalMutation({
return null;
},
});
-
diff --git a/packages/backend/convex/usuarios.ts b/packages/backend/convex/usuarios.ts
index 18c3938..1cf0aa3 100644
--- a/packages/backend/convex/usuarios.ts
+++ b/packages/backend/convex/usuarios.ts
@@ -3,6 +3,7 @@ import { mutation, query } from "./_generated/server";
import { hashPassword, generateToken } from "./auth/utils";
import { registrarAtividade } from "./logsAtividades";
import { Id } from "./_generated/dataModel";
+import { api } from "./_generated/api";
/**
* Associar funcionário a um usuário
@@ -23,7 +24,9 @@ export const associarFuncionario = mutation({
// Verificar se o funcionário já está associado a outro usuário
const usuarioExistente = await ctx.db
.query("usuarios")
- .withIndex("by_funcionarioId", (q) => q.eq("funcionarioId", args.funcionarioId))
+ .withIndex("by_funcionarioId", (q) =>
+ q.eq("funcionarioId", args.funcionarioId)
+ )
.first();
if (usuarioExistente && usuarioExistente._id !== args.usuarioId) {
@@ -160,9 +163,7 @@ export const listar = query({
// Filtrar por matrícula
if (args.matricula) {
- usuarios = usuarios.filter((u) =>
- u.matricula.includes(args.matricula!)
- );
+ usuarios = usuarios.filter((u) => u.matricula.includes(args.matricula!));
}
// Filtrar por ativo
@@ -403,9 +404,9 @@ export const atualizarPerfil = mutation({
handler: async (ctx, args) => {
// TENTAR BETTER AUTH PRIMEIRO
const identity = await ctx.auth.getUserIdentity();
-
+
let usuarioAtual = null;
-
+
if (identity && identity.email) {
// Buscar por email (Better Auth)
usuarioAtual = await ctx.db
@@ -413,7 +414,7 @@ export const atualizarPerfil = mutation({
.withIndex("by_email", (q) => q.eq("email", identity.email!))
.first();
}
-
+
// SE NÃO ENCONTROU, BUSCAR POR SESSÃO ATIVA (Sistema customizado)
if (!usuarioAtual) {
const sessaoAtiva = await ctx.db
@@ -421,7 +422,7 @@ export const atualizarPerfil = mutation({
.filter((q) => q.eq(q.field("ativo"), true))
.order("desc")
.first();
-
+
if (sessaoAtiva) {
usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
}
@@ -436,17 +437,20 @@ export const atualizarPerfil = mutation({
// Atualizar apenas os campos fornecidos
const updates: any = { atualizadoEm: Date.now() };
-
+
if (args.avatar !== undefined) updates.avatar = args.avatar;
if (args.fotoPerfil !== undefined) updates.fotoPerfil = args.fotoPerfil;
if (args.setor !== undefined) updates.setor = args.setor;
- if (args.statusMensagem !== undefined) updates.statusMensagem = args.statusMensagem;
+ if (args.statusMensagem !== undefined)
+ updates.statusMensagem = args.statusMensagem;
if (args.statusPresenca !== undefined) {
updates.statusPresenca = args.statusPresenca;
updates.ultimaAtividade = Date.now();
}
- if (args.notificacoesAtivadas !== undefined) updates.notificacoesAtivadas = args.notificacoesAtivadas;
- if (args.somNotificacao !== undefined) updates.somNotificacao = args.somNotificacao;
+ if (args.notificacoesAtivadas !== undefined)
+ updates.notificacoesAtivadas = args.notificacoesAtivadas;
+ if (args.somNotificacao !== undefined)
+ updates.somNotificacao = args.somNotificacao;
await ctx.db.patch(usuarioAtual._id, updates);
@@ -471,13 +475,15 @@ export const obterPerfil = query({
fotoPerfilUrl: v.union(v.string(), v.null()),
setor: v.optional(v.string()),
statusMensagem: v.optional(v.string()),
- statusPresenca: v.optional(v.union(
- v.literal("online"),
- v.literal("offline"),
- v.literal("ausente"),
- v.literal("externo"),
- v.literal("em_reuniao")
- )),
+ statusPresenca: v.optional(
+ v.union(
+ v.literal("online"),
+ v.literal("offline"),
+ v.literal("ausente"),
+ v.literal("externo"),
+ v.literal("em_reuniao")
+ )
+ ),
notificacoesAtivadas: v.boolean(),
somNotificacao: v.boolean(),
}),
@@ -485,13 +491,13 @@ export const obterPerfil = query({
),
handler: async (ctx) => {
console.log("=== DEBUG obterPerfil ===");
-
+
// TENTAR BETTER AUTH PRIMEIRO
const identity = await ctx.auth.getUserIdentity();
console.log("Identity:", identity ? "encontrado" : "null");
-
+
let usuarioAtual = null;
-
+
if (identity && identity.email) {
console.log("Tentando buscar por email:", identity.email);
// Buscar por email (Better Auth)
@@ -499,10 +505,13 @@ export const obterPerfil = query({
.query("usuarios")
.withIndex("by_email", (q) => q.eq("email", identity.email!))
.first();
-
- console.log("Usuário encontrado por email:", usuarioAtual ? "SIM" : "NÃO");
+
+ console.log(
+ "Usuário encontrado por email:",
+ usuarioAtual ? "SIM" : "NÃO"
+ );
}
-
+
// SE NÃO ENCONTROU, BUSCAR POR SESSÃO ATIVA (Sistema customizado)
if (!usuarioAtual) {
console.log("Buscando por sessão ativa...");
@@ -511,24 +520,30 @@ export const obterPerfil = query({
.filter((q) => q.eq(q.field("ativo"), true))
.order("desc")
.first();
-
+
console.log("Sessão ativa encontrada:", sessaoAtiva ? "SIM" : "NÃO");
-
+
if (sessaoAtiva) {
usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
- console.log("Usuário da sessão encontrado:", usuarioAtual ? "SIM" : "NÃO");
+ console.log(
+ "Usuário da sessão encontrado:",
+ usuarioAtual ? "SIM" : "NÃO"
+ );
}
}
-
+
if (!usuarioAtual) {
console.log("❌ Nenhum usuário encontrado");
// Listar todos os usuários para debug
const todosUsuarios = await ctx.db.query("usuarios").collect();
console.log("Total de usuários no banco:", todosUsuarios.length);
- console.log("Emails cadastrados:", todosUsuarios.map(u => u.email));
+ console.log(
+ "Emails cadastrados:",
+ todosUsuarios.map((u) => u.email)
+ );
return null;
}
-
+
console.log("✅ Usuário encontrado:", usuarioAtual.nome);
// Buscar fotoPerfil URL se existir
@@ -621,12 +636,13 @@ export const listarParaChat = query({
*/
export const uploadFotoPerfil = mutation({
args: {},
+ returns: v.string(),
handler: async (ctx) => {
// TENTAR BETTER AUTH PRIMEIRO
const identity = await ctx.auth.getUserIdentity();
-
+
let usuarioAtual = null;
-
+
if (identity && identity.email) {
// Buscar por email (Better Auth)
usuarioAtual = await ctx.db
@@ -634,7 +650,7 @@ export const uploadFotoPerfil = mutation({
.withIndex("by_email", (q) => q.eq("email", identity.email!))
.first();
}
-
+
// SE NÃO ENCONTROU, BUSCAR POR SESSÃO ATIVA (Sistema customizado)
if (!usuarioAtual) {
const sessaoAtiva = await ctx.db
@@ -642,7 +658,7 @@ export const uploadFotoPerfil = mutation({
.filter((q) => q.eq(q.field("ativo"), true))
.order("desc")
.first();
-
+
if (sessaoAtiva) {
usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
}
@@ -822,7 +838,8 @@ export const resetarSenhaUsuario = mutation({
// Helper para gerar senha temporária
function gerarSenhaTemporaria(): string {
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%";
+ const chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%";
let senha = "";
for (let i = 0; i < 12; i++) {
senha += chars.charAt(Math.floor(Math.random() * chars.length));
@@ -890,6 +907,116 @@ export const editarUsuario = mutation({
},
});
+/**
+ * Criar/Promover usuário Admin Master (TI_MASTER - nível 0)
+ */
+export const criarAdminMaster = mutation({
+ args: {
+ matricula: v.string(),
+ nome: v.string(),
+ email: v.string(),
+ senha: v.optional(v.string()),
+ },
+ returns: v.union(
+ v.object({
+ sucesso: v.literal(true),
+ usuarioId: v.id("usuarios"),
+ senhaTemporaria: v.string(),
+ }),
+ v.object({ sucesso: v.literal(false), erro: v.string() })
+ ),
+ handler: async (ctx, args) => {
+ // Garantir que a role TI_MASTER exista (nível 0)
+ let roleTIMaster = await ctx.db
+ .query("roles")
+ .withIndex("by_nome", (q) => q.eq("nome", "ti_master"))
+ .first();
+
+ if (!roleTIMaster) {
+ const roleId = await ctx.db.insert("roles", {
+ nome: "ti_master",
+ descricao: "TI Master",
+ nivel: 0,
+ setor: "ti",
+ customizado: false,
+ editavel: false,
+ });
+ roleTIMaster = await ctx.db.get(roleId);
+ }
+
+ if (!roleTIMaster) {
+ return {
+ sucesso: false as const,
+ erro: "Falha ao garantir role TI Master",
+ };
+ }
+
+ // Se já existir usuário por matrícula, promove/atualiza
+ const existentePorMatricula = await ctx.db
+ .query("usuarios")
+ .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
+ .first();
+
+ const senhaTemporaria = args.senha || gerarSenhaTemporaria();
+ const senhaHash = await hashPassword(senhaTemporaria);
+
+ if (existentePorMatricula) {
+ await ctx.db.patch(existentePorMatricula._id, {
+ nome: args.nome,
+ email: args.email,
+ senhaHash,
+ roleId: roleTIMaster._id,
+ ativo: true,
+ primeiroAcesso: true,
+ atualizadoEm: Date.now(),
+ });
+ return {
+ sucesso: true as const,
+ usuarioId: existentePorMatricula._id,
+ senhaTemporaria,
+ };
+ }
+
+ // Verificar se email já existe
+ const existentePorEmail = await ctx.db
+ .query("usuarios")
+ .withIndex("by_email", (q) => q.eq("email", args.email))
+ .first();
+ if (existentePorEmail) {
+ // Promove usuário existente por email
+ await ctx.db.patch(existentePorEmail._id, {
+ matricula: args.matricula,
+ nome: args.nome,
+ senhaHash,
+ roleId: roleTIMaster._id,
+ ativo: true,
+ primeiroAcesso: true,
+ atualizadoEm: Date.now(),
+ });
+ return {
+ sucesso: true as const,
+ usuarioId: existentePorEmail._id,
+ senhaTemporaria,
+ };
+ }
+
+ // Criar novo usuário TI Master
+ const usuarioId = await ctx.db.insert("usuarios", {
+ matricula: args.matricula,
+ senhaHash,
+ nome: args.nome,
+ email: args.email,
+ roleId: roleTIMaster._id,
+ ativo: true,
+ primeiroAcesso: true,
+ criadoEm: Date.now(),
+ atualizadoEm: Date.now(),
+ });
+
+ return { sucesso: true as const, usuarioId, senhaTemporaria };
+ },
+});
+
/**
* Desativar usuário logicamente (soft delete - apenas TI_MASTER)
*/
@@ -954,7 +1081,11 @@ export const criarUsuarioCompleto = mutation({
enviarEmailBoasVindas: v.optional(v.boolean()),
},
returns: v.union(
- v.object({ sucesso: v.literal(true), usuarioId: v.id("usuarios"), senhaTemporaria: v.string() }),
+ v.object({
+ sucesso: v.literal(true),
+ usuarioId: v.id("usuarios"),
+ senhaTemporaria: v.string(),
+ }),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args) => {
@@ -1013,3 +1144,85 @@ export const criarUsuarioCompleto = mutation({
},
});
+/**
+ * Criar (ou garantir) um usuário ADMIN padrão
+ */
+export const criarAdminPadrao = mutation({
+ args: {
+ matricula: v.optional(v.string()),
+ nome: v.optional(v.string()),
+ email: v.optional(v.string()),
+ senha: v.optional(v.string()),
+ },
+ returns: v.object({
+ sucesso: v.boolean(),
+ usuarioId: v.optional(v.id("usuarios")),
+ }),
+ handler: async (ctx, args) => {
+ const matricula = args.matricula ?? "0000";
+ const nome = args.nome ?? "Administrador Geral";
+ const email = args.email ?? "admin@sgse.pe.gov.br";
+ const senha = args.senha ?? "Admin@123";
+
+ // Garantir role ADMIN (nível 2)
+ let roleAdmin = await ctx.db
+ .query("roles")
+ .withIndex("by_nome", (q) => q.eq("nome", "admin"))
+ .first();
+ if (!roleAdmin) {
+ const roleId = await ctx.db.insert("roles", {
+ nome: "admin",
+ descricao: "Administrador Geral",
+ nivel: 2,
+ setor: "administrativo",
+ customizado: false,
+ editavel: true,
+ });
+ roleAdmin = await ctx.db.get(roleId);
+ }
+
+ if (!roleAdmin) return { sucesso: false };
+
+ // Verificar se já existe por matrícula ou email
+ const existentePorMatricula = await ctx.db
+ .query("usuarios")
+ .withIndex("by_matricula", (q) => q.eq("matricula", matricula))
+ .first();
+
+ const existentePorEmail = await ctx.db
+ .query("usuarios")
+ .withIndex("by_email", (q) => q.eq("email", email))
+ .first();
+
+ const senhaHash = await hashPassword(senha);
+
+ if (existentePorMatricula || existentePorEmail) {
+ const alvo = existentePorMatricula ?? existentePorEmail!;
+ await ctx.db.patch(alvo._id, {
+ matricula,
+ nome,
+ email,
+ senhaHash,
+ roleId: roleAdmin._id,
+ ativo: true,
+ primeiroAcesso: false,
+ atualizadoEm: Date.now(),
+ });
+ return { sucesso: true, usuarioId: alvo._id };
+ }
+
+ const usuarioId = await ctx.db.insert("usuarios", {
+ matricula,
+ senhaHash,
+ nome,
+ email,
+ roleId: roleAdmin._id,
+ ativo: true,
+ primeiroAcesso: false,
+ criadoEm: Date.now(),
+ atualizadoEm: Date.now(),
+ });
+
+ return { sucesso: true, usuarioId };
+ },
+});
diff --git a/packages/backend/package.json b/packages/backend/package.json
index ea8050c..dc60e84 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -20,10 +20,8 @@
"typescript": "^5.9.2"
},
"dependencies": {
- "@convex-dev/better-auth": "^0.9.6",
"@dicebear/avataaars": "^9.2.4",
- "better-auth": "1.3.27",
"convex": "^1.28.0",
"nodemailer": "^7.0.10"
}
-}
+}
\ No newline at end of file