"use server" import { cookies } from "next/headers" import type { AuthUser } from "@garage/api" const TOKEN_COOKIE = "auth_token" const USER_COOKIE = "auth_user" const WORKSPACE_COOKIE = "workspace_uuid" const API_BASE_COOKIE = "api_base_url" const DEFAULT_EXPIRES_IN = 60 * 60 * 24 * 7 // 7 days in seconds const isProd = process.env.NODE_ENV === "production" export async function setAuthCookies( token: string, user: AuthUser, expiresIn: number = DEFAULT_EXPIRES_IN, ) { const cookieStore = await cookies() const expires = new Date(Date.now() + expiresIn * 1000) cookieStore.set(TOKEN_COOKIE, token, { expires, path: "/", sameSite: "strict", httpOnly: true, secure: isProd, }) cookieStore.set(USER_COOKIE, JSON.stringify(user), { expires, path: "/", sameSite: "strict", httpOnly: true, secure: isProd, }) } export async function clearAuthCookies() { const cookieStore = await cookies() cookieStore.delete(TOKEN_COOKIE) cookieStore.delete(USER_COOKIE) cookieStore.delete(WORKSPACE_COOKIE) cookieStore.delete(API_BASE_COOKIE) } export async function getAuthCookies(): Promise<{ token: string | undefined user: AuthUser | undefined }> { const cookieStore = await cookies() const token = cookieStore.get(TOKEN_COOKIE)?.value const rawUser = cookieStore.get(USER_COOKIE)?.value let user: AuthUser | undefined if (rawUser) { try { user = JSON.parse(rawUser) as AuthUser } catch { user = undefined } } return { token, user } } /** * Set the per-session workspace context: which garage backend to proxy to, * and which workspace UUID to send on every upstream call. Written by the * SaaS → garage-erp activation handoff. */ export async function setWorkspaceContext( apiBase: string, workspaceUuid: string, expiresIn: number = DEFAULT_EXPIRES_IN, ) { const cookieStore = await cookies() const expires = new Date(Date.now() + expiresIn * 1000) cookieStore.set(API_BASE_COOKIE, apiBase, { expires, path: "/", sameSite: "strict", httpOnly: true, secure: isProd, }) cookieStore.set(WORKSPACE_COOKIE, workspaceUuid, { expires, path: "/", sameSite: "strict", httpOnly: true, secure: isProd, }) } export async function getWorkspaceContext(): Promise<{ apiBase: string | undefined workspaceUuid: string | undefined }> { const cookieStore = await cookies() return { apiBase: cookieStore.get(API_BASE_COOKIE)?.value, workspaceUuid: cookieStore.get(WORKSPACE_COOKIE)?.value, } } export async function clearWorkspaceContext() { const cookieStore = await cookies() cookieStore.delete(WORKSPACE_COOKIE) cookieStore.delete(API_BASE_COOKIE) } /** * Server-action used by the SaaS handoff page. Wraps cookie writes for both * the auth token/user and the workspace context atomically (from the client's * point of view). */ export async function applyHandoff( token: string, user: AuthUser, apiBase: string, workspaceUuid: string, ) { await setAuthCookies(token, user) await setWorkspaceContext(apiBase, workspaceUuid) }