import { getApps, initializeApp, cert, type App } from 'firebase-admin/app'; import { getAuth, type Auth } from 'firebase-admin/auth'; import { getFirestore, type Firestore } from 'firebase-admin/firestore'; import { getServerFirebaseProjectId } from './firebase-config'; /** * Server-only singleton initialization for Firebase Admin. * * Requirements: * - Singleton reuse across Next.js API route invocations. * - Server-only execution (never imported or bundled in client-side code). * - Fails closed if project configuration is missing. * - Requires explicit FIREBASE_PROJECT_ID with no fallback to production. * - Supports Google Application Default Credentials (ADC), explicit service account * via FIREBASE_SERVICE_ACCOUNT or GOOGLE_APPLICATION_CREDENTIALS, and Firebase emulator. */ let _adminApp: App | null = null; export function resetFirebaseAdminAppForTesting(): void { _adminApp = null; } export function getFirebaseAdminApp(): App { if (_adminApp) { return _adminApp; } const existingApps = getApps(); if (existingApps.length > 0 && existingApps[0]) { _adminApp = existingApps[0]; return _adminApp; } const projectId = getServerFirebaseProjectId(); if (process.env.NEXT_PUBLIC_FIREBASE_EMULATORS === 'true' || projectId.startsWith('demo-')) { process.env.FIREBASE_AUTH_EMULATOR_HOST = process.env.FIREBASE_AUTH_EMULATOR_HOST || '127.0.0.1:9099'; process.env.FIRESTORE_EMULATOR_HOST = process.env.FIRESTORE_EMULATOR_HOST || '127.0.0.1:8088'; } const serviceAccountJson = process.env.FIREBASE_SERVICE_ACCOUNT; let credential; if (serviceAccountJson) { try { credential = cert(JSON.parse(serviceAccountJson)); } catch (err) { console.error('[FIREBASE_ADMIN] Failed to parse FIREBASE_SERVICE_ACCOUNT credential:', err); throw new Error('Invalid Firebase service account configuration.'); } } try { _adminApp = initializeApp({ projectId, ...(credential ? { credential } : {}), }); return _adminApp; } catch (err: any) { console.error('[FIREBASE_ADMIN] Failed to initialize Firebase Admin SDK:', err?.message || err); throw new Error('Firebase Admin SDK initialization failed.'); } } export function getAdminAuth(): Auth { return getAuth(getFirebaseAdminApp()); } export function getAdminFirestore(): Firestore { return getFirestore(getFirebaseAdminApp()); }