import { env } from "cloudflare:workers"; import { redirect } from "next/navigation"; import { getChatGPTUser, requireChatGPTUser, type ChatGPTUser, } from "./chatgpt-auth"; import type { CloudIdentity } from "@/db/repository"; export type CloudViewer = CloudIdentity & { isLocalDemo: boolean; isAdmin: boolean; }; function toIdentity(user: ChatGPTUser): CloudIdentity { return { userId: user.userId, email: user.email, displayName: user.displayName, }; } function localDemoIdentity(): CloudIdentity | null { if (process.env.NODE_ENV === "production") return null; return { userId: "local-demo-user", email: "demo@nekonest.local", displayName: "本地演示账户", }; } function isAdminEmail(email: string, isLocalDemo: boolean): boolean { if (isLocalDemo) return true; const configured = env.NEKONEST_CLOUD_ADMIN_EMAILS ?? ""; const allowed = configured .split(",") .map((item) => item.trim().toLowerCase()) .filter(Boolean); return allowed.includes(email.toLowerCase()); } export async function getCloudViewer(): Promise { const signedIn = await getChatGPTUser(); const demo = signedIn ? null : localDemoIdentity(); const identity = signedIn ? toIdentity(signedIn) : demo; if (!identity) return null; const isLocalDemo = Boolean(demo); return { ...identity, isLocalDemo, isAdmin: isAdminEmail(identity.email, isLocalDemo), }; } export async function requireCloudViewer(returnTo: string): Promise { const viewer = await getCloudViewer(); if (viewer) return viewer; const user = await requireChatGPTUser(returnTo); const identity = toIdentity(user); return { ...identity, isLocalDemo: false, isAdmin: isAdminEmail(identity.email, false), }; } export async function requireAdminViewer(returnTo = "/admin"): Promise { const viewer = await requireCloudViewer(returnTo); if (!viewer.isAdmin) redirect("/dashboard?admin=denied"); return viewer; }