import { fail, handleOptions, json } from "../_shared/http.ts"; import { createServiceClient, requireUser } from "../_shared/supabase.ts"; Deno.serve(async (req) => { const preflight = handleOptions(req); if (preflight) return preflight; if (req.method !== "POST") return fail("Method not allowed", 405); const { user, error: userError } = await requireUser(req); if (!user) return fail(userError ?? "Unauthorized", 401); let body: { token?: string }; try { body = await req.json(); } catch { return fail("Invalid JSON body"); } const token = (body.token ?? "").trim().toLowerCase(); if (!token) return fail("token is required"); const service = createServiceClient(); const { data: invite, error: inviteError } = await service .from("organization_invites") .select( "id, token, organization_id, role, max_uses, uses_count, expires_at, revoked", ) .eq("token", token) .maybeSingle(); if (inviteError) return fail(inviteError.message, 400); if (!invite) return fail("Invite not found", 404); if (invite.revoked) return fail("Invite revoked", 410); if (invite.expires_at && new Date(invite.expires_at).getTime() < Date.now()) { return fail("Invite expired", 410); } if (invite.uses_count >= invite.max_uses) { return fail("Invite has reached max uses", 410); } const { data: existingMember, error: existingMemberError } = await service .from("organization_members") .select("organization_id") .eq("organization_id", invite.organization_id) .eq("user_id", user.id) .maybeSingle(); if (existingMemberError) return fail(existingMemberError.message, 400); if (existingMember) { return json({ accepted: true, already_member: true, organization_id: invite.organization_id, }); } const { error: insertMemberError } = await service .from("organization_members") .insert({ organization_id: invite.organization_id, user_id: user.id, role: invite.role ?? "member", }); if (insertMemberError) return fail(insertMemberError.message, 400); const nextUses = invite.uses_count + 1; const shouldRevoke = nextUses >= invite.max_uses; const { error: updateInviteError } = await service .from("organization_invites") .update({ uses_count: nextUses, revoked: shouldRevoke, }) .eq("id", invite.id); if (updateInviteError) return fail(updateInviteError.message, 400); return json({ accepted: true, already_member: false, organization_id: invite.organization_id, }); });