// app/api/db-client.server.ts import { getUserSession } from '~/api/login/auth.server'; import { runWithContext } from './postgrest-client'; /** * 在认证上下文中运行 * * 所有在此上下文中调用的 postgrest 函数(postgrestGet/Post/Put/Delete) * 都会自动获取并添加 JWT Token 到 Authorization 头部 * * @param request Remix Request 对象 * @param fn 要在认证上下文中执行的函数 * @returns 函数执行结果 * @throws 如果用户未登录则抛出错误 * * @example * ```typescript * export async function loader({ request }: LoaderFunctionArgs) { * return await runInAuthContext(request, async () => { * // 所有 postgrest 调用自动带 JWT * const users = await postgrestGet('users', { limit: 10 }); * const docs = await postgrestGet('documents', { filter: { status: 'eq.0' } }); * * return json({ users: users.data, docs: docs.data }); * }); * } * ``` */ export async function runInAuthContext( request: Request, fn: () => T | Promise ): Promise { const { frontendJWT, isAuthenticated } = await getUserSession(request); if (!isAuthenticated || !frontendJWT) { throw new Error('用户未登录,无法执行需要认证的操作'); } // 在上下文中设置 JWT,所有 postgrest 调用都会自动使用 return runWithContext({ jwt: frontendJWT }, fn); } /** * 在公开上下文中运行(不需要认证) * * 用于公开数据访问,不会添加 JWT Token * * @param fn 要执行的函数 * @returns 函数执行结果 * * @example * ```typescript * export async function loader() { * return runInPublicContext(async () => { * const articles = await postgrestGet('public_articles', { * filter: { published: 'eq.true' } * }); * return json({ articles: articles.data }); * }); * } * ``` */ export function runInPublicContext( fn: () => T | Promise ): T | Promise { // 在空上下文中运行,不设置 JWT return runWithContext({}, fn); } /** * 在可选认证上下文中运行 * * 如果用户已登录,会自动添加 JWT; * 如果用户未登录,则不添加 JWT(不会抛出错误) * * @param request Remix Request 对象 * @param fn 要执行的函数 * @returns 函数执行结果 * * @example * ```typescript * export async function loader({ request }: LoaderFunctionArgs) { * return await runInOptionalAuthContext(request, async () => { * // 如果用户登录,会带 JWT(可能看到更多内容) * // 如果用户未登录,不带 JWT(看到基础内容) * const content = await postgrestGet('content', { limit: 20 }); * return json({ content: content.data }); * }); * } * ``` */ export async function runInOptionalAuthContext( request: Request, fn: () => T | Promise ): Promise { try { const { frontendJWT, isAuthenticated } = await getUserSession(request); if (isAuthenticated && frontendJWT) { // 用户已登录,使用 JWT return runWithContext({ jwt: frontendJWT }, fn); } } catch (error) { // 获取会话失败,继续以公开方式运行 console.warn('获取用户会话失败,以公开方式运行:', error); } // 用户未登录或获取会话失败,以公开方式运行 return runWithContext({}, fn); }