refactor: integrate Better-Auth for authentication and remove Supabase dependencies

This commit is contained in:
Jose Selesan
2026-04-16 20:30:01 -03:00
parent f158845279
commit e5002ce440
29 changed files with 165 additions and 211 deletions

View File

@@ -8,6 +8,7 @@ model User {
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
sessions Session[] sessions Session[]
accounts Account[] accounts Account[]
role String @default("member")
complexes ComplexUser[] complexes ComplexUser[]
@@unique([email]) @@unique([email])

View File

@@ -21,7 +21,7 @@ export function createApp() {
}, },
allowHeaders: ['Authorization', 'Content-Type'], allowHeaders: ['Authorization', 'Content-Type'],
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
exposeHeaders: ["Content-Length"], exposeHeaders: ['Content-Length'],
maxAge: 600, maxAge: 600,
credentials: true, credentials: true,
}) })

File diff suppressed because one or more lines are too long

View File

@@ -1499,7 +1499,8 @@ export const UserScalarFieldEnum = {
emailVerified: 'emailVerified', emailVerified: 'emailVerified',
image: 'image', image: 'image',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt' updatedAt: 'updatedAt',
role: 'role'
} as const } as const
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]

View File

@@ -90,7 +90,8 @@ export const UserScalarFieldEnum = {
emailVerified: 'emailVerified', emailVerified: 'emailVerified',
image: 'image', image: 'image',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt' updatedAt: 'updatedAt',
role: 'role'
} as const } as const
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]

View File

@@ -32,6 +32,7 @@ export type UserMinAggregateOutputType = {
image: string | null image: string | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
role: string | null
} }
export type UserMaxAggregateOutputType = { export type UserMaxAggregateOutputType = {
@@ -42,6 +43,7 @@ export type UserMaxAggregateOutputType = {
image: string | null image: string | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
role: string | null
} }
export type UserCountAggregateOutputType = { export type UserCountAggregateOutputType = {
@@ -52,6 +54,7 @@ export type UserCountAggregateOutputType = {
image: number image: number
createdAt: number createdAt: number
updatedAt: number updatedAt: number
role: number
_all: number _all: number
} }
@@ -64,6 +67,7 @@ export type UserMinAggregateInputType = {
image?: true image?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
role?: true
} }
export type UserMaxAggregateInputType = { export type UserMaxAggregateInputType = {
@@ -74,6 +78,7 @@ export type UserMaxAggregateInputType = {
image?: true image?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
role?: true
} }
export type UserCountAggregateInputType = { export type UserCountAggregateInputType = {
@@ -84,6 +89,7 @@ export type UserCountAggregateInputType = {
image?: true image?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
role?: true
_all?: true _all?: true
} }
@@ -167,6 +173,7 @@ export type UserGroupByOutputType = {
image: string | null image: string | null
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
role: string
_count: UserCountAggregateOutputType | null _count: UserCountAggregateOutputType | null
_min: UserMinAggregateOutputType | null _min: UserMinAggregateOutputType | null
_max: UserMaxAggregateOutputType | null _max: UserMaxAggregateOutputType | null
@@ -198,6 +205,7 @@ export type UserWhereInput = {
image?: Prisma.StringNullableFilter<"User"> | string | null image?: Prisma.StringNullableFilter<"User"> | string | null
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
role?: Prisma.StringFilter<"User"> | string
sessions?: Prisma.SessionListRelationFilter sessions?: Prisma.SessionListRelationFilter
accounts?: Prisma.AccountListRelationFilter accounts?: Prisma.AccountListRelationFilter
complexes?: Prisma.ComplexUserListRelationFilter complexes?: Prisma.ComplexUserListRelationFilter
@@ -211,6 +219,7 @@ export type UserOrderByWithRelationInput = {
image?: Prisma.SortOrderInput | Prisma.SortOrder image?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
role?: Prisma.SortOrder
sessions?: Prisma.SessionOrderByRelationAggregateInput sessions?: Prisma.SessionOrderByRelationAggregateInput
accounts?: Prisma.AccountOrderByRelationAggregateInput accounts?: Prisma.AccountOrderByRelationAggregateInput
complexes?: Prisma.ComplexUserOrderByRelationAggregateInput complexes?: Prisma.ComplexUserOrderByRelationAggregateInput
@@ -227,6 +236,7 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{
image?: Prisma.StringNullableFilter<"User"> | string | null image?: Prisma.StringNullableFilter<"User"> | string | null
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
role?: Prisma.StringFilter<"User"> | string
sessions?: Prisma.SessionListRelationFilter sessions?: Prisma.SessionListRelationFilter
accounts?: Prisma.AccountListRelationFilter accounts?: Prisma.AccountListRelationFilter
complexes?: Prisma.ComplexUserListRelationFilter complexes?: Prisma.ComplexUserListRelationFilter
@@ -240,6 +250,7 @@ export type UserOrderByWithAggregationInput = {
image?: Prisma.SortOrderInput | Prisma.SortOrder image?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
role?: Prisma.SortOrder
_count?: Prisma.UserCountOrderByAggregateInput _count?: Prisma.UserCountOrderByAggregateInput
_max?: Prisma.UserMaxOrderByAggregateInput _max?: Prisma.UserMaxOrderByAggregateInput
_min?: Prisma.UserMinOrderByAggregateInput _min?: Prisma.UserMinOrderByAggregateInput
@@ -256,6 +267,7 @@ export type UserScalarWhereWithAggregatesInput = {
image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
role?: Prisma.StringWithAggregatesFilter<"User"> | string
} }
export type UserCreateInput = { export type UserCreateInput = {
@@ -266,6 +278,7 @@ export type UserCreateInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
sessions?: Prisma.SessionCreateNestedManyWithoutUserInput sessions?: Prisma.SessionCreateNestedManyWithoutUserInput
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
complexes?: Prisma.ComplexUserCreateNestedManyWithoutUserInput complexes?: Prisma.ComplexUserCreateNestedManyWithoutUserInput
@@ -279,6 +292,7 @@ export type UserUncheckedCreateInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
complexes?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutUserInput complexes?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutUserInput
@@ -292,6 +306,7 @@ export type UserUpdateInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
complexes?: Prisma.ComplexUserUpdateManyWithoutUserNestedInput complexes?: Prisma.ComplexUserUpdateManyWithoutUserNestedInput
@@ -305,6 +320,7 @@ export type UserUncheckedUpdateInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
complexes?: Prisma.ComplexUserUncheckedUpdateManyWithoutUserNestedInput complexes?: Prisma.ComplexUserUncheckedUpdateManyWithoutUserNestedInput
@@ -318,6 +334,7 @@ export type UserCreateManyInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
} }
export type UserUpdateManyMutationInput = { export type UserUpdateManyMutationInput = {
@@ -328,6 +345,7 @@ export type UserUpdateManyMutationInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
} }
export type UserUncheckedUpdateManyInput = { export type UserUncheckedUpdateManyInput = {
@@ -338,6 +356,7 @@ export type UserUncheckedUpdateManyInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
} }
export type UserCountOrderByAggregateInput = { export type UserCountOrderByAggregateInput = {
@@ -348,6 +367,7 @@ export type UserCountOrderByAggregateInput = {
image?: Prisma.SortOrder image?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
role?: Prisma.SortOrder
} }
export type UserMaxOrderByAggregateInput = { export type UserMaxOrderByAggregateInput = {
@@ -358,6 +378,7 @@ export type UserMaxOrderByAggregateInput = {
image?: Prisma.SortOrder image?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
role?: Prisma.SortOrder
} }
export type UserMinOrderByAggregateInput = { export type UserMinOrderByAggregateInput = {
@@ -368,6 +389,7 @@ export type UserMinOrderByAggregateInput = {
image?: Prisma.SortOrder image?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
role?: Prisma.SortOrder
} }
export type UserScalarRelationFilter = { export type UserScalarRelationFilter = {
@@ -441,6 +463,7 @@ export type UserCreateWithoutSessionsInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
complexes?: Prisma.ComplexUserCreateNestedManyWithoutUserInput complexes?: Prisma.ComplexUserCreateNestedManyWithoutUserInput
} }
@@ -453,6 +476,7 @@ export type UserUncheckedCreateWithoutSessionsInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
complexes?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutUserInput complexes?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutUserInput
} }
@@ -481,6 +505,7 @@ export type UserUpdateWithoutSessionsInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
complexes?: Prisma.ComplexUserUpdateManyWithoutUserNestedInput complexes?: Prisma.ComplexUserUpdateManyWithoutUserNestedInput
} }
@@ -493,6 +518,7 @@ export type UserUncheckedUpdateWithoutSessionsInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
complexes?: Prisma.ComplexUserUncheckedUpdateManyWithoutUserNestedInput complexes?: Prisma.ComplexUserUncheckedUpdateManyWithoutUserNestedInput
} }
@@ -505,6 +531,7 @@ export type UserCreateWithoutAccountsInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
sessions?: Prisma.SessionCreateNestedManyWithoutUserInput sessions?: Prisma.SessionCreateNestedManyWithoutUserInput
complexes?: Prisma.ComplexUserCreateNestedManyWithoutUserInput complexes?: Prisma.ComplexUserCreateNestedManyWithoutUserInput
} }
@@ -517,6 +544,7 @@ export type UserUncheckedCreateWithoutAccountsInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput
complexes?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutUserInput complexes?: Prisma.ComplexUserUncheckedCreateNestedManyWithoutUserInput
} }
@@ -545,6 +573,7 @@ export type UserUpdateWithoutAccountsInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput
complexes?: Prisma.ComplexUserUpdateManyWithoutUserNestedInput complexes?: Prisma.ComplexUserUpdateManyWithoutUserNestedInput
} }
@@ -557,6 +586,7 @@ export type UserUncheckedUpdateWithoutAccountsInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput
complexes?: Prisma.ComplexUserUncheckedUpdateManyWithoutUserNestedInput complexes?: Prisma.ComplexUserUncheckedUpdateManyWithoutUserNestedInput
} }
@@ -569,6 +599,7 @@ export type UserCreateWithoutComplexesInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
sessions?: Prisma.SessionCreateNestedManyWithoutUserInput sessions?: Prisma.SessionCreateNestedManyWithoutUserInput
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
} }
@@ -581,6 +612,7 @@ export type UserUncheckedCreateWithoutComplexesInput = {
image?: string | null image?: string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
role?: string
sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
} }
@@ -609,6 +641,7 @@ export type UserUpdateWithoutComplexesInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
} }
@@ -621,6 +654,7 @@ export type UserUncheckedUpdateWithoutComplexesInput = {
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
role?: Prisma.StringFieldUpdateOperationsInput | string
sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
} }
@@ -682,6 +716,7 @@ export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
image?: boolean image?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
role?: boolean
sessions?: boolean | Prisma.User$sessionsArgs<ExtArgs> sessions?: boolean | Prisma.User$sessionsArgs<ExtArgs>
accounts?: boolean | Prisma.User$accountsArgs<ExtArgs> accounts?: boolean | Prisma.User$accountsArgs<ExtArgs>
complexes?: boolean | Prisma.User$complexesArgs<ExtArgs> complexes?: boolean | Prisma.User$complexesArgs<ExtArgs>
@@ -696,6 +731,7 @@ export type UserSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensio
image?: boolean image?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
role?: boolean
}, ExtArgs["result"]["user"]> }, ExtArgs["result"]["user"]>
export type UserSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{ export type UserSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
@@ -706,6 +742,7 @@ export type UserSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensio
image?: boolean image?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
role?: boolean
}, ExtArgs["result"]["user"]> }, ExtArgs["result"]["user"]>
export type UserSelectScalar = { export type UserSelectScalar = {
@@ -716,9 +753,10 @@ export type UserSelectScalar = {
image?: boolean image?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
role?: boolean
} }
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "emailVerified" | "image" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]> export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "emailVerified" | "image" | "createdAt" | "updatedAt" | "role", ExtArgs["result"]["user"]>
export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
sessions?: boolean | Prisma.User$sessionsArgs<ExtArgs> sessions?: boolean | Prisma.User$sessionsArgs<ExtArgs>
accounts?: boolean | Prisma.User$accountsArgs<ExtArgs> accounts?: boolean | Prisma.User$accountsArgs<ExtArgs>
@@ -743,6 +781,7 @@ export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
image: string | null image: string | null
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
role: string
}, ExtArgs["result"]["user"]> }, ExtArgs["result"]["user"]>
composites: {} composites: {}
} }
@@ -1176,6 +1215,7 @@ export interface UserFieldRefs {
readonly image: Prisma.FieldRef<"User", 'String'> readonly image: Prisma.FieldRef<"User", 'String'>
readonly createdAt: Prisma.FieldRef<"User", 'DateTime'> readonly createdAt: Prisma.FieldRef<"User", 'DateTime'>
readonly updatedAt: Prisma.FieldRef<"User", 'DateTime'> readonly updatedAt: Prisma.FieldRef<"User", 'DateTime'>
readonly role: Prisma.FieldRef<"User", 'String'>
} }

View File

@@ -1,12 +1,12 @@
import { betterAuth } from "better-auth"; import { betterAuth } from 'better-auth';
import { prismaAdapter } from "better-auth/adapters/prisma"; import { prismaAdapter } from 'better-auth/adapters/prisma';
// If your Prisma file is located elsewhere, you can change the path // If your Prisma file is located elsewhere, you can change the path
import { openAPI } from "better-auth/plugins"; import { openAPI } from 'better-auth/plugins';
import { db } from "./prisma"; import { db } from './prisma';
export const auth = betterAuth({ export const auth = betterAuth({
database: prismaAdapter(db, { database: prismaAdapter(db, {
provider: "postgresql", provider: 'postgresql',
}), }),
secret: process.env.BETTER_AUTH_SECRET, secret: process.env.BETTER_AUTH_SECRET,
baseURL: process.env.BETTER_AUTH_URL, baseURL: process.env.BETTER_AUTH_URL,
@@ -18,9 +18,8 @@ export const auth = betterAuth({
emailAndPassword: { emailAndPassword: {
enabled: true, enabled: true,
}, },
trustedOrigins: [process.env.APP_BASE_URL ?? "http://localhost:5173"], trustedOrigins: [process.env.APP_BASE_URL ?? 'http://localhost:5173'],
plugins: [ plugins: [],
],
}); });
export type Session = typeof auth.$Infer.Session.session; export type Session = typeof auth.$Infer.Session.session;

View File

@@ -1,27 +1,18 @@
import { createMiddleware } from "hono/factory"; import { auth } from '@/lib/auth';
import { auth } from "@/lib/auth"; import type { AppEnv } from '@/types/hono';
import type { Session, User } from "@/lib/auth"; import { createMiddleware } from 'hono/factory';
export type AuthEnv = { export const requireAuth = createMiddleware<AppEnv>(async (c, next) => {
Variables: {
user: User;
session: Session;
};
};
export const requireAuth = createMiddleware<AuthEnv>(async (c, next) => {
const session = await auth.api.getSession({ const session = await auth.api.getSession({
headers: c.req.raw.headers, headers: c.req.raw.headers,
}); });
console.log(session)
if (!session) { if (!session) {
return c.json({ message: "Unauthorized" }, 401); return c.json({ message: 'Unauthorized' }, 401);
} }
c.set("user", session.user); c.set('user', session.user);
c.set("session", session.session); c.set('session', session.session);
await next(); await next();
}); });

View File

@@ -11,9 +11,9 @@ function getSuperAdminEmails(): Set<string> {
} }
export const requireSuperAdmin: MiddlewareHandler<AppEnv> = async (c, next) => { export const requireSuperAdmin: MiddlewareHandler<AppEnv> = async (c, next) => {
const authUser = c.get('authUser'); const user = c.get('user');
const role = typeof authUser.app_metadata?.role === 'string' ? authUser.app_metadata.role : null; const role = (user as any).role || 'member';
const email = authUser.email?.toLowerCase(); const email = user.email.toLowerCase();
if (role === 'super_admin') { if (role === 'super_admin') {
await next(); await next();

View File

@@ -10,10 +10,10 @@ type ComplexIdParams = { complexId: string };
export async function createAdminBookingHandler(c: AppContext) { export async function createAdminBookingHandler(c: AppContext) {
const { complexId } = c.req.valid('param' as never) as ComplexIdParams; const { complexId } = c.req.valid('param' as never) as ComplexIdParams;
const payload = c.req.valid('json' as never) as CreateAdminBookingInput; const payload = c.req.valid('json' as never) as CreateAdminBookingInput;
const appUserId = c.get('appUserId'); const user = c.get('user');
try { try {
const booking = await createAdminBooking(appUserId, complexId, payload); const booking = await createAdminBooking(user.id, complexId, payload);
return c.json(booking, 201); return c.json(booking, 201);
} catch (error) { } catch (error) {
if (error instanceof AdminBookingServiceError) { if (error instanceof AdminBookingServiceError) {

View File

@@ -10,10 +10,10 @@ type ComplexIdParams = { complexId: string };
export async function listAdminBookingsHandler(c: AppContext) { export async function listAdminBookingsHandler(c: AppContext) {
const { complexId } = c.req.valid('param' as never) as ComplexIdParams; const { complexId } = c.req.valid('param' as never) as ComplexIdParams;
const query = c.req.valid('query' as never) as ListAdminBookingsQuery; const query = c.req.valid('query' as never) as ListAdminBookingsQuery;
const appUserId = c.get('appUserId'); const user = c.get('user');
try { try {
const response = await listAdminBookings(appUserId, complexId, query); const response = await listAdminBookings(user.id, complexId, query);
return c.json(response); return c.json(response);
} catch (error) { } catch (error) {
if (error instanceof AdminBookingServiceError) { if (error instanceof AdminBookingServiceError) {

View File

@@ -10,10 +10,10 @@ type BookingIdParams = { id: string };
export async function updateAdminBookingStatusHandler(c: AppContext) { export async function updateAdminBookingStatusHandler(c: AppContext) {
const { id } = c.req.valid('param' as never) as BookingIdParams; const { id } = c.req.valid('param' as never) as BookingIdParams;
const payload = c.req.valid('json' as never) as UpdateAdminBookingStatusInput; const payload = c.req.valid('json' as never) as UpdateAdminBookingStatusInput;
const appUserId = c.get('appUserId'); const user = c.get('user');
try { try {
const booking = await updateAdminBookingStatus(appUserId, id, payload); const booking = await updateAdminBookingStatus(user.id, id, payload);
return c.json(booking); return c.json(booking);
} catch (error) { } catch (error) {
if (error instanceof AdminBookingServiceError) { if (error instanceof AdminBookingServiceError) {

View File

@@ -126,12 +126,12 @@ function buildSlots(
return slots; return slots;
} }
async function ensureComplexAccess(complexId: string, appUserId: string) { async function ensureComplexAccess(complexId: string, userId: string) {
const complexUser = await db.complexUser.findUnique({ const complexUser = await db.complexUser.findUnique({
where: { where: {
complexId_userId: { complexId_userId: {
complexId, complexId,
userId: appUserId, userId,
}, },
}, },
include: { include: {
@@ -205,11 +205,11 @@ function mapBookingResponse(booking: {
} }
export async function listAdminBookings( export async function listAdminBookings(
appUserId: string, userId: string,
complexId: string, complexId: string,
query: ListAdminBookingsQuery query: ListAdminBookingsQuery
) { ) {
await ensureComplexAccess(complexId, appUserId); await ensureComplexAccess(complexId, userId);
const fromDate = parseIsoDate(query.fromDate); const fromDate = parseIsoDate(query.fromDate);
const bookings = await db.courtBooking.findMany({ const bookings = await db.courtBooking.findMany({
@@ -253,11 +253,11 @@ export async function listAdminBookings(
} }
export async function createAdminBooking( export async function createAdminBooking(
appUserId: string, userId: string,
complexId: string, complexId: string,
input: CreateAdminBookingInput input: CreateAdminBookingInput
) { ) {
const complex = await ensureComplexAccess(complexId, appUserId); const complex = await ensureComplexAccess(complexId, userId);
const bookingDate = parseIsoDate(input.date); const bookingDate = parseIsoDate(input.date);
const dayOfWeek = getDayOfWeek(bookingDate); const dayOfWeek = getDayOfWeek(bookingDate);
@@ -436,7 +436,7 @@ export async function createAdminBooking(
} }
export async function updateAdminBookingStatus( export async function updateAdminBookingStatus(
appUserId: string, userId: string,
bookingId: string, bookingId: string,
input: UpdateAdminBookingStatusInput input: UpdateAdminBookingStatusInput
) { ) {
@@ -447,7 +447,7 @@ export async function updateAdminBookingStatus(
complex: { complex: {
users: { users: {
some: { some: {
userId: appUserId, userId,
}, },
}, },
}, },

View File

@@ -1,9 +1,9 @@
import { Hono } from "hono"; import { auth } from '@/lib/auth';
import { auth } from "@/lib/auth"; import { AppEnv } from '@/types/hono';
import { AppEnv } from "@/types/hono"; import { Hono } from 'hono';
export const authRoutes = new Hono<AppEnv>(); export const authRoutes = new Hono<AppEnv>();
authRoutes.on(["POST", "GET"], "/api/auth/*", (c) => { authRoutes.on(['POST', 'GET'], '/api/auth/*', (c) => {
return auth.handler(c.req.raw); return auth.handler(c.req.raw);
}); });

View File

@@ -5,8 +5,8 @@ import type { CreateComplexInput } from '@repo/api-contract';
export async function createComplexHandler(c: AppContext) { export async function createComplexHandler(c: AppContext) {
const payload = c.req.valid('json' as never) as CreateComplexInput; const payload = c.req.valid('json' as never) as CreateComplexInput;
const authUser = c.get('authUser'); const user = c.get('user');
const adminEmail = authUser.email; const adminEmail = user.email;
if (!adminEmail) { if (!adminEmail) {
return c.json({ message: 'El usuario autenticado no tiene email.' }, 400); return c.json({ message: 'El usuario autenticado no tiene email.' }, 400);

View File

@@ -2,7 +2,7 @@ import { listMyComplexes } from '@/modules/complex/services/complex.service';
import type { AppContext } from '@/types/hono'; import type { AppContext } from '@/types/hono';
export async function listMyComplexesHandler(c: AppContext) { export async function listMyComplexesHandler(c: AppContext) {
const appUserId = c.get('appUserId'); const user = c.get('user');
const complexes = await listMyComplexes(appUserId); const complexes = await listMyComplexes(user.id);
return c.json(complexes); return c.json(complexes);
} }

View File

@@ -93,9 +93,9 @@ export async function getComplexBySlug(slug: string) {
}); });
} }
export async function listMyComplexes(appUserId: string) { export async function listMyComplexes(userId: string) {
const complexUsers = await db.complexUser.findMany({ const complexUsers = await db.complexUser.findMany({
where: { userId: appUserId }, where: { userId },
include: { include: {
complex: true, complex: true,
}, },

View File

@@ -7,10 +7,10 @@ type ComplexIdParams = { complexId: string };
export async function createCourtHandler(c: AppContext) { export async function createCourtHandler(c: AppContext) {
const { complexId } = c.req.valid('param' as never) as ComplexIdParams; const { complexId } = c.req.valid('param' as never) as ComplexIdParams;
const payload = c.req.valid('json' as never) as CreateCourtInput; const payload = c.req.valid('json' as never) as CreateCourtInput;
const appUserId = c.get('appUserId'); const user = c.get('user');
try { try {
const court = await createCourt(appUserId, complexId, payload); const court = await createCourt(user.id, complexId, payload);
return c.json(court, 201); return c.json(court, 201);
} catch (error) { } catch (error) {
if (error instanceof CourtServiceError) { if (error instanceof CourtServiceError) {

View File

@@ -5,10 +5,10 @@ type ComplexIdParams = { complexId: string };
export async function listCourtsByComplexHandler(c: AppContext) { export async function listCourtsByComplexHandler(c: AppContext) {
const { complexId } = c.req.valid('param' as never) as ComplexIdParams; const { complexId } = c.req.valid('param' as never) as ComplexIdParams;
const appUserId = c.get('appUserId'); const user = c.get('user');
try { try {
const courts = await listCourtsByComplex(complexId, appUserId); const courts = await listCourtsByComplex(complexId, user.id);
return c.json(courts); return c.json(courts);
} catch (error) { } catch (error) {
if (error instanceof CourtServiceError) { if (error instanceof CourtServiceError) {

View File

@@ -7,10 +7,10 @@ type CourtIdParams = { id: string };
export async function updateCourtHandler(c: AppContext) { export async function updateCourtHandler(c: AppContext) {
const { id } = c.req.valid('param' as never) as CourtIdParams; const { id } = c.req.valid('param' as never) as CourtIdParams;
const payload = c.req.valid('json' as never) as UpdateCourtInput; const payload = c.req.valid('json' as never) as UpdateCourtInput;
const appUserId = c.get('appUserId'); const user = c.get('user');
try { try {
const court = await updateCourt(appUserId, id, payload); const court = await updateCourt(user.id, id, payload);
return c.json(court); return c.json(court);
} catch (error) { } catch (error) {
if (error instanceof CourtServiceError) { if (error instanceof CourtServiceError) {

View File

@@ -61,12 +61,12 @@ function assertAvailabilityRanges(
} }
} }
async function ensureComplexAccess(complexId: string, appUserId: string) { async function ensureComplexAccess(complexId: string, userId: string) {
const complexUser = await db.complexUser.findUnique({ const complexUser = await db.complexUser.findUnique({
where: { where: {
complexId_userId: { complexId_userId: {
complexId, complexId,
userId: appUserId, userId,
}, },
}, },
include: { include: {
@@ -137,14 +137,14 @@ async function enforcePlanCourtLimit(complexId: string) {
} }
} }
async function getCourtByIdForUser(courtId: string, appUserId: string) { async function getCourtByIdForUser(courtId: string, userId: string) {
return db.court.findFirst({ return db.court.findFirst({
where: { where: {
id: courtId, id: courtId,
complex: { complex: {
users: { users: {
some: { some: {
userId: appUserId, userId,
}, },
}, },
}, },
@@ -195,8 +195,8 @@ function mapCourtResponse(court: CourtWithRelations) {
}; };
} }
export async function listCourtsByComplex(complexId: string, appUserId: string) { export async function listCourtsByComplex(complexId: string, userId: string) {
await ensureComplexAccess(complexId, appUserId); await ensureComplexAccess(complexId, userId);
const courts = await db.court.findMany({ const courts = await db.court.findMany({
where: { complexId }, where: { complexId },
@@ -218,8 +218,8 @@ export async function listCourtsByComplex(complexId: string, appUserId: string)
return courts.map((court) => mapCourtResponse(court)); return courts.map((court) => mapCourtResponse(court));
} }
export async function createCourt(appUserId: string, complexId: string, input: CreateCourtInput) { export async function createCourt(userId: string, complexId: string, input: CreateCourtInput) {
await ensureComplexAccess(complexId, appUserId); await ensureComplexAccess(complexId, userId);
await ensureActiveSport(input.sportId); await ensureActiveSport(input.sportId);
await enforcePlanCourtLimit(complexId); await enforcePlanCourtLimit(complexId);
assertAvailabilityRanges(input.availability); assertAvailabilityRanges(input.availability);
@@ -249,7 +249,7 @@ export async function createCourt(appUserId: string, complexId: string, input: C
return court; return court;
}); });
const court = await getCourtByIdForUser(createdCourt.id, appUserId); const court = await getCourtByIdForUser(createdCourt.id, userId);
if (!court) { if (!court) {
throw new CourtServiceError('No se pudo obtener la cancha creada.', 404); throw new CourtServiceError('No se pudo obtener la cancha creada.', 404);
@@ -258,8 +258,8 @@ export async function createCourt(appUserId: string, complexId: string, input: C
return mapCourtResponse(court); return mapCourtResponse(court);
} }
export async function updateCourt(appUserId: string, courtId: string, input: UpdateCourtInput) { export async function updateCourt(userId: string, courtId: string, input: UpdateCourtInput) {
const existingCourt = await getCourtByIdForUser(courtId, appUserId); const existingCourt = await getCourtByIdForUser(courtId, userId);
if (!existingCourt) { if (!existingCourt) {
throw new CourtServiceError('Cancha no encontrada.', 404); throw new CourtServiceError('Cancha no encontrada.', 404);
@@ -305,7 +305,7 @@ export async function updateCourt(appUserId: string, courtId: string, input: Upd
} }
}); });
const updatedCourt = await getCourtByIdForUser(courtId, appUserId); const updatedCourt = await getCourtByIdForUser(courtId, userId);
if (!updatedCourt) { if (!updatedCourt) {
throw new CourtServiceError('Cancha no encontrada.', 404); throw new CourtServiceError('Cancha no encontrada.', 404);

View File

@@ -1,4 +1,5 @@
import { createHash, randomInt } from 'node:crypto'; import { createHash, randomInt } from 'node:crypto';
import { auth } from '@/lib/auth';
import { sendMail } from '@/lib/mailer'; import { sendMail } from '@/lib/mailer';
import { db } from '@/lib/prisma'; import { db } from '@/lib/prisma';
import { getSupabaseAdminClient } from '@/lib/supabase-admin'; import { getSupabaseAdminClient } from '@/lib/supabase-admin';
@@ -10,7 +11,6 @@ import type {
} from '@repo/api-contract'; } from '@repo/api-contract';
import type { User as SupabaseAuthUser } from '@supabase/supabase-js'; import type { User as SupabaseAuthUser } from '@supabase/supabase-js';
import { v7 as uuidv7 } from 'uuid'; import { v7 as uuidv7 } from 'uuid';
import { auth } from '@/lib/auth';
const OTP_LENGTH = 6; const OTP_LENGTH = 6;
const OTP_TTL_MINUTES = Number(Bun.env.ONBOARDING_OTP_TTL_MINUTES ?? 10); const OTP_TTL_MINUTES = Number(Bun.env.ONBOARDING_OTP_TTL_MINUTES ?? 10);
@@ -441,7 +441,6 @@ export async function completeOnboarding(input: OnboardingCompleteInput) {
const complexSlug = await buildUniqueComplexSlug(input.complexName); const complexSlug = await buildUniqueComplexSlug(input.complexName);
const result = await db.$transaction(async (tx) => { const result = await db.$transaction(async (tx) => {
const complex = await tx.complex.create({ const complex = await tx.complex.create({
data: { data: {
id: uuidv7(), id: uuidv7(),

View File

@@ -2,7 +2,7 @@ import { getUserProfile } from '@/modules/user/services/user.service';
import type { AppContext } from '@/types/hono'; import type { AppContext } from '@/types/hono';
export function getUserProfileHandler(c: AppContext) { export function getUserProfileHandler(c: AppContext) {
const authUser = c.get('authUser'); const user = c.get('user');
const profile = getUserProfile(authUser); const profile = getUserProfile(user);
return c.json(profile); return c.json(profile);
} }

View File

@@ -1,23 +1,13 @@
import type { AuthUser } from '@/types/auth-user'; import type { User } from '@/lib/auth';
import type { UserProfile } from '@repo/api-contract'; import type { UserProfile } from '@repo/api-contract';
export function getUserProfile(user: AuthUser): UserProfile { export function getUserProfile(user: User): UserProfile {
const fullName =
(typeof user.user_metadata?.full_name === 'string' && user.user_metadata.full_name) ||
(typeof user.user_metadata?.name === 'string' && user.user_metadata.name) ||
(user.email ?? 'Usuario');
const role = (typeof user.app_metadata?.role === 'string' && user.app_metadata.role) || 'member';
const avatarUrl =
(typeof user.user_metadata?.avatar_url === 'string' && user.user_metadata.avatar_url) || null;
return { return {
id: user.id, id: user.id,
fullName, fullName: user.name,
email: user.email ?? null, email: user.email,
role, role: (user as any).role || 'member',
avatarUrl, avatarUrl: user.image || null,
createdAt: user.created_at, createdAt: user.createdAt,
}; };
} }

View File

@@ -1,5 +1,6 @@
import path from 'node:path'; import path from 'node:path';
import { adminBookingRoutes } from '@/modules/admin-booking/admin-booking.routes'; import { adminBookingRoutes } from '@/modules/admin-booking/admin-booking.routes';
import { authRoutes } from '@/modules/auth/auth.routes';
import { complexRoutes } from '@/modules/complex/complex.routes'; import { complexRoutes } from '@/modules/complex/complex.routes';
import { courtRoutes } from '@/modules/court/court.routes'; import { courtRoutes } from '@/modules/court/court.routes';
import { onboardingRoutes } from '@/modules/onboarding/onboarding.routes'; import { onboardingRoutes } from '@/modules/onboarding/onboarding.routes';
@@ -8,14 +9,12 @@ import { planRoutes } from '@/modules/plan/plan.routes';
import { publicBookingRoutes } from '@/modules/public-booking/public-booking.routes'; import { publicBookingRoutes } from '@/modules/public-booking/public-booking.routes';
import { sportRoutes } from '@/modules/sport/sport.routes'; import { sportRoutes } from '@/modules/sport/sport.routes';
import { userRoutes } from '@/modules/user/user.routes'; import { userRoutes } from '@/modules/user/user.routes';
import { authRoutes } from '@/modules/auth/auth.routes';
import type { AppEnv } from '@/types/hono'; import type { AppEnv } from '@/types/hono';
import type { Hono } from 'hono'; import type { Hono } from 'hono';
import { serveStatic } from 'hono/bun'; import { serveStatic } from 'hono/bun';
import { healthCheckRoutes } from './modules/health-check/health-check.routes'; import { healthCheckRoutes } from './modules/health-check/health-check.routes';
export function registerRoutes(app: Hono<AppEnv>) { export function registerRoutes(app: Hono<AppEnv>) {
app app
.route('', authRoutes) .route('', authRoutes)
.route('/api/user', userRoutes) .route('/api/user', userRoutes)

View File

@@ -1,9 +1,9 @@
import type { AuthUser } from '@/types/auth-user'; import type { Session, User } from '@/lib/auth';
import type { Context } from 'hono'; import type { Context } from 'hono';
export type AppVariables = { export type AppVariables = {
authUser: AuthUser; user: User;
appUserId: string; session: Session;
}; };
export type AppEnv = { export type AppEnv = {

View File

@@ -29,7 +29,7 @@ import type {
UserProfileResponse, UserProfileResponse,
} from '@repo/api-contract'; } from '@repo/api-contract';
import axios, { AxiosError } from 'axios'; import axios, { AxiosError } from 'axios';
import { createAuthClient } from "better-auth/react"; import { createAuthClient } from 'better-auth/react';
const apiBaseUrl = const apiBaseUrl =
import.meta.env.VITE_API_BASE_URL?.trim() || import.meta.env.VITE_API_BASE_URL?.trim() ||
@@ -37,9 +37,11 @@ const apiBaseUrl =
export const authClient = createAuthClient({ export const authClient = createAuthClient({
baseURL: apiBaseUrl, baseURL: apiBaseUrl,
fetchOptions: {
credentials: 'include',
},
}); });
export class ApiClientError extends Error { export class ApiClientError extends Error {
status?: number; status?: number;
details?: unknown; details?: unknown;
@@ -66,6 +68,7 @@ const handlers: ErrorHandlers = {};
const http = axios.create({ const http = axios.create({
baseURL: apiBaseUrl, baseURL: apiBaseUrl,
withCredentials: true,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
@@ -285,6 +288,6 @@ export function configureApiClient(nextHandlers: ErrorHandlers) {
handlers.onError = nextHandlers.onError; handlers.onError = nextHandlers.onError;
} }
export function setApiAccessToken(token: string | null) { export function setApiAccessToken(_token: string | null) {
// accessToken = token; // accessToken = token;
} }

View File

@@ -1,14 +1,8 @@
import { setApiAccessToken } from '@/lib/api-client'; import { authClient } from '@/lib/api-client';
import { supabase } from '@/lib/supabase'; import { type PropsWithChildren, createContext, useContext, useMemo } from 'react';
import type { Session, User } from '@supabase/supabase-js';
import { export type User = typeof authClient.$Infer.Session.user;
type PropsWithChildren, export type Session = typeof authClient.$Infer.Session.session;
createContext,
useContext,
useEffect,
useMemo,
useState,
} from 'react';
type SignInParams = { type SignInParams = {
email: string; email: string;
@@ -48,14 +42,7 @@ const AuthContext = createContext<AuthContextValue | null>(null);
function getDisplayName(user: User | null): string { function getDisplayName(user: User | null): string {
if (!user) return 'Usuario'; if (!user) return 'Usuario';
if (user.name?.trim()) return user.name.trim();
const fromMetadata =
user.user_metadata?.name ?? user.user_metadata?.full_name ?? user.user_metadata?.user_name;
if (typeof fromMetadata === 'string' && fromMetadata.trim().length > 0) {
return fromMetadata.trim();
}
return user.email ?? 'Usuario'; return user.email ?? 'Usuario';
} }
@@ -66,47 +53,14 @@ function getInitials(name: string): string {
} }
function getAvatarUrl(user: User | null): string | null { function getAvatarUrl(user: User | null): string | null {
if (!user) return null; return user?.image || null;
const value = user.user_metadata?.avatar_url ?? user.user_metadata?.picture;
return typeof value === 'string' && value.length > 0 ? value : null;
} }
export function AuthProvider({ children }: PropsWithChildren) { export function AuthProvider({ children }: PropsWithChildren) {
const [session, setSession] = useState<Session | null>(null); const { data, isPending } = authClient.useSession();
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => { const user = data?.user ?? null;
let mounted = true; const session = data?.session ?? null;
const init = async () => {
const { data } = await supabase.auth.getSession();
if (!mounted) return;
setSession(data.session);
setUser(data.session?.user ?? null);
setApiAccessToken(data.session?.access_token ?? null);
setLoading(false);
};
void init();
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_event, nextSession) => {
setSession(nextSession);
setUser(nextSession?.user ?? null);
setApiAccessToken(nextSession?.access_token ?? null);
setLoading(false);
});
return () => {
mounted = false;
subscription.unsubscribe();
};
}, []);
const value = useMemo<AuthContextValue>(() => { const value = useMemo<AuthContextValue>(() => {
const displayName = getDisplayName(user); const displayName = getDisplayName(user);
@@ -116,13 +70,13 @@ export function AuthProvider({ children }: PropsWithChildren) {
return { return {
user, user,
session, session,
loading, loading: isPending,
isAuthenticated: Boolean(user), isAuthenticated: Boolean(user),
displayName, displayName,
initials, initials,
avatarUrl, avatarUrl,
signInWithPassword: async ({ email, password }) => { signInWithPassword: async ({ email, password }) => {
const { error } = await supabase.auth.signInWithPassword({ const { error } = await authClient.signIn.email({
email, email,
password, password,
}); });
@@ -132,15 +86,10 @@ export function AuthProvider({ children }: PropsWithChildren) {
} }
}, },
signUp: async ({ email, password, fullName }) => { signUp: async ({ email, password, fullName }) => {
const { data, error } = await supabase.auth.signUp({ const { data: signUpData, error } = await authClient.signUp.email({
email, email,
password, password,
options: {
data: {
full_name: fullName,
name: fullName, name: fullName,
},
},
}); });
if (error) { if (error) {
@@ -148,15 +97,12 @@ export function AuthProvider({ children }: PropsWithChildren) {
} }
return { return {
requiresEmailConfirmation: !data.session, requiresEmailConfirmation: !signUpData?.session,
}; };
}, },
updateProfile: async ({ fullName }) => { updateProfile: async ({ fullName }) => {
const { error } = await supabase.auth.updateUser({ const { error } = await authClient.user.update({
data: {
full_name: fullName,
name: fullName, name: fullName,
},
}); });
if (error) { if (error) {
@@ -164,8 +110,10 @@ export function AuthProvider({ children }: PropsWithChildren) {
} }
}, },
updatePassword: async ({ password }) => { updatePassword: async ({ password }) => {
const { error } = await supabase.auth.updateUser({ // Better Auth uses changePassword for authenticated users
password, const { error } = await authClient.changePassword({
newPassword: password,
revokeOtherSessions: true,
}); });
if (error) { if (error) {
@@ -173,13 +121,13 @@ export function AuthProvider({ children }: PropsWithChildren) {
} }
}, },
signOut: async () => { signOut: async () => {
const { error } = await supabase.auth.signOut(); const { error } = await authClient.signOut();
if (error) { if (error) {
throw error; throw error;
} }
}, },
}; };
}, [loading, session, user]); }, [isPending, session, user]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
} }

View File

@@ -1,18 +0,0 @@
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error(
'Missing Supabase environment variables. Define VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY.'
);
}
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
},
});