Implement next-auth v5

This commit is contained in:
Jared Palmer 2023-06-16 11:49:14 -04:00
parent a9e4956909
commit 187b55aad7
15 changed files with 420 additions and 547 deletions

View file

@ -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')
}

View file

@ -0,0 +1,2 @@
export { GET, POST } from '@/auth'
export const runtime = 'edge'

View file

@ -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>
)
}

View file

@ -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()

View file

@ -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
View 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>
)
}

View file

@ -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>
)
}