Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ yarn-error.log*
/playwright-report/
/blob-report/
/playwright/*


package-lock.json

**/*backup*
**/*ignore*
!.gitignore
55 changes: 42 additions & 13 deletions app/(auth)/api/auth/guest/route.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
import { NextResponse } from "next/server";
import { getToken } from "next-auth/jwt";
import { signIn } from "@/app/(auth)/auth";
import { isDevelopmentEnvironment } from "@/lib/constants";
import { getToken } from "next-auth/jwt";
import { NextRequest, NextResponse } from "next/server";

export async function GET(request: Request) {
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const redirectUrl = searchParams.get("redirectUrl") || "/";

const token = await getToken({
req: request,
secret: process.env.AUTH_SECRET,
secureCookie: !isDevelopmentEnvironment,
});
try {
console.log("Testing environment variables...");
console.log("AUTH_SECRET exists:", !!process.env.AUTH_SECRET);
console.log("POSTGRES_URL exists:", !!process.env.POSTGRES_URL);

const token = await getToken({
req: request,
secret: process.env.AUTH_SECRET,
secureCookie: !isDevelopmentEnvironment,
});

if (token) {
return NextResponse.redirect(new URL("/", request.url));
}
if (token) {
console.log("User already has token, redirecting to:", redirectUrl);
// return NextResponse.redirect(new URL(redirectUrl, request.url));
return NextResponse.redirect(new URL("/", request.url));
}

return signIn("guest", { redirect: true, redirectTo: redirectUrl });
// console.log("Attempting to import signIn...");
// const { signIn } = await import("@/app/(auth)/auth");
// // console.log("signIn imported successfully");

// // console.log("Attempting guest sign in with redirectUrl:", redirectUrl);
// const result = await signIn("guest", { redirect: true, redirectTo: redirectUrl });
// // console.log("Guest sign in result:", result);
// return result;

console.log("No token found, redirecting to NextAuth signin endpoint");
// Redirect to NextAuth's signin endpoint with guest provider
const signinUrl = new URL("/api/auth/signin", request.url);
signinUrl.searchParams.set("provider", "guest");
signinUrl.searchParams.set("callbackUrl", redirectUrl);

console.log("Redirecting to:", signinUrl.toString());
return NextResponse.redirect(signinUrl);
} catch (error) {
console.error("Error in guest auth route:", error);
return NextResponse.json(
{ error: "Internal server error", details: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}
41 changes: 38 additions & 3 deletions app/(auth)/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,27 @@ declare module "next-auth" {
user: {
id: string;
type: UserType;
isLoggedIn: boolean;
username?: string|null;
} & DefaultSession["user"];
}

interface User {
id?: string;
email?: string | null;
type: UserType;
username?: string|null;
isLoggedIn: boolean;
}
}

declare module "next-auth/jwt" {
interface JWT extends DefaultJWT {
id: string;
type: UserType;
email?: string;
username?: string;
isLoggedIn: boolean;
}
}

Expand Down Expand Up @@ -61,15 +68,29 @@ export const {
return null;
}

return { ...user, type: "regular" };
return { ...user, type: "regular", isLoggedIn: true };
},
}),
Credentials({
id: "guest",
credentials: {},
async authorize() {
const [guestUser] = await createGuestUser();
return { ...guestUser, type: "guest" };
try {
// Create guest user
const [guestUser] = await createGuestUser();

return {
...guestUser,
type: "guest",
isLoggedIn: false
};
} catch (error) {
console.error("Guest auth error: Unexpected error during guest authentication:", {
error: error instanceof Error ? error.message : 'Unknown error',
stack: error instanceof Error ? error.stack : undefined
});
return null;
}
},
}),
],
Expand All @@ -78,6 +99,13 @@ export const {
if (user) {
token.id = user.id as string;
token.type = user.type;
token.isLoggedIn = user.isLoggedIn;
if (user.email) {
token.email = user.email;
}
if (user.username) {
token.username = user.username;
}
}

return token;
Expand All @@ -86,6 +114,13 @@ export const {
if (session.user) {
session.user.id = token.id;
session.user.type = token.type;
session.user.isLoggedIn = token.isLoggedIn;
if (token.email) {
session.user.email = token.email;
}
if (token.username) {
session.user.username = token.username;
}
}

return session;
Expand Down
16 changes: 15 additions & 1 deletion app/(chat)/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,21 @@ export async function POST(request: Request) {
title: "New chat",
visibility: selectedVisibilityType,
});
titlePromise = generateTitleFromUserMessage({ message });
// titlePromise = generateTitleFromUserMessage({ message });
// Convert message to proper ChatMessage format by filtering out undefined text parts
const cleanedMessage: ChatMessage = {
...message,
parts: message.parts
.filter(part => part.type === 'file' || (part.type === 'text' && part.text !== undefined))
.map(part => {
if (part.type === 'text') {
return { type: 'text', text: part.text! };
}
return part;
})
};
titlePromise = generateTitleFromUserMessage({ message: cleanedMessage });

}

const uiMessages = isToolApprovalFlow
Expand Down
24 changes: 23 additions & 1 deletion app/(chat)/api/files/upload/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { NextResponse } from "next/server";
import { z } from "zod";

import { auth } from "@/app/(auth)/auth";
import { ChatbotError } from "@/lib/errors";
import { filterImage } from "@/lib/image-filter";

// Storage on Vercel Blob
// Use Blob instead of File since File is not available in Node.js environment
const FileSchema = z.object({
file: z
Expand Down Expand Up @@ -49,9 +52,24 @@ export async function POST(request: Request) {
// Get filename from formData since Blob doesn't have name property
const filename = (formData.get("file") as File).name;
const fileBuffer = await file.arrayBuffer();
const buffer = Buffer.from(fileBuffer);

// Check if user is guest
const isGuest = !!session.user.email?.startsWith('guest-') && session.user.type !== "regular";

if (process.env.OPENAI_API_KEY) {
// Filter image for inappropriate content
const filterResult = await filterImage(buffer, isGuest);

if (!filterResult.isAllowed) {
return NextResponse.json({
error: filterResult.reason || "Image validation failed"
}, { status: 400 });
}
}

try {
const data = await put(`${filename}`, fileBuffer, {
const data = await put(`${filename}`, buffer, {
access: "public",
});

Expand All @@ -60,6 +78,10 @@ export async function POST(request: Request) {
return NextResponse.json({ error: "Upload failed" }, { status: 500 });
}
} catch (_error) {
if (_error instanceof ChatbotError) {
return _error.toResponse();
}

return NextResponse.json(
{ error: "Failed to process request" },
{ status: 500 }
Expand Down
26 changes: 26 additions & 0 deletions app/(chat)/api/rename-chat/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { auth } from "@/app/(auth)/auth";
import { updateChatTitleById } from "@/lib/db/queries";
import { NextRequest, NextResponse } from "next/server";

export async function PATCH(request: NextRequest) {
try {
const session = await auth();

if (!session?.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

const { chatId, title } = await request.json();

if (!chatId || !title) {
return NextResponse.json({ error: 'Missing chatId or title' }, { status: 400 });
}

await updateChatTitleById({ chatId, title });

return NextResponse.json({ success: true, title });
} catch (error) {
console.error('Error renaming chat:', error);
return NextResponse.json({ error: 'Failed to rename chat' }, { status: 500 });
}
}
4 changes: 4 additions & 0 deletions components/chat-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Button } from "@/components/ui/button";
import { PlusIcon, VercelIcon } from "./icons";
import { useSidebar } from "./ui/sidebar";
import { VisibilitySelector, type VisibilityType } from "./visibility-selector";
import { ThemeToggle } from "./theme-toggle";

function PureChatHeader({
chatId,
Expand Down Expand Up @@ -50,6 +51,9 @@ function PureChatHeader({
/>
)}

<ThemeToggle />


<Button
asChild
className="order-3 hidden bg-zinc-900 px-2 text-zinc-50 hover:bg-zinc-800 md:ml-auto md:flex md:h-fit dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
Expand Down
Loading