feat: integrate Better Auth and enhance authentication flow

- Added Better Auth integration to the web application, allowing for dual login support with both custom and Better Auth systems.
- Updated authentication client configuration to dynamically set the base URL based on the environment.
- Enhanced chat components to utilize user authentication status, improving user experience and security.
- Refactored various components to support Better Auth, including error handling and user identity management.
- Improved notification handling and user feedback mechanisms during authentication processes.
This commit is contained in:
2025-11-06 09:35:36 -03:00
parent 33f305220b
commit 06f03b53e5
28 changed files with 4109 additions and 436 deletions

View File

@@ -3,16 +3,115 @@
import Sidebar from "$lib/components/Sidebar.svelte";
import { PUBLIC_CONVEX_URL } from "$env/static/public";
import { setupConvex } from "convex-svelte";
// import { createSvelteAuthClient } from "@mmailaender/convex-better-auth-svelte/svelte";
// import { authClient } from "$lib/auth";
import { authStore } from "$lib/stores/auth.svelte";
import { browser } from "$app/environment";
import { createSvelteAuthClient } from "@mmailaender/convex-better-auth-svelte/svelte";
import { authClient } from "$lib/auth";
const { children } = $props();
// Configurar Convex para usar o backend local
// Interfaces TypeScript devem estar no nível superior
interface ConvexHttpClientPrototype {
_authPatched?: boolean;
mutation?: (...args: unknown[]) => Promise<unknown>;
query?: (...args: unknown[]) => Promise<unknown>;
setAuth?: (token: string) => void;
}
interface WindowWithConvexClients extends Window {
__convexClients?: Array<{ setAuth?: (token: string) => void }>;
}
// Configurar Convex
setupConvex(PUBLIC_CONVEX_URL);
// Configurar cliente de autenticação
// createSvelteAuthClient({ authClient });
// CORREÇÃO CRÍTICA: Configurar token no cliente Convex após setup
// O convex-svelte usa WebSocket, então precisamos configurar via setAuth
if (browser) {
// Aguardar setupConvex inicializar e então configurar token
$effect(() => {
const token = authStore.token;
if (!token) return;
// Aguardar um pouco para garantir que setupConvex inicializou
setTimeout(() => {
// Tentar acessar o cliente Convex interno do convex-svelte
// O convex-svelte pode usar uma instância interna, então vamos tentar várias abordagens
// Abordagem 1: Interceptar WebSocket para adicionar token como query param
const originalWebSocket = window.WebSocket;
if (!(window as { _convexWsPatched?: boolean })._convexWsPatched) {
window.WebSocket = class extends originalWebSocket {
constructor(url: string | URL, protocols?: string | string[]) {
const wsUrl = typeof url === 'string' ? url : url.href;
// Se for conexão Convex e tivermos token, adicionar como query param
if ((wsUrl.includes(PUBLIC_CONVEX_URL) || wsUrl.includes('convex.cloud')) && token) {
try {
const urlObj = new URL(wsUrl);
if (!urlObj.searchParams.has('authToken')) {
urlObj.searchParams.set('authToken', token);
super(urlObj.href, protocols);
if (import.meta.env.DEV) {
console.log("✅ [Convex Auth] Token adicionado ao WebSocket:", token.substring(0, 20) + "...");
}
return;
}
} catch (e) {
// Se falhar, usar URL original
}
}
super(url, protocols);
}
} as typeof WebSocket;
(window as { _convexWsPatched?: boolean })._convexWsPatched = true;
console.log("✅ [Convex Auth] Interceptador WebSocket configurado");
}
// Abordagem 2: Interceptar fetch para requisições HTTP (fallback)
const originalFetch = window.fetch;
if (!(window as { _convexFetchPatched?: boolean })._convexFetchPatched) {
window.fetch = function(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
const currentToken = authStore.token;
if (currentToken && (url.includes(PUBLIC_CONVEX_URL) || url.includes('convex.cloud'))) {
const headers = new Headers(init?.headers);
if (!headers.has('authorization')) {
headers.set('authorization', `Bearer ${currentToken}`);
}
return originalFetch(input, {
...init,
headers: headers,
});
}
return originalFetch(input, init);
};
(window as { _convexFetchPatched?: boolean })._convexFetchPatched = true;
console.log("✅ [Convex Auth] Interceptador Fetch configurado");
}
}, 300);
});
}
// FASE 4: Integração Better Auth com Convex
// Better Auth agora está configurado e ativo
// Usar $effect para garantir que seja executado apenas no cliente
if (browser) {
$effect(() => {
try {
createSvelteAuthClient({ authClient });
} catch (error) {
console.warn("⚠️ [Better Auth] Erro ao inicializar cliente:", error);
}
});
}
</script>
<div>

View File

@@ -1,3 +1,8 @@
import { createSvelteKitHandler } from "@mmailaender/convex-better-auth-svelte/sveltekit";
import { PUBLIC_CONVEX_URL } from "$env/static/public";
export const { GET, POST } = createSvelteKitHandler();
// PUBLIC_CONVEX_SITE_URL é necessário para o Better Auth handler
// Se não estiver definido, usar PUBLIC_CONVEX_URL como fallback
export const { GET, POST } = createSvelteKitHandler({
convexSiteUrl: PUBLIC_CONVEX_URL,
});