Move to clerk

This commit is contained in:
Jared Palmer 2023-06-13 17:31:15 -04:00
parent cd340320b7
commit 567b0ac313
18 changed files with 550 additions and 178 deletions

View file

@ -4,6 +4,7 @@ import { revalidatePath } from 'next/cache'
import { kv } from '@vercel/kv'
import { type Chat } from '@/lib/types'
import { currentUser } from '@clerk/nextjs'
export async function getChats(userId?: string | null) {
if (!userId) {
@ -40,24 +41,19 @@ export async function getChat(id: string, userId: string) {
return chat
}
export async function removeChat({
id,
path,
userId
}: {
id: string
userId: string
path: string
}) {
// @todo next-auth@v5 doesn't work in server actions yet
// const session = await auth();
export async function removeChat({ id, path }: { id: string; path: string }) {
const user = await currentUser()
if (!user) {
throw new Error('Unauthorized')
}
const uid = await kv.hget<string>(`chat:${id}`, 'userId')
if (uid !== userId) {
if (uid !== user.id) {
throw new Error('Unauthorized')
}
await kv.del(`chat:${id}`)
await kv.zrem(`user:chat:${userId}`, `chat:${id}`)
await kv.zrem(`user:chat:${user.id}`, `chat:${id}`)
revalidatePath('/')
revalidatePath('/chat/[id]')

View file

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

View file

@ -1,11 +1,11 @@
import { auth } from '@/auth'
import { kv } from '@vercel/kv'
import { OpenAIStream, StreamingTextResponse } from 'ai-connector'
import { Configuration, OpenAIApi } from 'openai-edge'
import { nanoid } from '@/lib/utils'
import { currentUser } from '@clerk/nextjs'
// export const runtime = 'edge'
export const runtime = 'edge'
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY
@ -17,13 +17,15 @@ if (!process.env.OPENAI_API_KEY) {
throw new Error('Missing env var from OpenAI')
}
export const POST = auth(async function POST(req: Request) {
export async function POST(req: Request) {
const user = await currentUser()
if (user == null) {
return new Response('Unauthorized', { status: 401 })
}
const json = await req.json()
// @ts-ignore
const messages = json.messages.map((m: any) => ({
content: m.content,
role: m.role
}))
const { messages } = json
const res = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages,
@ -35,14 +37,10 @@ export const POST = auth(async function POST(req: Request) {
stream: true
})
const stream = await OpenAIStream(res, {
const stream = OpenAIStream(res, {
async onCompletion(completion) {
// @ts-ignore
if (req.auth?.user?.email == null) {
return
}
const title = json.messages[0].content.substring(0, 100)
const userId = (req as any).auth?.user?.email
const userId = user.id
const id = json.id ?? nanoid()
const createdAt = Date.now()
const payload = {
@ -67,4 +65,4 @@ export const POST = auth(async function POST(req: Request) {
})
return new StreamingTextResponse(stream)
})
}

View file

@ -1,8 +1,9 @@
import { type Metadata } from 'next'
import { auth } from '@/auth'
import { Chat } from '@/components/chat'
import { getChat } from '@/app/actions'
import { Header } from '@/components/header'
import { auth } from '@clerk/nextjs'
// export const runtime = 'edge'
export const preferredRegion = 'home'
@ -16,16 +17,24 @@ export interface ChatPageProps {
export async function generateMetadata({
params
}: ChatPageProps): Promise<Metadata> {
const session = await auth()
const chat = await getChat(params.id, session?.user?.email ?? '')
const { user } = await auth()
const chat = await getChat(params.id, user?.id ?? '')
return {
title: chat?.title.slice(0, 50) ?? 'Chat'
}
}
export default async function ChatPage({ params }: ChatPageProps) {
const session = await auth()
const chat = await getChat(params.id, session?.user?.email ?? '')
const { user } = await auth()
const chat = await getChat(params.id, user?.id ?? '')
return <Chat id={chat.id} initialMessages={chat.messages} />
return (
<div className="flex flex-col min-h-screen">
{/* @ts-ignore */}
<Header />
<main className="flex-1 bg-muted/50">
<Chat id={chat.id} initialMessages={chat.messages} />
</main>
</div>
)
}

View file

@ -6,6 +6,7 @@ import { cn } from '@/lib/utils'
import { Header } from '@/components/header'
import { TailwindIndicator } from '@/components/tailwind-indicator'
import { ThemeProvider } from '@/components/theme-provider'
import { ClerkProvider } from '@clerk/nextjs'
export const metadata: Metadata = {
title: {
@ -30,24 +31,22 @@ interface RootLayoutProps {
export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="en" suppressHydrationWarning>
<head />
<body
className={cn(
'font-sans antialiased',
fontSans.variable,
fontMono.variable
)}
>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<div className="flex min-h-screen flex-col">
{/* @ts-ignore */}
<Header />
<main className="flex-1 bg-muted/50">{children}</main>
</div>
<TailwindIndicator />
</ThemeProvider>
</body>
</html>
<ClerkProvider>
<html lang="en" suppressHydrationWarning>
<head />
<body
className={cn(
'font-sans antialiased',
fontSans.variable,
fontMono.variable
)}
>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
<TailwindIndicator />
</ThemeProvider>
</body>
</html>
</ClerkProvider>
)
}

View file

@ -1,8 +1,17 @@
import { Chat } from '@/components/chat'
import { Header } from '@/components/header'
// export const runtime = 'edge'
export const preferredRegion = 'home'
export default async function IndexPage() {
return <Chat />
return (
<div className="flex flex-col min-h-screen">
{/* @ts-ignore */}
<Header />
<main className="flex-1 bg-muted/50">
<Chat />
</main>
</div>
)
}

View file

@ -0,0 +1,11 @@
import { SignIn } from '@clerk/nextjs'
export default function Page() {
return (
<div className="flex flex-col items-center justify-center h-full min-h-screen">
<div className="flex flex-col items-center justify-center h-full">
<SignIn />
</div>
</div>
)
}

View file

@ -0,0 +1,11 @@
import { SignUp } from '@clerk/nextjs'
export default function Page() {
return (
<div className="flex flex-col items-center justify-center h-full min-h-screen">
<div className="flex flex-col items-center justify-center h-full">
<SignUp />
</div>
</div>
)
}