69 lines
3.1 KiB
TypeScript
69 lines
3.1 KiB
TypeScript
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
|
|
import { createClient } from "npm:@supabase/supabase-js@2";
|
|
|
|
const cors = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
|
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
"Content-Type": "application/json",
|
|
};
|
|
const reply = (body: unknown, status = 200) => new Response(JSON.stringify(body), { status, headers: cors });
|
|
|
|
Deno.serve(async (req: Request) => {
|
|
if (req.method === "OPTIONS") return new Response("ok", { headers: cors });
|
|
if (req.method !== "POST") return reply({ error: "Method not allowed" }, 405);
|
|
try {
|
|
const auth = req.headers.get("Authorization") || "";
|
|
const url = Deno.env.get("SUPABASE_URL") || "";
|
|
const anon = Deno.env.get("SUPABASE_ANON_KEY") || "";
|
|
const serviceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") || "";
|
|
if (!url || !anon || !serviceKey) return reply({ error: "Server auth configuration is incomplete" }, 500);
|
|
const caller = createClient(url, anon, {
|
|
global: { headers: { Authorization: auth } },
|
|
auth: { persistSession: false, autoRefreshToken: false },
|
|
});
|
|
const service = createClient(url, serviceKey, { auth: { persistSession: false, autoRefreshToken: false } });
|
|
const body = await req.json();
|
|
const workspaceId = String(body.workspace_id || "");
|
|
const email = String(body.email || "").trim().toLowerCase();
|
|
const displayName = String(body.display_name || "").trim();
|
|
const role = String(body.role || "manager");
|
|
const prep = await caller.rpc("sun_employee_prepare_v28", {
|
|
p_workspace: workspaceId,
|
|
p_email: email,
|
|
p_display_name: displayName,
|
|
p_role: role,
|
|
});
|
|
if (prep.error) return reply({ error: prep.error.message }, 400);
|
|
if (prep.data?.status !== "new") {
|
|
return reply({ status: prep.data?.status, user_id: prep.data?.user_id, email, display_name: displayName, role }, 200);
|
|
}
|
|
const alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
|
|
const bytes = crypto.getRandomValues(new Uint8Array(12));
|
|
let password = "";
|
|
for (const b of bytes) password += alphabet[b % alphabet.length];
|
|
password = password.slice(0, 6) + "-" + password.slice(6);
|
|
const created = await service.auth.admin.createUser({
|
|
email,
|
|
password,
|
|
email_confirm: true,
|
|
user_metadata: {
|
|
name: displayName || email.split("@")[0],
|
|
must_change_password: true,
|
|
registration_source: "caterium_employee_admin",
|
|
},
|
|
});
|
|
if (created.error || !created.data.user) return reply({ error: created.error?.message || "Create failed" }, 400);
|
|
const fin = await caller.rpc("sun_employee_finalize_v28", {
|
|
p_workspace: workspaceId,
|
|
p_user_id: created.data.user.id,
|
|
p_display_name: displayName,
|
|
p_role: role,
|
|
});
|
|
if (fin.error) return reply({ error: fin.error.message }, 400);
|
|
return reply({ ...fin.data, created: true, temporary_password: password, must_change_password: true });
|
|
} catch (e) {
|
|
return reply({ error: e instanceof Error ? e.message : String(e) }, 500);
|
|
}
|
|
});
|