migrate: replace Supabase REST with Drizzle/pg in billing + integrations + wholesale (wave 3)

This commit is contained in:
2026-06-07 03:25:22 +00:00
parent eb9621d238
commit 99a3d66636
26 changed files with 1216 additions and 1776 deletions
+50 -78
View File
@@ -1,7 +1,7 @@
"use server";
import { getAdminUser } from "@/lib/admin-permissions";
import { svcHeaders } from "@/lib/svc-headers";
import { pool } from "@/lib/db";
// ── Types ─────────────────────────────────────────────────────────────────────
@@ -24,28 +24,25 @@ export type SaveCredentialsResult =
// ── Resend Credentials ─────────────────────────────────────────────────────────
export async function getResendCredentials(brandId: string): Promise<ResendCredentials> {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
const response = await fetch(
`${supabaseUrl}/rest/v1/rpc/get_resend_credentials`,
{
method: "POST",
headers: { ...svcHeaders(supabaseKey), "Content-Type": "application/json" },
body: JSON.stringify({ p_brand_id: brandId }),
}
);
if (!response.ok) {
try {
const res = await pool.query<{
api_key: string | null;
from_email: string | null;
from_name: string | null;
}>(
"SELECT * FROM get_resend_credentials($1)",
[brandId]
);
const data = res.rows[0];
if (!data) return { api_key: null, from_email: null, from_name: null };
return {
api_key: data.api_key ?? null,
from_email: data.from_email ?? null,
from_name: data.from_name ?? null,
};
} catch {
return { api_key: null, from_email: null, from_name: null };
}
const data = await response.json();
return {
api_key: data?.api_key ?? null,
from_email: data?.from_email ?? null,
from_name: data?.from_name ?? null,
};
}
export async function saveResendCredentials(
@@ -66,9 +63,6 @@ export async function saveResendCredentials(
return { success: false, error: "Not authorized" };
}
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
// Get current credentials to merge
const current = await getResendCredentials(brandId);
const merged = {
@@ -77,50 +71,39 @@ export async function saveResendCredentials(
from_name: credentials.from_name !== undefined ? credentials.from_name : current.from_name,
};
const response = await fetch(
`${supabaseUrl}/rest/v1/rpc/set_resend_credentials`,
{
method: "POST",
headers: { ...svcHeaders(supabaseKey), "Content-Type": "application/json" },
body: JSON.stringify({
p_brand_id: brandId,
p_credentials: merged,
}),
}
);
if (!response.ok) {
try {
await pool.query(
"SELECT set_resend_credentials($1, $2::jsonb)",
[brandId, JSON.stringify(merged)]
);
return { success: true };
} catch {
return { success: false, error: "Failed to save Resend credentials" };
}
return { success: true };
}
// ── Twilio Credentials ─────────────────────────────────────────────────────────
export async function getTwilioCredentials(brandId: string): Promise<TwilioCredentials> {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
const response = await fetch(
`${supabaseUrl}/rest/v1/rpc/get_twilio_credentials`,
{
method: "POST",
headers: { ...svcHeaders(supabaseKey), "Content-Type": "application/json" },
body: JSON.stringify({ p_brand_id: brandId }),
}
);
if (!response.ok) {
try {
const res = await pool.query<{
account_sid: string | null;
auth_token: string | null;
phone_number: string | null;
}>(
"SELECT * FROM get_twilio_credentials($1)",
[brandId]
);
const data = res.rows[0];
if (!data) return { account_sid: null, auth_token: null, phone_number: null };
return {
account_sid: data.account_sid ?? null,
auth_token: data.auth_token ?? null,
phone_number: data.phone_number ?? null,
};
} catch {
return { account_sid: null, auth_token: null, phone_number: null };
}
const data = await response.json();
return {
account_sid: data?.account_sid ?? null,
auth_token: data?.auth_token ?? null,
phone_number: data?.phone_number ?? null,
};
}
export async function saveTwilioCredentials(
@@ -141,9 +124,6 @@ export async function saveTwilioCredentials(
return { success: false, error: "Not authorized" };
}
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
// Get current credentials to merge
const current = await getTwilioCredentials(brandId);
const merged = {
@@ -152,23 +132,15 @@ export async function saveTwilioCredentials(
phone_number: credentials.phone_number !== undefined ? credentials.phone_number : current.phone_number,
};
const response = await fetch(
`${supabaseUrl}/rest/v1/rpc/set_twilio_credentials`,
{
method: "POST",
headers: { ...svcHeaders(supabaseKey), "Content-Type": "application/json" },
body: JSON.stringify({
p_brand_id: brandId,
p_credentials: merged,
}),
}
);
if (!response.ok) {
try {
await pool.query(
"SELECT set_twilio_credentials($1, $2::jsonb)",
[brandId, JSON.stringify(merged)]
);
return { success: true };
} catch {
return { success: false, error: "Failed to save Twilio credentials" };
}
return { success: true };
}
// ── Test Connection Functions ─────────────────────────────────────────────────
@@ -229,4 +201,4 @@ export async function testTwilioConnection(
} catch (err) {
return { ok: false, message: "Network error - please check your connection" };
}
}
}