@create-lft-app/nextjs 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +549 -549
  2. package/package.json +48 -48
  3. package/template/CLAUDE.md +1239 -279
  4. package/template/drizzle.config.ts +12 -12
  5. package/template/eslint.config.mjs +16 -16
  6. package/template/gitignore +36 -36
  7. package/template/next.config.ts +7 -7
  8. package/template/package.json +86 -86
  9. package/template/postcss.config.mjs +7 -7
  10. package/template/proxy.ts +12 -12
  11. package/template/public/logolft.svg +11 -11
  12. package/template/src/app/(auth)/dashboard/dashboard-content.tsx +124 -124
  13. package/template/src/app/(auth)/dashboard/page.tsx +9 -9
  14. package/template/src/app/(auth)/layout.tsx +7 -7
  15. package/template/src/app/(auth)/users/page.tsx +9 -9
  16. package/template/src/app/(auth)/users/users-content.tsx +26 -26
  17. package/template/src/app/(public)/layout.tsx +7 -7
  18. package/template/src/app/(public)/login/page.tsx +17 -17
  19. package/template/src/app/api/webhooks/route.ts +20 -20
  20. package/template/src/app/globals.css +249 -249
  21. package/template/src/app/layout.tsx +37 -37
  22. package/template/src/app/page.tsx +5 -5
  23. package/template/src/app/providers.tsx +27 -27
  24. package/template/src/components/layout/main-content.tsx +28 -28
  25. package/template/src/components/layout/sidebar-context.tsx +33 -33
  26. package/template/src/components/layout/sidebar.tsx +141 -146
  27. package/template/src/components/tables/data-table-column-header.tsx +68 -68
  28. package/template/src/components/tables/data-table-date-filter.tsx +203 -0
  29. package/template/src/components/tables/data-table-faceted-filter.tsx +185 -0
  30. package/template/src/components/tables/data-table-filters-dropdown.tsx +130 -0
  31. package/template/src/components/tables/data-table-number-filter.tsx +295 -0
  32. package/template/src/components/tables/data-table-pagination.tsx +99 -99
  33. package/template/src/components/tables/data-table-toolbar.tsx +140 -50
  34. package/template/src/components/tables/data-table-view-options.tsx +63 -59
  35. package/template/src/components/tables/data-table.tsx +148 -128
  36. package/template/src/components/tables/index.ts +9 -5
  37. package/template/src/components/ui/accordion.tsx +58 -58
  38. package/template/src/components/ui/alert-dialog.tsx +165 -165
  39. package/template/src/components/ui/alert.tsx +66 -66
  40. package/template/src/components/ui/animations/index.ts +44 -44
  41. package/template/src/components/ui/avatar.tsx +55 -55
  42. package/template/src/components/ui/badge.tsx +50 -50
  43. package/template/src/components/ui/button.tsx +118 -118
  44. package/template/src/components/ui/calendar.tsx +220 -220
  45. package/template/src/components/ui/card.tsx +113 -113
  46. package/template/src/components/ui/checkbox.tsx +38 -38
  47. package/template/src/components/ui/collapsible.tsx +33 -33
  48. package/template/src/components/ui/command.tsx +196 -196
  49. package/template/src/components/ui/dialog.tsx +156 -156
  50. package/template/src/components/ui/dropdown-menu.tsx +280 -280
  51. package/template/src/components/ui/form.tsx +171 -171
  52. package/template/src/components/ui/icons.tsx +167 -167
  53. package/template/src/components/ui/input.tsx +28 -28
  54. package/template/src/components/ui/label.tsx +25 -25
  55. package/template/src/components/ui/motion.tsx +197 -197
  56. package/template/src/components/ui/page-transition.tsx +166 -166
  57. package/template/src/components/ui/popover.tsx +59 -59
  58. package/template/src/components/ui/progress.tsx +32 -32
  59. package/template/src/components/ui/radio-group.tsx +45 -45
  60. package/template/src/components/ui/scroll-area.tsx +63 -63
  61. package/template/src/components/ui/select.tsx +208 -208
  62. package/template/src/components/ui/separator.tsx +28 -28
  63. package/template/src/components/ui/sheet.tsx +170 -170
  64. package/template/src/components/ui/sidebar.tsx +726 -726
  65. package/template/src/components/ui/skeleton.tsx +15 -15
  66. package/template/src/components/ui/slider.tsx +58 -58
  67. package/template/src/components/ui/sonner.tsx +47 -47
  68. package/template/src/components/ui/spinner.tsx +27 -27
  69. package/template/src/components/ui/submit-button.tsx +47 -47
  70. package/template/src/components/ui/switch.tsx +31 -31
  71. package/template/src/components/ui/table.tsx +120 -120
  72. package/template/src/components/ui/tabs.tsx +75 -75
  73. package/template/src/components/ui/textarea.tsx +26 -26
  74. package/template/src/components/ui/tooltip.tsx +70 -70
  75. package/template/src/config/navigation.ts +59 -69
  76. package/template/src/config/roles.ts +27 -0
  77. package/template/src/config/site.ts +12 -12
  78. package/template/src/db/index.ts +12 -12
  79. package/template/src/db/schema/index.ts +1 -1
  80. package/template/src/db/schema/users.ts +16 -16
  81. package/template/src/db/seed.ts +39 -39
  82. package/template/src/hooks/index.ts +3 -3
  83. package/template/src/hooks/use-mobile.ts +21 -21
  84. package/template/src/hooks/useDataTable.ts +82 -82
  85. package/template/src/hooks/useDebounce.ts +49 -49
  86. package/template/src/hooks/useMediaQuery.ts +36 -36
  87. package/template/src/lib/date/config.ts +36 -34
  88. package/template/src/lib/date/formatters.ts +127 -120
  89. package/template/src/lib/date/index.ts +26 -19
  90. package/template/src/lib/excel/exporter.ts +89 -89
  91. package/template/src/lib/excel/index.ts +14 -14
  92. package/template/src/lib/excel/parser.ts +96 -96
  93. package/template/src/lib/query-client.ts +35 -35
  94. package/template/src/lib/supabase/admin.ts +23 -0
  95. package/template/src/lib/supabase/client.ts +11 -11
  96. package/template/src/lib/supabase/proxy.ts +67 -67
  97. package/template/src/lib/supabase/server.ts +38 -38
  98. package/template/src/lib/supabase/types.ts +53 -53
  99. package/template/src/lib/utils.ts +6 -6
  100. package/template/src/lib/validations/common.ts +75 -75
  101. package/template/src/lib/validations/index.ts +20 -20
  102. package/template/src/modules/auth/actions/auth-actions.ts +59 -59
  103. package/template/src/modules/auth/components/login-form.tsx +68 -68
  104. package/template/src/modules/auth/hooks/useAuth.ts +38 -38
  105. package/template/src/modules/auth/hooks/useAuthMutations.ts +43 -43
  106. package/template/src/modules/auth/hooks/useAuthQueries.ts +43 -43
  107. package/template/src/modules/auth/index.ts +12 -12
  108. package/template/src/modules/auth/schemas/auth.schema.ts +32 -32
  109. package/template/src/modules/auth/stores/useAuthStore.ts +37 -37
  110. package/template/src/modules/users/actions/users-actions.ts +166 -94
  111. package/template/src/modules/users/columns.tsx +106 -86
  112. package/template/src/modules/users/components/users-list.tsx +48 -22
  113. package/template/src/modules/users/hooks/useUsers.ts +39 -39
  114. package/template/src/modules/users/hooks/useUsersMutations.ts +55 -55
  115. package/template/src/modules/users/hooks/useUsersQueries.ts +35 -35
  116. package/template/src/modules/users/index.ts +30 -12
  117. package/template/src/modules/users/schemas/users.schema.ts +51 -23
  118. package/template/src/modules/users/stores/useUsersStore.ts +60 -60
  119. package/template/src/modules/users/types/auth-user.types.ts +42 -0
  120. package/template/src/modules/users/utils/user-mapper.ts +32 -0
  121. package/template/src/stores/index.ts +1 -1
  122. package/template/src/stores/useUiStore.ts +55 -55
  123. package/template/src/types/api.ts +28 -28
  124. package/template/src/types/index.ts +2 -2
  125. package/template/src/types/table.ts +34 -34
  126. package/template/supabase/config.toml +94 -94
  127. package/template/tsconfig.json +42 -42
  128. package/template/tsconfig.tsbuildinfo +1 -1
@@ -1,43 +1,43 @@
1
- 'use client'
2
-
3
- import { useQuery } from '@tanstack/react-query'
4
- import { createClient } from '@/lib/supabase/client'
5
-
6
- export const authKeys = {
7
- all: ['auth'] as const,
8
- user: () => [...authKeys.all, 'user'] as const,
9
- session: () => [...authKeys.all, 'session'] as const,
10
- }
11
-
12
- export function useAuthQueries() {
13
- const supabase = createClient()
14
-
15
- const userQuery = useQuery({
16
- queryKey: authKeys.user(),
17
- queryFn: async () => {
18
- const { data: { user }, error } = await supabase.auth.getUser()
19
- if (error) throw error
20
- return user
21
- },
22
- staleTime: 1000 * 60 * 5, // 5 minutos
23
- })
24
-
25
- const sessionQuery = useQuery({
26
- queryKey: authKeys.session(),
27
- queryFn: async () => {
28
- const { data: { session }, error } = await supabase.auth.getSession()
29
- if (error) throw error
30
- return session
31
- },
32
- staleTime: 1000 * 60 * 5,
33
- })
34
-
35
- return {
36
- user: userQuery.data,
37
- session: sessionQuery.data,
38
- isLoading: userQuery.isLoading || sessionQuery.isLoading,
39
- isAuthenticated: !!userQuery.data,
40
- userQuery,
41
- sessionQuery,
42
- }
43
- }
1
+ 'use client'
2
+
3
+ import { useQuery } from '@tanstack/react-query'
4
+ import { createClient } from '@/lib/supabase/client'
5
+
6
+ export const authKeys = {
7
+ all: ['auth'] as const,
8
+ user: () => [...authKeys.all, 'user'] as const,
9
+ session: () => [...authKeys.all, 'session'] as const,
10
+ }
11
+
12
+ export function useAuthQueries() {
13
+ const supabase = createClient()
14
+
15
+ const userQuery = useQuery({
16
+ queryKey: authKeys.user(),
17
+ queryFn: async () => {
18
+ const { data: { user }, error } = await supabase.auth.getUser()
19
+ if (error) throw error
20
+ return user
21
+ },
22
+ staleTime: 1000 * 60 * 5, // 5 minutos
23
+ })
24
+
25
+ const sessionQuery = useQuery({
26
+ queryKey: authKeys.session(),
27
+ queryFn: async () => {
28
+ const { data: { session }, error } = await supabase.auth.getSession()
29
+ if (error) throw error
30
+ return session
31
+ },
32
+ staleTime: 1000 * 60 * 5,
33
+ })
34
+
35
+ return {
36
+ user: userQuery.data,
37
+ session: sessionQuery.data,
38
+ isLoading: userQuery.isLoading || sessionQuery.isLoading,
39
+ isAuthenticated: !!userQuery.data,
40
+ userQuery,
41
+ sessionQuery,
42
+ }
43
+ }
@@ -1,12 +1,12 @@
1
- // Components
2
- export { LoginForm } from './components/login-form'
3
-
4
- // Hooks - Solo exportar el hook unificado
5
- export { useAuth } from './hooks/useAuth'
6
-
7
- // Schemas
8
- export { loginSchema, registerSchema } from './schemas/auth.schema'
9
- export type { LoginInput, RegisterInput } from './schemas/auth.schema'
10
-
11
- // Actions
12
- export { login, register, logout, getUser } from './actions/auth-actions'
1
+ // Components
2
+ export { LoginForm } from './components/login-form'
3
+
4
+ // Hooks - Solo exportar el hook unificado
5
+ export { useAuth } from './hooks/useAuth'
6
+
7
+ // Schemas
8
+ export { loginSchema, registerSchema } from './schemas/auth.schema'
9
+ export type { LoginInput, RegisterInput } from './schemas/auth.schema'
10
+
11
+ // Actions
12
+ export { login, register, logout, getUser } from './actions/auth-actions'
@@ -1,32 +1,32 @@
1
- import { z } from 'zod'
2
-
3
- export const loginSchema = z.object({
4
- email: z
5
- .string()
6
- .min(1, 'El email es requerido')
7
- .email('Email inválido'),
8
- password: z
9
- .string()
10
- .min(1, 'La contraseña es requerida')
11
- .min(6, 'La contraseña debe tener al menos 6 caracteres'),
12
- })
13
-
14
- export const registerSchema = z.object({
15
- email: z
16
- .string()
17
- .min(1, 'El email es requerido')
18
- .email('Email inválido'),
19
- password: z
20
- .string()
21
- .min(1, 'La contraseña es requerida')
22
- .min(6, 'La contraseña debe tener al menos 6 caracteres'),
23
- confirmPassword: z
24
- .string()
25
- .min(1, 'Confirma tu contraseña'),
26
- }).refine((data) => data.password === data.confirmPassword, {
27
- message: 'Las contraseñas no coinciden',
28
- path: ['confirmPassword'],
29
- })
30
-
31
- export type LoginInput = z.infer<typeof loginSchema>
32
- export type RegisterInput = z.infer<typeof registerSchema>
1
+ import { z } from 'zod'
2
+
3
+ export const loginSchema = z.object({
4
+ email: z
5
+ .string()
6
+ .min(1, 'El email es requerido')
7
+ .email('Email inválido'),
8
+ password: z
9
+ .string()
10
+ .min(1, 'La contraseña es requerida')
11
+ .min(6, 'La contraseña debe tener al menos 6 caracteres'),
12
+ })
13
+
14
+ export const registerSchema = z.object({
15
+ email: z
16
+ .string()
17
+ .min(1, 'El email es requerido')
18
+ .email('Email inválido'),
19
+ password: z
20
+ .string()
21
+ .min(1, 'La contraseña es requerida')
22
+ .min(6, 'La contraseña debe tener al menos 6 caracteres'),
23
+ confirmPassword: z
24
+ .string()
25
+ .min(1, 'Confirma tu contraseña'),
26
+ }).refine((data) => data.password === data.confirmPassword, {
27
+ message: 'Las contraseñas no coinciden',
28
+ path: ['confirmPassword'],
29
+ })
30
+
31
+ export type LoginInput = z.infer<typeof loginSchema>
32
+ export type RegisterInput = z.infer<typeof registerSchema>
@@ -1,37 +1,37 @@
1
- import { create } from 'zustand'
2
- import type { User } from '@supabase/supabase-js'
3
-
4
- interface AuthState {
5
- state: {
6
- user: User | null
7
- isLoading: boolean
8
- }
9
- actions: {
10
- setUser: (user: User | null) => void
11
- setLoading: (isLoading: boolean) => void
12
- reset: () => void
13
- }
14
- }
15
-
16
- const initialState = {
17
- user: null,
18
- isLoading: true,
19
- }
20
-
21
- export const useAuthStore = create<AuthState>()((set) => ({
22
- state: initialState,
23
- actions: {
24
- setUser: (user) =>
25
- set((state) => ({
26
- state: { ...state.state, user },
27
- })),
28
- setLoading: (isLoading) =>
29
- set((state) => ({
30
- state: { ...state.state, isLoading },
31
- })),
32
- reset: () =>
33
- set(() => ({
34
- state: initialState,
35
- })),
36
- },
37
- }))
1
+ import { create } from 'zustand'
2
+ import type { User } from '@supabase/supabase-js'
3
+
4
+ interface AuthState {
5
+ state: {
6
+ user: User | null
7
+ isLoading: boolean
8
+ }
9
+ actions: {
10
+ setUser: (user: User | null) => void
11
+ setLoading: (isLoading: boolean) => void
12
+ reset: () => void
13
+ }
14
+ }
15
+
16
+ const initialState = {
17
+ user: null,
18
+ isLoading: true,
19
+ }
20
+
21
+ export const useAuthStore = create<AuthState>()((set) => ({
22
+ state: initialState,
23
+ actions: {
24
+ setUser: (user) =>
25
+ set((state) => ({
26
+ state: { ...state.state, user },
27
+ })),
28
+ setLoading: (isLoading) =>
29
+ set((state) => ({
30
+ state: { ...state.state, isLoading },
31
+ })),
32
+ reset: () =>
33
+ set(() => ({
34
+ state: initialState,
35
+ })),
36
+ },
37
+ }))
@@ -1,94 +1,166 @@
1
- 'use server'
2
-
3
- import { createClient } from '@/lib/supabase/server'
4
- import { createUserSchema, updateUserSchema, type CreateUserInput, type UpdateUserInput } from '../schemas/users.schema'
5
-
6
- export async function getUsers() {
7
- const supabase = await createClient()
8
- const { data: { user } } = await supabase.auth.getUser()
9
-
10
- if (!user) throw new Error('Unauthorized')
11
-
12
- const { data, error } = await supabase
13
- .from('users')
14
- .select('*')
15
- .order('created_at', { ascending: false })
16
-
17
- if (error) throw error
18
- return data
19
- }
20
-
21
- export async function getUserById(id: string) {
22
- const supabase = await createClient()
23
- const { data: { user } } = await supabase.auth.getUser()
24
-
25
- if (!user) throw new Error('Unauthorized')
26
-
27
- const { data, error } = await supabase
28
- .from('users')
29
- .select('*')
30
- .eq('id', id)
31
- .single()
32
-
33
- if (error) throw error
34
- return data
35
- }
36
-
37
- export async function createUser(input: CreateUserInput) {
38
- const parsed = createUserSchema.safeParse(input)
39
-
40
- if (!parsed.success) {
41
- throw new Error(parsed.error.errors[0].message)
42
- }
43
-
44
- const supabase = await createClient()
45
- const { data: { user } } = await supabase.auth.getUser()
46
-
47
- if (!user) throw new Error('Unauthorized')
48
-
49
- const { data, error } = await supabase
50
- .from('users')
51
- .insert(parsed.data)
52
- .select()
53
- .single()
54
-
55
- if (error) throw error
56
- return data
57
- }
58
-
59
- export async function updateUser(id: string, input: UpdateUserInput) {
60
- const parsed = updateUserSchema.safeParse(input)
61
-
62
- if (!parsed.success) {
63
- throw new Error(parsed.error.errors[0].message)
64
- }
65
-
66
- const supabase = await createClient()
67
- const { data: { user } } = await supabase.auth.getUser()
68
-
69
- if (!user) throw new Error('Unauthorized')
70
-
71
- const { data, error } = await supabase
72
- .from('users')
73
- .update(parsed.data)
74
- .eq('id', id)
75
- .select()
76
- .single()
77
-
78
- if (error) throw error
79
- return data
80
- }
81
-
82
- export async function deleteUser(id: string) {
83
- const supabase = await createClient()
84
- const { data: { user } } = await supabase.auth.getUser()
85
-
86
- if (!user) throw new Error('Unauthorized')
87
-
88
- const { error } = await supabase
89
- .from('users')
90
- .delete()
91
- .eq('id', id)
92
-
93
- if (error) throw error
94
- }
1
+ 'use server'
2
+
3
+ import { createClient } from '@/lib/supabase/server'
4
+ import { createAdminClient } from '@/lib/supabase/admin'
5
+ import {
6
+ createAuthUserSchema,
7
+ updateAuthUserSchema,
8
+ type CreateAuthUserInput,
9
+ type UpdateAuthUserInput,
10
+ } from '../schemas/users.schema'
11
+ import { mapAuthUserToUser, mapAuthUsersToUsers } from '../utils/user-mapper'
12
+
13
+ /**
14
+ * Obtiene todos los usuarios desde auth.users
15
+ */
16
+ export async function getUsers() {
17
+ const supabase = await createClient()
18
+ const { data: { user } } = await supabase.auth.getUser()
19
+
20
+ if (!user) throw new Error('Unauthorized')
21
+
22
+ const adminClient = createAdminClient()
23
+ const { data, error } = await adminClient.auth.admin.listUsers()
24
+
25
+ if (error) throw error
26
+
27
+ return mapAuthUsersToUsers(data.users)
28
+ }
29
+
30
+ /**
31
+ * Obtiene un usuario por ID desde auth.users
32
+ */
33
+ export async function getUserById(id: string) {
34
+ const supabase = await createClient()
35
+ const { data: { user } } = await supabase.auth.getUser()
36
+
37
+ if (!user) throw new Error('Unauthorized')
38
+
39
+ const adminClient = createAdminClient()
40
+ const { data, error } = await adminClient.auth.admin.getUserById(id)
41
+
42
+ if (error) throw error
43
+
44
+ return mapAuthUserToUser(data.user)
45
+ }
46
+
47
+ /**
48
+ * Crea un nuevo usuario en auth.users
49
+ */
50
+ export async function createUser(input: CreateAuthUserInput) {
51
+ const parsed = createAuthUserSchema.safeParse(input)
52
+
53
+ if (!parsed.success) {
54
+ throw new Error(parsed.error.errors[0].message)
55
+ }
56
+
57
+ const supabase = await createClient()
58
+ const { data: { user } } = await supabase.auth.getUser()
59
+
60
+ if (!user) throw new Error('Unauthorized')
61
+
62
+ const adminClient = createAdminClient()
63
+
64
+ const { data, error } = await adminClient.auth.admin.createUser({
65
+ email: parsed.data.email,
66
+ password: parsed.data.password,
67
+ email_confirm: !parsed.data.send_invite,
68
+ app_metadata: {
69
+ role: parsed.data.role,
70
+ },
71
+ user_metadata: {
72
+ name: parsed.data.name,
73
+ avatar_url: parsed.data.avatar_url ?? null,
74
+ },
75
+ })
76
+
77
+ if (error) throw error
78
+
79
+ // Enviar email de invitación si se solicita y no se proporcionó password
80
+ if (parsed.data.send_invite && !parsed.data.password) {
81
+ await adminClient.auth.admin.inviteUserByEmail(parsed.data.email)
82
+ }
83
+
84
+ return mapAuthUserToUser(data.user)
85
+ }
86
+
87
+ /**
88
+ * Actualiza un usuario en auth.users
89
+ */
90
+ export async function updateUser(id: string, input: UpdateAuthUserInput) {
91
+ const parsed = updateAuthUserSchema.safeParse(input)
92
+
93
+ if (!parsed.success) {
94
+ throw new Error(parsed.error.errors[0].message)
95
+ }
96
+
97
+ const supabase = await createClient()
98
+ const { data: { user } } = await supabase.auth.getUser()
99
+
100
+ if (!user) throw new Error('Unauthorized')
101
+
102
+ const adminClient = createAdminClient()
103
+
104
+ // Obtener usuario actual para merge de metadata
105
+ const { data: currentUser, error: fetchError } = await adminClient.auth.admin.getUserById(id)
106
+
107
+ if (fetchError) throw fetchError
108
+ if (!currentUser.user) throw new Error('User not found')
109
+
110
+ const updatePayload: Parameters<typeof adminClient.auth.admin.updateUserById>[1] = {}
111
+
112
+ if (parsed.data.email) {
113
+ updatePayload.email = parsed.data.email
114
+ }
115
+
116
+ if (parsed.data.password) {
117
+ updatePayload.password = parsed.data.password
118
+ }
119
+
120
+ // Merge app_metadata (solo role)
121
+ if (parsed.data.role) {
122
+ updatePayload.app_metadata = {
123
+ ...currentUser.user.app_metadata,
124
+ role: parsed.data.role,
125
+ }
126
+ }
127
+
128
+ // Merge user_metadata
129
+ const hasUserMetadataChanges =
130
+ parsed.data.name !== undefined ||
131
+ parsed.data.avatar_url !== undefined
132
+
133
+ if (hasUserMetadataChanges) {
134
+ updatePayload.user_metadata = {
135
+ ...currentUser.user.user_metadata,
136
+ ...(parsed.data.name !== undefined && { name: parsed.data.name }),
137
+ ...(parsed.data.avatar_url !== undefined && { avatar_url: parsed.data.avatar_url }),
138
+ }
139
+ }
140
+
141
+ const { data, error } = await adminClient.auth.admin.updateUserById(id, updatePayload)
142
+
143
+ if (error) throw error
144
+
145
+ return mapAuthUserToUser(data.user)
146
+ }
147
+
148
+ /**
149
+ * Elimina un usuario de auth.users
150
+ */
151
+ export async function deleteUser(id: string) {
152
+ const supabase = await createClient()
153
+ const { data: { user } } = await supabase.auth.getUser()
154
+
155
+ if (!user) throw new Error('Unauthorized')
156
+
157
+ // Prevenir auto-eliminación
158
+ if (user.id === id) {
159
+ throw new Error('No puedes eliminar tu propio usuario')
160
+ }
161
+
162
+ const adminClient = createAdminClient()
163
+ const { error } = await adminClient.auth.admin.deleteUser(id)
164
+
165
+ if (error) throw error
166
+ }