initial better auth config
This commit is contained in:
12
apps/web/src/app.d.ts
vendored
12
apps/web/src/app.d.ts
vendored
@@ -1,13 +1,7 @@
|
|||||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
|
||||||
// for information about these interfaces
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace App {
|
namespace App {
|
||||||
// interface Error {}
|
interface Locals {
|
||||||
// interface Locals {}
|
token: string | undefined;
|
||||||
// interface PageData {}
|
}
|
||||||
// interface PageState {}
|
|
||||||
// interface Platform {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Handle } from "@sveltejs/kit";
|
import type { Handle } from "@sveltejs/kit";
|
||||||
|
import { getToken } from "@mmailaender/convex-better-auth-svelte/sveltekit";
|
||||||
// Middleware desabilitado - proteção de rotas feita no lado do cliente
|
import { createAuth } from "@sgse-app/backend/convex/auth";
|
||||||
// para compatibilidade com localStorage do authStore
|
|
||||||
|
|
||||||
export const handle: Handle = async ({ event, resolve }) => {
|
export const handle: Handle = async ({ event, resolve }) => {
|
||||||
|
event.locals.token = await getToken(createAuth, event.cookies);
|
||||||
|
|
||||||
return resolve(event);
|
return resolve(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,18 +4,10 @@
|
|||||||
* Configurado para trabalhar com Convex via plugin convexClient.
|
* Configurado para trabalhar com Convex via plugin convexClient.
|
||||||
* Este cliente será usado para autenticação quando Better Auth estiver ativo.
|
* Este cliente será usado para autenticação quando Better Auth estiver ativo.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createAuthClient } from "better-auth/svelte";
|
import { createAuthClient } from "better-auth/svelte";
|
||||||
import { convexClient } from "@convex-dev/better-auth/client/plugins";
|
import { convexClient } from "@convex-dev/better-auth/client/plugins";
|
||||||
|
|
||||||
export const authClient = createAuthClient({
|
export const authClient = createAuthClient({
|
||||||
// Base URL da API Better Auth (mesma do app)
|
plugins: [convexClient()],
|
||||||
baseURL: typeof window !== "undefined"
|
|
||||||
? window.location.origin // Usar origem atual em produção
|
|
||||||
: "http://localhost:5173", // Fallback para desenvolvimento
|
|
||||||
plugins: [
|
|
||||||
// Plugin Convex integra Better Auth com Convex backend
|
|
||||||
convexClient({
|
|
||||||
convexUrl: import.meta.env.PUBLIC_CONVEX_URL || "",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,117 +1,118 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "../app.css";
|
import "../app.css";
|
||||||
import Sidebar from "$lib/components/Sidebar.svelte";
|
import Sidebar from "$lib/components/Sidebar.svelte";
|
||||||
import { PUBLIC_CONVEX_URL } from "$env/static/public";
|
// import { PUBLIC_CONVEX_URL } from "$env/static/public";
|
||||||
import { setupConvex } from "convex-svelte";
|
// import { setupConvex } from "convex-svelte";
|
||||||
import { authStore } from "$lib/stores/auth.svelte";
|
// import { authStore } from "$lib/stores/auth.svelte";
|
||||||
import { browser } from "$app/environment";
|
// import { browser } from "$app/environment";
|
||||||
import { createSvelteAuthClient } from "@mmailaender/convex-better-auth-svelte/svelte";
|
import { createSvelteAuthClient } from "@mmailaender/convex-better-auth-svelte/svelte";
|
||||||
import { authClient } from "$lib/auth";
|
import { authClient } from "$lib/auth";
|
||||||
|
|
||||||
const { children } = $props();
|
const { children } = $props();
|
||||||
|
|
||||||
// Interfaces TypeScript devem estar no nível superior
|
// Interfaces TypeScript devem estar no nível superior
|
||||||
interface ConvexHttpClientPrototype {
|
// interface ConvexHttpClientPrototype {
|
||||||
_authPatched?: boolean;
|
// _authPatched?: boolean;
|
||||||
mutation?: (...args: unknown[]) => Promise<unknown>;
|
// mutation?: (...args: unknown[]) => Promise<unknown>;
|
||||||
query?: (...args: unknown[]) => Promise<unknown>;
|
// query?: (...args: unknown[]) => Promise<unknown>;
|
||||||
setAuth?: (token: string) => void;
|
// setAuth?: (token: string) => void;
|
||||||
}
|
// }
|
||||||
|
|
||||||
interface WindowWithConvexClients extends Window {
|
// interface WindowWithConvexClients extends Window {
|
||||||
__convexClients?: Array<{ setAuth?: (token: string) => void }>;
|
// __convexClients?: Array<{ setAuth?: (token: string) => void }>;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Configurar Convex
|
// Configurar Convex
|
||||||
setupConvex(PUBLIC_CONVEX_URL);
|
createSvelteAuthClient({ authClient });
|
||||||
|
// setupConvex(PUBLIC_CONVEX_URL);
|
||||||
|
|
||||||
// CORREÇÃO CRÍTICA: Configurar token no cliente Convex após setup
|
// CORREÇÃO CRÍTICA: Configurar token no cliente Convex após setup
|
||||||
// O convex-svelte usa WebSocket, então precisamos configurar via setAuth
|
// O convex-svelte usa WebSocket, então precisamos configurar via setAuth
|
||||||
if (browser) {
|
// if (browser) {
|
||||||
// Aguardar setupConvex inicializar e então configurar token
|
// // Aguardar setupConvex inicializar e então configurar token
|
||||||
$effect(() => {
|
// $effect(() => {
|
||||||
const token = authStore.token;
|
// const token = authStore.token;
|
||||||
|
|
||||||
if (!token) return;
|
// if (!token) return;
|
||||||
|
|
||||||
// Aguardar um pouco para garantir que setupConvex inicializou
|
// // Aguardar um pouco para garantir que setupConvex inicializou
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
// Tentar acessar o cliente Convex interno do convex-svelte
|
// // 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
|
// // 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
|
// // Abordagem 1: Interceptar WebSocket para adicionar token como query param
|
||||||
const originalWebSocket = window.WebSocket;
|
// const originalWebSocket = window.WebSocket;
|
||||||
if (!(window as { _convexWsPatched?: boolean })._convexWsPatched) {
|
// if (!(window as { _convexWsPatched?: boolean })._convexWsPatched) {
|
||||||
window.WebSocket = class extends originalWebSocket {
|
// window.WebSocket = class extends originalWebSocket {
|
||||||
constructor(url: string | URL, protocols?: string | string[]) {
|
// constructor(url: string | URL, protocols?: string | string[]) {
|
||||||
const wsUrl = typeof url === 'string' ? url : url.href;
|
// const wsUrl = typeof url === 'string' ? url : url.href;
|
||||||
|
|
||||||
// Se for conexão Convex e tivermos token, adicionar como query param
|
// // Se for conexão Convex e tivermos token, adicionar como query param
|
||||||
if ((wsUrl.includes(PUBLIC_CONVEX_URL) || wsUrl.includes('convex.cloud')) && token) {
|
// if ((wsUrl.includes(PUBLIC_CONVEX_URL) || wsUrl.includes('convex.cloud')) && token) {
|
||||||
try {
|
// try {
|
||||||
const urlObj = new URL(wsUrl);
|
// const urlObj = new URL(wsUrl);
|
||||||
if (!urlObj.searchParams.has('authToken')) {
|
// if (!urlObj.searchParams.has('authToken')) {
|
||||||
urlObj.searchParams.set('authToken', token);
|
// urlObj.searchParams.set('authToken', token);
|
||||||
super(urlObj.href, protocols);
|
// super(urlObj.href, protocols);
|
||||||
if (import.meta.env.DEV) {
|
// if (import.meta.env.DEV) {
|
||||||
console.log("✅ [Convex Auth] Token adicionado ao WebSocket:", token.substring(0, 20) + "...");
|
// console.log("✅ [Convex Auth] Token adicionado ao WebSocket:", token.substring(0, 20) + "...");
|
||||||
}
|
// }
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
// Se falhar, usar URL original
|
// // Se falhar, usar URL original
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
super(url, protocols);
|
// super(url, protocols);
|
||||||
}
|
// }
|
||||||
} as typeof WebSocket;
|
// } as typeof WebSocket;
|
||||||
|
|
||||||
(window as { _convexWsPatched?: boolean })._convexWsPatched = true;
|
// (window as { _convexWsPatched?: boolean })._convexWsPatched = true;
|
||||||
console.log("✅ [Convex Auth] Interceptador WebSocket configurado");
|
// console.log("✅ [Convex Auth] Interceptador WebSocket configurado");
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Abordagem 2: Interceptar fetch para requisições HTTP (fallback)
|
// // Abordagem 2: Interceptar fetch para requisições HTTP (fallback)
|
||||||
const originalFetch = window.fetch;
|
// const originalFetch = window.fetch;
|
||||||
if (!(window as { _convexFetchPatched?: boolean })._convexFetchPatched) {
|
// if (!(window as { _convexFetchPatched?: boolean })._convexFetchPatched) {
|
||||||
window.fetch = function(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
// window.fetch = function(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
||||||
const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
|
// const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
|
||||||
const currentToken = authStore.token;
|
// const currentToken = authStore.token;
|
||||||
|
|
||||||
if (currentToken && (url.includes(PUBLIC_CONVEX_URL) || url.includes('convex.cloud'))) {
|
// if (currentToken && (url.includes(PUBLIC_CONVEX_URL) || url.includes('convex.cloud'))) {
|
||||||
const headers = new Headers(init?.headers);
|
// const headers = new Headers(init?.headers);
|
||||||
if (!headers.has('authorization')) {
|
// if (!headers.has('authorization')) {
|
||||||
headers.set('authorization', `Bearer ${currentToken}`);
|
// headers.set('authorization', `Bearer ${currentToken}`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return originalFetch(input, {
|
// return originalFetch(input, {
|
||||||
...init,
|
// ...init,
|
||||||
headers: headers,
|
// headers: headers,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return originalFetch(input, init);
|
// return originalFetch(input, init);
|
||||||
};
|
// };
|
||||||
|
|
||||||
(window as { _convexFetchPatched?: boolean })._convexFetchPatched = true;
|
// (window as { _convexFetchPatched?: boolean })._convexFetchPatched = true;
|
||||||
console.log("✅ [Convex Auth] Interceptador Fetch configurado");
|
// console.log("✅ [Convex Auth] Interceptador Fetch configurado");
|
||||||
}
|
// }
|
||||||
}, 300);
|
// }, 300);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
// FASE 4: Integração Better Auth com Convex
|
// FASE 4: Integração Better Auth com Convex
|
||||||
// Better Auth agora está configurado e ativo
|
// Better Auth agora está configurado e ativo
|
||||||
// Usar $effect para garantir que seja executado apenas no cliente
|
// Usar $effect para garantir que seja executado apenas no cliente
|
||||||
if (browser) {
|
// if (browser) {
|
||||||
$effect(() => {
|
// $effect(() => {
|
||||||
try {
|
// try {
|
||||||
createSvelteAuthClient({ authClient });
|
// createSvelteAuthClient({ authClient });
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.warn("⚠️ [Better Auth] Erro ao inicializar cliente:", error);
|
// console.warn("⚠️ [Better Auth] Erro ao inicializar cliente:", error);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
11
bun.lock
11
bun.lock
@@ -67,6 +67,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@convex-dev/better-auth": "^0.9.7",
|
"@convex-dev/better-auth": "^0.9.7",
|
||||||
"@dicebear/avataaars": "^9.2.4",
|
"@dicebear/avataaars": "^9.2.4",
|
||||||
|
"better-auth": "1.3.27",
|
||||||
"convex": "catalog:",
|
"convex": "catalog:",
|
||||||
"nodemailer": "^7.0.10",
|
"nodemailer": "^7.0.10",
|
||||||
},
|
},
|
||||||
@@ -152,7 +153,7 @@
|
|||||||
|
|
||||||
"@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="],
|
"@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="],
|
||||||
|
|
||||||
"@better-auth/core": ["@better-auth/core@1.3.34", "", { "dependencies": { "zod": "^4.1.5" }, "peerDependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18", "better-call": "1.0.19", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" } }, "sha512-rt/Bgl0Xa8OQ2DUMKCZEJ8vL9kUw4NCJsBP9Sj9uRhbsK8NEMPiznUOFMkUY2FvrslvfKN7H/fivwyHz9c7HzQ=="],
|
"@better-auth/core": ["@better-auth/core@1.3.27", "", { "dependencies": { "better-call": "1.0.19", "zod": "^4.1.5" } }, "sha512-3Sfdax6MQyronY+znx7bOsfQHI6m1SThvJWb0RDscFEAhfqLy95k1sl+/PgGyg0cwc2cUXoEiAOSqYdFYrg3vA=="],
|
||||||
|
|
||||||
"@better-auth/telemetry": ["@better-auth/telemetry@1.3.34", "", { "dependencies": { "@better-auth/core": "1.3.34", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18" } }, "sha512-aQZ3wN90YMqV49diWxAMe1k7s2qb55KCsedCZne5PlgCjU4s3YtnqyjC5FEpzw2KY8l8rvR7DMAsDl13NjObKA=="],
|
"@better-auth/telemetry": ["@better-auth/telemetry@1.3.34", "", { "dependencies": { "@better-auth/core": "1.3.34", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18" } }, "sha512-aQZ3wN90YMqV49diWxAMe1k7s2qb55KCsedCZne5PlgCjU4s3YtnqyjC5FEpzw2KY8l8rvR7DMAsDl13NjObKA=="],
|
||||||
|
|
||||||
@@ -574,7 +575,7 @@
|
|||||||
|
|
||||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q=="],
|
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q=="],
|
||||||
|
|
||||||
"better-auth": ["better-auth@1.3.34", "", { "dependencies": { "@better-auth/core": "1.3.34", "@better-auth/telemetry": "1.3.34", "@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-LWA52SlvnUBJRbN8VLSTLILPomZY3zZAiLxVJCeSQ5uVmaIKkMBhERitkfJcXB9RJcfl4uP+3EqKkb6hX1/uiw=="],
|
"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=="],
|
"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=="],
|
||||||
|
|
||||||
@@ -840,6 +841,8 @@
|
|||||||
|
|
||||||
"@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=="],
|
"@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=="],
|
||||||
|
|
||||||
|
"@better-auth/telemetry/@better-auth/core": ["@better-auth/core@1.3.34", "", { "dependencies": { "zod": "^4.1.5" }, "peerDependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18", "better-call": "1.0.19", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" } }, "sha512-rt/Bgl0Xa8OQ2DUMKCZEJ8vL9kUw4NCJsBP9Sj9uRhbsK8NEMPiznUOFMkUY2FvrslvfKN7H/fivwyHz9c7HzQ=="],
|
||||||
|
|
||||||
"@convex-dev/better-auth/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
"@convex-dev/better-auth/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||||
|
|
||||||
"@sveltejs/kit/@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
|
"@sveltejs/kit/@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
|
||||||
@@ -862,6 +865,8 @@
|
|||||||
|
|
||||||
"tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
|
"tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
|
||||||
|
|
||||||
|
"web/better-auth": ["better-auth@1.3.34", "", { "dependencies": { "@better-auth/core": "1.3.34", "@better-auth/telemetry": "1.3.34", "@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-LWA52SlvnUBJRbN8VLSTLILPomZY3zZAiLxVJCeSQ5uVmaIKkMBhERitkfJcXB9RJcfl4uP+3EqKkb6hX1/uiw=="],
|
||||||
|
|
||||||
"@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=="],
|
"@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=="],
|
||||||
|
|
||||||
"@aws-crypto/util/@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=="],
|
"@aws-crypto/util/@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=="],
|
||||||
@@ -916,6 +921,8 @@
|
|||||||
|
|
||||||
"convex/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
|
"convex/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
|
||||||
|
|
||||||
|
"web/better-auth/@better-auth/core": ["@better-auth/core@1.3.34", "", { "dependencies": { "zod": "^4.1.5" }, "peerDependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18", "better-call": "1.0.19", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" } }, "sha512-rt/Bgl0Xa8OQ2DUMKCZEJ8vL9kUw4NCJsBP9Sj9uRhbsK8NEMPiznUOFMkUY2FvrslvfKN7H/fivwyHz9c7HzQ=="],
|
||||||
|
|
||||||
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||||
|
|
||||||
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||||
|
|||||||
1166
packages/backend/convex/_generated/api.d.ts
vendored
1166
packages/backend/convex/_generated/api.d.ts
vendored
File diff suppressed because it is too large
Load Diff
8
packages/backend/convex/auth.config.ts
Normal file
8
packages/backend/convex/auth.config.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
domain: process.env.CONVEX_SITE_URL,
|
||||||
|
applicationID: "convex",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
53
packages/backend/convex/auth.ts
Normal file
53
packages/backend/convex/auth.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
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 authSchema from "./betterAuth/schema";
|
||||||
|
|
||||||
|
const siteUrl = process.env.SITE_URL!;
|
||||||
|
|
||||||
|
// The component client has methods needed for integrating Convex with Better Auth,
|
||||||
|
// as well as helper methods for general use.
|
||||||
|
export const authComponent = createClient<DataModel, typeof authSchema>(
|
||||||
|
components.betterAuth,
|
||||||
|
{
|
||||||
|
local: {
|
||||||
|
schema: authSchema,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const createAuth = (
|
||||||
|
ctx: GenericCtx<DataModel>,
|
||||||
|
{ optionsOnly } = { optionsOnly: false }
|
||||||
|
) => {
|
||||||
|
return betterAuth({
|
||||||
|
// 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);
|
||||||
|
},
|
||||||
|
});
|
||||||
993
packages/backend/convex/betterAuth/_generated/api.d.ts
vendored
Normal file
993
packages/backend/convex/betterAuth/_generated/api.d.ts
vendored
Normal file
@@ -0,0 +1,993 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated `api` utility.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type * as adapter from "../adapter.js";
|
||||||
|
import type * as auth from "../auth.js";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ApiFromModules,
|
||||||
|
FilterApi,
|
||||||
|
FunctionReference,
|
||||||
|
} from "convex/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility for referencing Convex functions in your app's API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```js
|
||||||
|
* const myFunctionReference = api.myModule.myFunction;
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
declare const fullApi: ApiFromModules<{
|
||||||
|
adapter: typeof adapter;
|
||||||
|
auth: typeof auth;
|
||||||
|
}>;
|
||||||
|
export type Mounts = {
|
||||||
|
adapter: {
|
||||||
|
create: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"public",
|
||||||
|
{
|
||||||
|
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<string>;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
deleteMany: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"public",
|
||||||
|
{
|
||||||
|
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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onDeleteHandle?: string;
|
||||||
|
paginationOpts: {
|
||||||
|
cursor: string | null;
|
||||||
|
endCursor?: string | null;
|
||||||
|
id?: number;
|
||||||
|
maximumBytesRead?: number;
|
||||||
|
maximumRowsRead?: number;
|
||||||
|
numItems: number;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
deleteOne: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"public",
|
||||||
|
{
|
||||||
|
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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onDeleteHandle?: string;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
findMany: FunctionReference<
|
||||||
|
"query",
|
||||||
|
"public",
|
||||||
|
{
|
||||||
|
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<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
findOne: FunctionReference<
|
||||||
|
"query",
|
||||||
|
"public",
|
||||||
|
{
|
||||||
|
model: "user" | "session" | "account" | "verification" | "jwks";
|
||||||
|
select?: Array<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<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
updateMany: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"public",
|
||||||
|
{
|
||||||
|
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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onUpdateHandle?: string;
|
||||||
|
paginationOpts: {
|
||||||
|
cursor: string | null;
|
||||||
|
endCursor?: string | null;
|
||||||
|
id?: number;
|
||||||
|
maximumBytesRead?: number;
|
||||||
|
maximumRowsRead?: number;
|
||||||
|
numItems: number;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
updateOne: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"public",
|
||||||
|
{
|
||||||
|
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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| 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<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onUpdateHandle?: string;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// For now fullApiWithMounts is only fullApi which provides
|
||||||
|
// jump-to-definition in component client code.
|
||||||
|
// Use Mounts for the same type without the inference.
|
||||||
|
declare const fullApiWithMounts: typeof fullApi;
|
||||||
|
|
||||||
|
export declare const api: FilterApi<
|
||||||
|
typeof fullApiWithMounts,
|
||||||
|
FunctionReference<any, "public">
|
||||||
|
>;
|
||||||
|
export declare const internal: FilterApi<
|
||||||
|
typeof fullApiWithMounts,
|
||||||
|
FunctionReference<any, "internal">
|
||||||
|
>;
|
||||||
|
|
||||||
|
export declare const components: {};
|
||||||
23
packages/backend/convex/betterAuth/_generated/api.js
Normal file
23
packages/backend/convex/betterAuth/_generated/api.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated `api` utility.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { anyApi, componentsGeneric } from "convex/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility for referencing Convex functions in your app's API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```js
|
||||||
|
* const myFunctionReference = api.myModule.myFunction;
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const api = anyApi;
|
||||||
|
export const internal = anyApi;
|
||||||
|
export const components = componentsGeneric();
|
||||||
60
packages/backend/convex/betterAuth/_generated/dataModel.d.ts
vendored
Normal file
60
packages/backend/convex/betterAuth/_generated/dataModel.d.ts
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated data model types.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
DataModelFromSchemaDefinition,
|
||||||
|
DocumentByName,
|
||||||
|
TableNamesInDataModel,
|
||||||
|
SystemTableNames,
|
||||||
|
} from "convex/server";
|
||||||
|
import type { GenericId } from "convex/values";
|
||||||
|
import schema from "../schema.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names of all of your Convex tables.
|
||||||
|
*/
|
||||||
|
export type TableNames = TableNamesInDataModel<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of a document stored in Convex.
|
||||||
|
*
|
||||||
|
* @typeParam TableName - A string literal type of the table name (like "users").
|
||||||
|
*/
|
||||||
|
export type Doc<TableName extends TableNames> = DocumentByName<
|
||||||
|
DataModel,
|
||||||
|
TableName
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An identifier for a document in Convex.
|
||||||
|
*
|
||||||
|
* Convex documents are uniquely identified by their `Id`, which is accessible
|
||||||
|
* on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
|
||||||
|
*
|
||||||
|
* Documents can be loaded using `db.get(id)` in query and mutation functions.
|
||||||
|
*
|
||||||
|
* IDs are just strings at runtime, but this type can be used to distinguish them from other
|
||||||
|
* strings when type checking.
|
||||||
|
*
|
||||||
|
* @typeParam TableName - A string literal type of the table name (like "users").
|
||||||
|
*/
|
||||||
|
export type Id<TableName extends TableNames | SystemTableNames> =
|
||||||
|
GenericId<TableName>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type describing your Convex data model.
|
||||||
|
*
|
||||||
|
* This type includes information about what tables you have, the type of
|
||||||
|
* documents stored in those tables, and the indexes defined on them.
|
||||||
|
*
|
||||||
|
* This type is used to parameterize methods like `queryGeneric` and
|
||||||
|
* `mutationGeneric` to make them type-safe.
|
||||||
|
*/
|
||||||
|
export type DataModel = DataModelFromSchemaDefinition<typeof schema>;
|
||||||
149
packages/backend/convex/betterAuth/_generated/server.d.ts
vendored
Normal file
149
packages/backend/convex/betterAuth/_generated/server.d.ts
vendored
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated utilities for implementing server-side Convex query and mutation functions.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
ActionBuilder,
|
||||||
|
AnyComponents,
|
||||||
|
HttpActionBuilder,
|
||||||
|
MutationBuilder,
|
||||||
|
QueryBuilder,
|
||||||
|
GenericActionCtx,
|
||||||
|
GenericMutationCtx,
|
||||||
|
GenericQueryCtx,
|
||||||
|
GenericDatabaseReader,
|
||||||
|
GenericDatabaseWriter,
|
||||||
|
FunctionReference,
|
||||||
|
} from "convex/server";
|
||||||
|
import type { DataModel } from "./dataModel.js";
|
||||||
|
|
||||||
|
type GenericCtx =
|
||||||
|
| GenericActionCtx<DataModel>
|
||||||
|
| GenericMutationCtx<DataModel>
|
||||||
|
| GenericQueryCtx<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a query in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* This function will be allowed to read your Convex database and will be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||||
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export declare const query: QueryBuilder<DataModel, "public">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a query that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||||
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export declare const internalQuery: QueryBuilder<DataModel, "internal">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a mutation in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* This function will be allowed to modify your Convex database and will be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||||
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export declare const mutation: MutationBuilder<DataModel, "public">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||||
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export declare const internalMutation: MutationBuilder<DataModel, "internal">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an action in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* An action is a function which can execute any JavaScript code, including non-deterministic
|
||||||
|
* code and code with side-effects, like calling third-party services.
|
||||||
|
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
|
||||||
|
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
|
||||||
|
*
|
||||||
|
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
||||||
|
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export declare const action: ActionBuilder<DataModel, "public">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an action that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
||||||
|
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export declare const internalAction: ActionBuilder<DataModel, "internal">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an HTTP action.
|
||||||
|
*
|
||||||
|
* This function will be used to respond to HTTP requests received by a Convex
|
||||||
|
* deployment if the requests matches the path and method where this action
|
||||||
|
* is routed. Be sure to route your action in `convex/http.js`.
|
||||||
|
*
|
||||||
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
||||||
|
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||||
|
*/
|
||||||
|
export declare const httpAction: HttpActionBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of services for use within Convex query functions.
|
||||||
|
*
|
||||||
|
* The query context is passed as the first argument to any Convex query
|
||||||
|
* function run on the server.
|
||||||
|
*
|
||||||
|
* This differs from the {@link MutationCtx} because all of the services are
|
||||||
|
* read-only.
|
||||||
|
*/
|
||||||
|
export type QueryCtx = GenericQueryCtx<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of services for use within Convex mutation functions.
|
||||||
|
*
|
||||||
|
* The mutation context is passed as the first argument to any Convex mutation
|
||||||
|
* function run on the server.
|
||||||
|
*/
|
||||||
|
export type MutationCtx = GenericMutationCtx<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of services for use within Convex action functions.
|
||||||
|
*
|
||||||
|
* The action context is passed as the first argument to any Convex action
|
||||||
|
* function run on the server.
|
||||||
|
*/
|
||||||
|
export type ActionCtx = GenericActionCtx<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to read from the database within Convex query functions.
|
||||||
|
*
|
||||||
|
* The two entry points are {@link DatabaseReader.get}, which fetches a single
|
||||||
|
* document by its {@link Id}, or {@link DatabaseReader.query}, which starts
|
||||||
|
* building a query.
|
||||||
|
*/
|
||||||
|
export type DatabaseReader = GenericDatabaseReader<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to read from and write to the database within Convex mutation
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* Convex guarantees that all writes within a single mutation are
|
||||||
|
* executed atomically, so you never have to worry about partial writes leaving
|
||||||
|
* your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)
|
||||||
|
* for the guarantees Convex provides your functions.
|
||||||
|
*/
|
||||||
|
export type DatabaseWriter = GenericDatabaseWriter<DataModel>;
|
||||||
90
packages/backend/convex/betterAuth/_generated/server.js
Normal file
90
packages/backend/convex/betterAuth/_generated/server.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated utilities for implementing server-side Convex query and mutation functions.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
actionGeneric,
|
||||||
|
httpActionGeneric,
|
||||||
|
queryGeneric,
|
||||||
|
mutationGeneric,
|
||||||
|
internalActionGeneric,
|
||||||
|
internalMutationGeneric,
|
||||||
|
internalQueryGeneric,
|
||||||
|
componentsGeneric,
|
||||||
|
} from "convex/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a query in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* This function will be allowed to read your Convex database and will be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||||
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const query = queryGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a query that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||||
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const internalQuery = internalQueryGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a mutation in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* This function will be allowed to modify your Convex database and will be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||||
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const mutation = mutationGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||||
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const internalMutation = internalMutationGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an action in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* An action is a function which can execute any JavaScript code, including non-deterministic
|
||||||
|
* code and code with side-effects, like calling third-party services.
|
||||||
|
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
|
||||||
|
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
|
||||||
|
*
|
||||||
|
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
||||||
|
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const action = actionGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an action that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
||||||
|
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const internalAction = internalActionGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a Convex HTTP action.
|
||||||
|
*
|
||||||
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
|
||||||
|
* as its second.
|
||||||
|
* @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
|
||||||
|
*/
|
||||||
|
export const httpAction = httpActionGeneric;
|
||||||
13
packages/backend/convex/betterAuth/adapter.ts
Normal file
13
packages/backend/convex/betterAuth/adapter.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
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);
|
||||||
5
packages/backend/convex/betterAuth/auth.ts
Normal file
5
packages/backend/convex/betterAuth/auth.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
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);
|
||||||
5
packages/backend/convex/betterAuth/convex.config.ts
Normal file
5
packages/backend/convex/betterAuth/convex.config.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { defineComponent } from "convex/server";
|
||||||
|
|
||||||
|
const component = defineComponent("betterAuth");
|
||||||
|
|
||||||
|
export default component;
|
||||||
70
packages/backend/convex/betterAuth/schema.ts
Normal file
70
packages/backend/convex/betterAuth/schema.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// 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;
|
||||||
@@ -1,72 +1,7 @@
|
|||||||
import { defineApp, defineAuth } from "convex/server";
|
import { defineApp } from "convex/server";
|
||||||
import betterAuth from "@convex-dev/better-auth/convex.config";
|
import betterAuth from "./betterAuth/convex.config";
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom Auth Provider para aceitar tokens customizados
|
|
||||||
*
|
|
||||||
* Este provider funciona junto com Better Auth para suportar:
|
|
||||||
* 1. Tokens customizados do sistema atual (via sessoes)
|
|
||||||
* 2. Tokens do Better Auth (quando configurado)
|
|
||||||
*/
|
|
||||||
const customAuth = defineAuth({
|
|
||||||
getToken: async (request: Request): Promise<string | null> => {
|
|
||||||
// Tentar obter token de várias fontes
|
|
||||||
// 1. Authorization header (Bearer token)
|
|
||||||
const authHeader = request.headers.get("authorization");
|
|
||||||
if (authHeader?.startsWith("Bearer ")) {
|
|
||||||
return authHeader.substring(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. x-auth-token header
|
|
||||||
const xAuthToken = request.headers.get("x-auth-token");
|
|
||||||
if (xAuthToken) {
|
|
||||||
return xAuthToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Query parameter (para WebSocket)
|
|
||||||
const url = new URL(request.url);
|
|
||||||
const queryToken = url.searchParams.get("authToken");
|
|
||||||
if (queryToken) {
|
|
||||||
return queryToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
getIdentity: async (ctx, token: string) => {
|
|
||||||
if (!token) return null;
|
|
||||||
|
|
||||||
// Buscar sessão ativa por token
|
|
||||||
const sessao = await ctx.db
|
|
||||||
.query("sessoes")
|
|
||||||
.withIndex("by_token", (q) => q.eq("token", token))
|
|
||||||
.filter((q) => q.eq(q.field("ativo"), true))
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!sessao) return null;
|
|
||||||
|
|
||||||
// Buscar usuário da sessão
|
|
||||||
const usuario = await ctx.db.get(sessao.usuarioId);
|
|
||||||
if (!usuario || !usuario.ativo) return null;
|
|
||||||
|
|
||||||
// Retornar identity compatível com Better Auth
|
|
||||||
return {
|
|
||||||
subject: usuario._id,
|
|
||||||
email: usuario.email,
|
|
||||||
emailVerified: true,
|
|
||||||
name: usuario.nome,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuração Better Auth para Convex
|
|
||||||
*
|
|
||||||
* Usando Better Auth oficialmente integrado com Convex.
|
|
||||||
* O Custom Auth Provider acima funciona junto com Better Auth para suportar tokens customizados.
|
|
||||||
*/
|
|
||||||
const app = defineApp();
|
const app = defineApp();
|
||||||
app.use(customAuth);
|
|
||||||
app.use(betterAuth);
|
app.use(betterAuth);
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { httpAction } from "./_generated/server";
|
|||||||
import { internal } from "./_generated/api";
|
import { internal } from "./_generated/api";
|
||||||
import { getClientIP } from "./utils/getClientIP";
|
import { getClientIP } from "./utils/getClientIP";
|
||||||
import { v } from "convex/values";
|
import { v } from "convex/values";
|
||||||
|
import { authComponent, createAuth } from "./auth";
|
||||||
|
|
||||||
const http = httpRouter();
|
const http = httpRouter();
|
||||||
|
|
||||||
@@ -98,12 +99,15 @@ http.route({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Chamar a mutation de login interna com IP e userAgent
|
// Chamar a mutation de login interna com IP e userAgent
|
||||||
const resultado = await ctx.runMutation(internal.autenticacao.loginComIP, {
|
const resultado = await ctx.runMutation(
|
||||||
|
internal.autenticacao.loginComIP,
|
||||||
|
{
|
||||||
matriculaOuEmail: body.matriculaOuEmail,
|
matriculaOuEmail: body.matriculaOuEmail,
|
||||||
senha: body.senha,
|
senha: body.senha,
|
||||||
ipAddress: clientIP,
|
ipAddress: clientIP,
|
||||||
userAgent: userAgent,
|
userAgent: userAgent,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return new Response(JSON.stringify(resultado), {
|
return new Response(JSON.stringify(resultado), {
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -118,7 +122,8 @@ http.route({
|
|||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
sucesso: false,
|
sucesso: false,
|
||||||
erro: error instanceof Error ? error.message : "Erro ao processar login",
|
erro:
|
||||||
|
error instanceof Error ? error.message : "Erro ao processar login",
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 500,
|
status: 500,
|
||||||
@@ -147,4 +152,6 @@ http.route({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
authComponent.registerRoutes(http, createAuth);
|
||||||
|
|
||||||
export default http;
|
export default http;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@convex-dev/better-auth": "^0.9.7",
|
"@convex-dev/better-auth": "^0.9.7",
|
||||||
"@dicebear/avataaars": "^9.2.4",
|
"@dicebear/avataaars": "^9.2.4",
|
||||||
|
"better-auth": "1.3.27",
|
||||||
"convex": "catalog:",
|
"convex": "catalog:",
|
||||||
"nodemailer": "^7.0.10"
|
"nodemailer": "^7.0.10"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user