feat: implement workspace session management and enhance API proxy handling
This commit is contained in:
@@ -5,8 +5,12 @@ 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,
|
||||
@@ -19,12 +23,16 @@ export async function setAuthCookies(
|
||||
expires,
|
||||
path: "/",
|
||||
sameSite: "strict",
|
||||
httpOnly: true,
|
||||
secure: isProd,
|
||||
})
|
||||
|
||||
cookieStore.set(USER_COOKIE, JSON.stringify(user), {
|
||||
expires,
|
||||
path: "/",
|
||||
sameSite: "strict",
|
||||
httpOnly: true,
|
||||
secure: isProd,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -32,6 +40,8 @@ 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<{
|
||||
@@ -53,3 +63,65 @@ export async function getAuthCookies(): Promise<{
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user