MotorSignal-App/website/lib/firebase-admin.ts

61 lines
1.9 KiB
TypeScript

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';
/**
* 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.
* - 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 getFirebaseAdminApp(): App {
if (_adminApp) {
return _adminApp;
}
const existingApps = getApps();
if (existingApps.length > 0 && existingApps[0]) {
_adminApp = existingApps[0];
return _adminApp;
}
const projectId = process.env.FIREBASE_PROJECT_ID || process.env.GCLOUD_PROJECT || 'motoapp-d22e0';
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());
}