forked from vercel/ai-chatbot
-
Notifications
You must be signed in to change notification settings - Fork 89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Supabaseify #1
Merged
Merged
Supabaseify #1
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
c5a7724
feat: migrate to supabase auth.
thorwebdev 80be27c
chore: typo.
thorwebdev 842803c
feat: add middleware auth redirect.
thorwebdev 2052847
feat: migrate kv to postgres.
thorwebdev 045b0b9
fix: allow public access for share route.
thorwebdev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,120 +1,97 @@ | ||
'use server' | ||
|
||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs' | ||
import { cookies } from 'next/headers' | ||
import { Database } from '@/lib/db_types' | ||
import { revalidatePath } from 'next/cache' | ||
import { redirect } from 'next/navigation' | ||
import { kv } from '@vercel/kv' | ||
|
||
import { auth } from '@/auth' | ||
import { type Chat } from '@/lib/types' | ||
import { auth } from '@/auth' | ||
|
||
const supabase = createServerActionClient<Database>({ cookies }) | ||
|
||
export async function getChats(userId?: string | null) { | ||
if (!userId) { | ||
return [] | ||
} | ||
|
||
try { | ||
const pipeline = kv.pipeline() | ||
const chats: string[] = await kv.zrange(`user:chat:${userId}`, 0, -1, { | ||
rev: true | ||
}) | ||
|
||
for (const chat of chats) { | ||
pipeline.hgetall(chat) | ||
} | ||
const { data } = await supabase | ||
.from('chats') | ||
.select('payload') | ||
.order('payload->createdAt', { ascending: false }) | ||
.throwOnError() | ||
|
||
const results = await pipeline.exec() | ||
|
||
return results as Chat[] | ||
return (data?.map(entry => entry.payload) as Chat[]) ?? [] | ||
} catch (error) { | ||
return [] | ||
} | ||
} | ||
|
||
export async function getChat(id: string, userId: string) { | ||
const chat = await kv.hgetall<Chat>(`chat:${id}`) | ||
|
||
if (!chat || (userId && chat.userId !== userId)) { | ||
return null | ||
} | ||
export async function getChat(id: string) { | ||
const { data } = await supabase | ||
.from('chats') | ||
.select('payload') | ||
.eq('id', id) | ||
.maybeSingle() | ||
|
||
return chat | ||
return (data?.payload as Chat) ?? null | ||
} | ||
|
||
export async function removeChat({ id, path }: { id: string; path: string }) { | ||
const session = await auth() | ||
|
||
if (!session) { | ||
return { | ||
error: 'Unauthorized' | ||
} | ||
} | ||
|
||
const uid = await kv.hget<string>(`chat:${id}`, 'userId') | ||
try { | ||
await supabase.from('chats').delete().eq('id', id).throwOnError() | ||
|
||
if (uid !== session?.user?.id) { | ||
revalidatePath('/') | ||
return revalidatePath(path) | ||
} catch (error) { | ||
return { | ||
error: 'Unauthorized' | ||
} | ||
} | ||
|
||
await kv.del(`chat:${id}`) | ||
await kv.zrem(`user:chat:${session.user.id}`, `chat:${id}`) | ||
|
||
revalidatePath('/') | ||
return revalidatePath(path) | ||
} | ||
|
||
export async function clearChats() { | ||
const session = await auth() | ||
|
||
if (!session?.user?.id) { | ||
try { | ||
const session = await auth() | ||
await supabase | ||
.from('chats') | ||
.delete() | ||
.eq('user_id', session?.user.id) | ||
.throwOnError() | ||
revalidatePath('/') | ||
return redirect('/') | ||
} catch (error) { | ||
console.log('clear chats error', error) | ||
return { | ||
error: 'Unauthorized' | ||
} | ||
} | ||
|
||
const chats: string[] = await kv.zrange(`user:chat:${session.user.id}`, 0, -1) | ||
if (!chats.length) { | ||
return redirect('/') | ||
} | ||
const pipeline = kv.pipeline() | ||
|
||
for (const chat of chats) { | ||
pipeline.del(chat) | ||
pipeline.zrem(`user:chat:${session.user.id}`, chat) | ||
} | ||
|
||
await pipeline.exec() | ||
|
||
revalidatePath('/') | ||
return redirect('/') | ||
} | ||
|
||
export async function getSharedChat(id: string) { | ||
const chat = await kv.hgetall<Chat>(`chat:${id}`) | ||
|
||
if (!chat || !chat.sharePath) { | ||
return null | ||
} | ||
|
||
return chat | ||
const { data } = await supabase | ||
.from('chats') | ||
.select('payload') | ||
.eq('id', id) | ||
.not('payload->sharePath', 'is', null) | ||
.maybeSingle() | ||
|
||
return (data?.payload as Chat) ?? null | ||
} | ||
|
||
export async function shareChat(chat: Chat) { | ||
const session = await auth() | ||
|
||
if (!session?.user?.id || session.user.id !== chat.userId) { | ||
return { | ||
error: 'Unauthorized' | ||
} | ||
} | ||
|
||
const payload = { | ||
...chat, | ||
sharePath: `/share/${chat.id}` | ||
} | ||
|
||
await kv.hmset(`chat:${chat.id}`, payload) | ||
await supabase | ||
.from('chats') | ||
.update({ payload: payload as any }) | ||
.eq('id', chat.id) | ||
.throwOnError() | ||
|
||
return payload | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' | ||
import { cookies } from 'next/headers' | ||
import { NextResponse } from 'next/server' | ||
|
||
export async function GET(request: Request) { | ||
// The `/auth/callback` route is required for the server-side auth flow implemented | ||
// by the Auth Helpers package. It exchanges an auth code for the user's session. | ||
// https://supabase.com/docs/guides/auth/auth-helpers/nextjs#managing-sign-in-with-code-exchange | ||
const requestUrl = new URL(request.url) | ||
const code = requestUrl.searchParams.get('code') | ||
|
||
if (code) { | ||
const supabase = createRouteHandlerClient({ cookies }) | ||
await supabase.auth.exchangeCodeForSession(code) | ||
} | ||
|
||
// URL to redirect to after sign in process completes | ||
return NextResponse.redirect(requestUrl.origin) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,10 @@ | ||
import NextAuth, { type DefaultSession } from 'next-auth' | ||
import GitHub from 'next-auth/providers/github' | ||
import { NextResponse } from 'next/server' | ||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs' | ||
import { cookies } from 'next/headers' | ||
|
||
declare module 'next-auth' { | ||
interface Session { | ||
user: { | ||
/** The user's id. */ | ||
id: string | ||
} & DefaultSession['user'] | ||
} | ||
export const auth = async () => { | ||
// Create a Supabase client configured to use cookies | ||
const supabase = createServerActionClient({ cookies }) | ||
const { data, error } = await supabase.auth.getSession() | ||
if (error) throw error | ||
return data.session | ||
} | ||
|
||
export const { | ||
handlers: { GET, POST }, | ||
auth, | ||
CSRF_experimental | ||
} = NextAuth({ | ||
providers: [GitHub], | ||
callbacks: { | ||
jwt({ token, profile }) { | ||
if (profile) { | ||
token.id = profile.id | ||
token.image = profile.picture | ||
} | ||
return token | ||
}, | ||
authorized({ auth }) { | ||
return !!auth?.user | ||
} | ||
}, | ||
pages: { | ||
signIn: '/sign-in' | ||
} | ||
}) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just to call out a potential issue - these are actual config/UX choices https://github.com/vercel-labs/ai-chatbot/pull/90/files i think you have mostly addressed them (except for the forced signin?) but just proactively calling it out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah interesting, their deployed demo actually allows anonymous conversations without requiring you to log in. But yah, happy to add a middleware based redirect if user isn't logged in, is that your preference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, added here with an comment that it's optional: 842803c