80 lines
3.0 KiB
TypeScript
80 lines
3.0 KiB
TypeScript
import 'server-only';
|
||
import { createClient } from '@supabase/supabase-js';
|
||
|
||
const supabaseUrl = process.env.SUPABASE_URL;
|
||
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||
|
||
if (!supabaseUrl || !serviceRoleKey) {
|
||
throw new Error('SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY tanımlı değil (.env dosyasına bakın).');
|
||
}
|
||
|
||
// service_role ile — RLS bypass edilir, admin panelinin ihtiyacı budur (licenses,
|
||
// crash_reports, access_logs gibi tablolarda bilerek hiç RLS policy yok, sadece
|
||
// service_role erişebiliyor). SADECE server component / route handler içinde
|
||
// import edilmeli — 'server-only' paketi bunu build-time'da garanti ediyor.
|
||
export const supabaseAdmin = createClient(supabaseUrl, serviceRoleKey, {
|
||
auth: { autoRefreshToken: false, persistSession: false },
|
||
});
|
||
|
||
export interface AuthUser {
|
||
id: string;
|
||
email?: string;
|
||
created_at: string;
|
||
last_sign_in_at?: string | null;
|
||
}
|
||
|
||
// profiles tablosunda e-posta yok (auth.users'a referans veriyor) — e-postayı
|
||
// Supabase Auth Admin API'den çekmemiz gerekiyor.
|
||
export async function listAuthUsers(): Promise<Map<string, AuthUser>> {
|
||
const res = await fetch(`${supabaseUrl}/auth/v1/admin/users?per_page=1000`, {
|
||
headers: { apikey: serviceRoleKey!, Authorization: `Bearer ${serviceRoleKey}` },
|
||
cache: 'no-store',
|
||
});
|
||
if (!res.ok) return new Map();
|
||
const data = await res.json();
|
||
const users: AuthUser[] = data.users || [];
|
||
return new Map(users.map((u) => [u.id, u]));
|
||
}
|
||
|
||
// Kullanıcı silme: Supabase Auth Admin API üzerinden. profiles satırını silmek
|
||
// admin'in sorumluluğunda ayrıca çağrılmalı — auth.users -> profiles cascade'i
|
||
// bu self-hosted kurulumda garanti değil.
|
||
export async function deleteAuthUser(id: string): Promise<{ error?: string }> {
|
||
const res = await fetch(`${supabaseUrl}/auth/v1/admin/users/${id}`, {
|
||
method: 'DELETE',
|
||
headers: { apikey: serviceRoleKey!, Authorization: `Bearer ${serviceRoleKey}` },
|
||
});
|
||
if (!res.ok) {
|
||
const text = await res.text().catch(() => '');
|
||
return { error: `Auth kullanıcı silinemedi (${res.status}): ${text}` };
|
||
}
|
||
return {};
|
||
}
|
||
|
||
export interface CustomerOption {
|
||
id: string;
|
||
name: string | null;
|
||
email: string;
|
||
}
|
||
|
||
// Lisans düzenleme/oluşturma formlarındaki "Müşteri" seçimi Kullanıcılar sayfasıyla
|
||
// AYNI kaynaktan (profiles + Supabase Auth e-postası) besleniyor — serbest metin
|
||
// yerine, gerçekten var olan bir kullanıcı seçtirmek için.
|
||
export async function listCustomerOptions(): Promise<CustomerOption[]> {
|
||
const [{ data: profiles }, authUsers] = await Promise.all([
|
||
supabaseAdmin.from('profiles').select('id, full_name'),
|
||
listAuthUsers(),
|
||
]);
|
||
|
||
const options: CustomerOption[] = (profiles || [])
|
||
.map((p: { id: string; full_name: string | null }) => ({
|
||
id: p.id,
|
||
name: p.full_name,
|
||
email: authUsers.get(p.id)?.email || '',
|
||
}))
|
||
.filter((c) => c.email);
|
||
|
||
options.sort((a, b) => (a.name || a.email).localeCompare(b.name || b.email, 'tr'));
|
||
return options;
|
||
}
|