import { getSupabaseAdmin } from "@/lib/supabase/admin"; import { createServerClient } from "@supabase/ssr"; import { cookies } from "next/headers"; import crypto from "node:crypto"; export type RequestIdentity = { organizationId: string; userId: string; }; export async function resolveRequestIdentity(): Promise { const cookieStore = await cookies(); const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { getAll() { return cookieStore.getAll(); }, setAll() {}, }, } ); const { data: { user }, error } = await supabase.auth.getUser(); if (error || !user) { throw new Error("Missing auth session"); } const userId = user.id; const adminClient = getSupabaseAdmin(); const { data: member, error: memberError } = await adminClient .from("members") .select("organization_id") .eq("user_id", userId) .order("created_at", { ascending: true }) .limit(1) .maybeSingle(); if (memberError && memberError.code !== "PGRST116") { throw new Error(`Failed to resolve organization: ${memberError.message}`); } // If the user has no org, lazily bootstrap a personal organization for them. let organizationId = member?.organization_id; if (!organizationId) { const newOrgId = crypto.randomUUID(); const { error: orgError } = await adminClient.from("organizations").insert({ id: newOrgId, name: `Personal Org (${user.email})`, slug: `org-${newOrgId.slice(0, 8)}`, }); if (orgError) throw new Error("Failed to bootstrap new organization for user"); const { error: memberInsertError } = await adminClient.from("members").insert({ organization_id: newOrgId, user_id: userId, role: "owner" }); if (memberInsertError) throw new Error("Failed to create membership for new organization"); organizationId = newOrgId; } return { organizationId, userId }; }