getServerApi only forwarded the auth token, using the default API base URL and sending no workspace header. In the multi-tenant setup the per-workspace backend URL (api_base_url) and id (workspace_uuid) live in httpOnly cookies, and client requests reach the right tenant via the /api/proxy route. SSR never replicated that, so server components hit the wrong/default backend and got "not found" for resources that exist — e.g. the vendor detail page. Read api_base_url and workspace_uuid from cookies and pass baseUrl + X-Workspace-UUID to createApi, mirroring the proxy. Fixes every server- rendered detail page, not just vendors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
37 lines
1.4 KiB
TypeScript
37 lines
1.4 KiB
TypeScript
import "server-only"
|
|
import { cookies } from "next/headers"
|
|
import { createApi } from "./api"
|
|
import type { AuthUser } from "./infra/token"
|
|
|
|
export async function getServerApi() {
|
|
const cookieStore = await cookies()
|
|
const token = cookieStore.get("auth_token")?.value
|
|
// Multi-tenant: the workspace's backend URL and id live in httpOnly cookies
|
|
// set by middleware. Client requests reach the right tenant via the
|
|
// /api/proxy route; SSR must replicate that — point at the tenant's
|
|
// api_base_url and send X-Workspace-UUID, or the request hits the wrong
|
|
// (default) backend and resources come back "not found".
|
|
const apiBaseUrl = cookieStore.get("api_base_url")?.value
|
|
const workspaceUuid = cookieStore.get("workspace_uuid")?.value
|
|
|
|
const headers: Record<string, string> = {}
|
|
if (token) headers.Authorization = `Bearer ${token}`
|
|
if (workspaceUuid) headers["X-Workspace-UUID"] = workspaceUuid
|
|
|
|
return createApi({
|
|
...(apiBaseUrl ? { baseUrl: apiBaseUrl } : {}),
|
|
...(Object.keys(headers).length ? { headers } : {}),
|
|
})
|
|
}
|
|
|
|
export async function getServerUser(): Promise<AuthUser | null> {
|
|
const cookieStore = await cookies()
|
|
const raw = cookieStore.get("auth_user")?.value
|
|
if (!raw) return null
|
|
try {
|
|
return JSON.parse(decodeURIComponent(raw)) as AuthUser
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|