Implement next-auth v5
This commit is contained in:
parent
a9e4956909
commit
187b55aad7
15 changed files with 420 additions and 547 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { kv } from '@vercel/kv'
|
||||
import { currentUser } from '@clerk/nextjs'
|
||||
import { auth } from '@/auth'
|
||||
|
||||
import { type Chat } from '@/lib/types'
|
||||
|
||||
|
|
@ -44,41 +44,50 @@ export async function getChat(id: string, userId: string) {
|
|||
}
|
||||
|
||||
export async function removeChat({ id, path }: { id: string; path: string }) {
|
||||
const user = await currentUser()
|
||||
const session = await auth<{ stuff: string }>()
|
||||
|
||||
if (!user) {
|
||||
if (!session) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
const uid = await kv.hget<string>(`chat:${id}`, 'userId')
|
||||
|
||||
if (uid !== user.id) {
|
||||
if (uid !== session?.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
await kv.del(`chat:${id}`)
|
||||
await kv.zrem(`user:chat:${user.id}`, `chat:${id}`)
|
||||
await kv.zrem(`user:chat:${session.user.id}`, `chat:${id}`)
|
||||
|
||||
revalidatePath('/')
|
||||
revalidatePath(path)
|
||||
}
|
||||
|
||||
export async function clearChats() {
|
||||
const user = await currentUser()
|
||||
const session = await auth()
|
||||
|
||||
if (!user) {
|
||||
if (!session) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
const chats: string[] = await kv.zrange(`user:chat:${user.id}`, 0, -1, {
|
||||
rev: true
|
||||
})
|
||||
if (!session.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
const chats: string[] = await kv.zrange(
|
||||
`user:chat:${session.user.id}`,
|
||||
0,
|
||||
-1,
|
||||
{
|
||||
rev: true
|
||||
}
|
||||
)
|
||||
|
||||
const pipeline = kv.pipeline()
|
||||
|
||||
for (const chat of chats) {
|
||||
pipeline.del(chat)
|
||||
pipeline.zrem(`user:chat:${user.id}`, chat)
|
||||
pipeline.zrem(`user:chat:${session.user.id}`, chat)
|
||||
}
|
||||
|
||||
await pipeline.exec()
|
||||
|
|
@ -97,9 +106,17 @@ export async function getSharedChat(id: string) {
|
|||
}
|
||||
|
||||
export async function shareChat(chat: Chat) {
|
||||
const user = await currentUser()
|
||||
const session = await auth()
|
||||
|
||||
if (!user || chat.userId !== user.id) {
|
||||
if (!session) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
if (!session.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
if (chat.userId !== session.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
|
|
|
|||
2
app/api/auth/[...nextauth]/route.ts
Normal file
2
app/api/auth/[...nextauth]/route.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { GET, POST } from '@/auth'
|
||||
export const runtime = 'edge'
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { Metadata } from 'next'
|
||||
|
||||
import { ClerkProvider } from '@clerk/nextjs'
|
||||
import { Toaster } from 'react-hot-toast'
|
||||
|
||||
import '@/app/globals.css'
|
||||
|
|
@ -33,29 +32,25 @@ interface RootLayoutProps {
|
|||
|
||||
export default function RootLayout({ children }: RootLayoutProps) {
|
||||
return (
|
||||
<ClerkProvider>
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head />
|
||||
<body
|
||||
className={cn(
|
||||
'font-sans antialiased',
|
||||
fontSans.variable,
|
||||
fontMono.variable
|
||||
)}
|
||||
>
|
||||
<Toaster />
|
||||
<Providers attribute="class" defaultTheme="system" enableSystem>
|
||||
<div className="flex min-h-screen flex-col">
|
||||
{/* @ts-ignore */}
|
||||
<Header />
|
||||
<main className="flex flex-1 flex-col bg-muted/50">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
<TailwindIndicator />
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
</ClerkProvider>
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head />
|
||||
<body
|
||||
className={cn(
|
||||
'font-sans antialiased',
|
||||
fontSans.variable,
|
||||
fontMono.variable
|
||||
)}
|
||||
>
|
||||
<Toaster />
|
||||
<Providers attribute="class" defaultTheme="system" enableSystem>
|
||||
<div className="flex flex-col min-h-screen">
|
||||
{/* @ts-ignore */}
|
||||
<Header />
|
||||
<main className="flex flex-col flex-1 bg-muted/50">{children}</main>
|
||||
</div>
|
||||
<TailwindIndicator />
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { nanoid } from '@/lib/utils'
|
||||
import { Chat } from '@/components/chat'
|
||||
|
||||
// export const runtime = 'edge'
|
||||
export const preferredRegion = 'home'
|
||||
export const runtime = 'edge'
|
||||
|
||||
export default function IndexPage() {
|
||||
const id = nanoid()
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
import { ClerkLoaded, ClerkLoading, SignIn } from '@clerk/nextjs'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ExternalLink } from '@/components/external-link'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
import { IconSpinner } from '@/components/ui/icons'
|
||||
import { FooterText } from '@/components/footer'
|
||||
|
||||
export default function SignInPage() {
|
||||
return (
|
||||
<div className="flex h-full min-h-screen flex-col items-center justify-center">
|
||||
<div className="space-y-4">
|
||||
<ClerkLoading>
|
||||
<div className="flex items-center text-sm text-muted-foreground">
|
||||
<IconSpinner className="mr-2 h-5 w-5" /> Loading...
|
||||
</div>
|
||||
</ClerkLoading>
|
||||
<ClerkLoaded>
|
||||
<SignIn
|
||||
appearance={{
|
||||
elements: {
|
||||
card: 'shadow rounded-lg border border-border',
|
||||
formFieldInput:
|
||||
'flex h-9 w-full rounded-md px-3 py-2 text-sm shadow-sm',
|
||||
formButtonPrimary: 'normal-case',
|
||||
footerAction: 'text-sm',
|
||||
footerActionLink: 'font-medium'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<FooterText />
|
||||
</ClerkLoaded>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
13
app/sign-in/page.tsx
Normal file
13
app/sign-in/page.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { FooterText } from '@/components/footer'
|
||||
import { LoginButton } from '@/components/login-button'
|
||||
|
||||
export default function SignInPage() {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full min-h-screen">
|
||||
<div className="space-y-4">
|
||||
<LoginButton />
|
||||
<FooterText />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
import { ClerkLoaded, ClerkLoading, SignUp } from '@clerk/nextjs'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
import { ExternalLink } from '@/components/external-link'
|
||||
import { IconSpinner } from '@/components/ui/icons'
|
||||
import { FooterText } from '@/components/footer'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex h-full min-h-screen flex-col items-center justify-center">
|
||||
<div className="space-y-4">
|
||||
<ClerkLoading>
|
||||
<div className="flex items-center text-sm text-muted-foreground">
|
||||
<IconSpinner className="mr-2 h-5 w-5" /> Loading...
|
||||
</div>
|
||||
</ClerkLoading>
|
||||
<ClerkLoaded>
|
||||
<SignUp
|
||||
appearance={{
|
||||
elements: {
|
||||
card: 'shadow rounded-lg border border-border',
|
||||
formFieldInput:
|
||||
'flex h-9 w-full rounded-md px-3 py-2 text-sm shadow-sm',
|
||||
formButtonPrimary: 'normal-case',
|
||||
footerAction: 'text-sm',
|
||||
footerActionLink: 'font-medium hover:underline',
|
||||
identityPreview: 'rounded-md'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<FooterText />
|
||||
</ClerkLoaded>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue