- Fix Next.js build failure: remove duplicate route at (dashboard)/listings/[id] that conflicted with (public)/listings/[id] (same URL path in two route groups) - Fix 772 ESLint errors: auto-fix import ordering (import-x/order), remove unused imports/variables, convert empty interfaces to type aliases, replace require() with ESM imports, fix consistent-type-imports violations - Add CLAUDE.md for developer onboarding documentation - All checks pass: 0 lint errors, typecheck clean, 230 tests passing, build success Co-Authored-By: Paperclip <noreply@paperclip.ing>
81 lines
2.1 KiB
TypeScript
81 lines
2.1 KiB
TypeScript
import { Injectable, type OnModuleInit } from '@nestjs/common';
|
|
import {
|
|
apps,
|
|
initializeApp,
|
|
credential,
|
|
messaging,
|
|
type ServiceAccount,
|
|
} from 'firebase-admin';
|
|
import { type LoggerService } from '@modules/shared/infrastructure/logger.service';
|
|
|
|
export interface SendPushDto {
|
|
token: string;
|
|
title: string;
|
|
body: string;
|
|
data?: Record<string, string>;
|
|
}
|
|
|
|
@Injectable()
|
|
export class FcmService implements OnModuleInit {
|
|
private initialized = false;
|
|
|
|
constructor(private readonly logger: LoggerService) {}
|
|
|
|
onModuleInit(): void {
|
|
const serviceAccountJson = process.env['FIREBASE_SERVICE_ACCOUNT'];
|
|
if (!serviceAccountJson) {
|
|
this.logger.warn(
|
|
'FIREBASE_SERVICE_ACCOUNT not set — push notifications disabled',
|
|
'FcmService',
|
|
);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const serviceAccount = JSON.parse(serviceAccountJson) as ServiceAccount;
|
|
if (!apps.length) {
|
|
initializeApp({ credential: credential.cert(serviceAccount) });
|
|
}
|
|
this.initialized = true;
|
|
this.logger.log('Firebase Admin initialized for push notifications', 'FcmService');
|
|
} catch (error) {
|
|
this.logger.error(
|
|
`Failed to initialize Firebase: ${error instanceof Error ? error.message : String(error)}`,
|
|
'FcmService',
|
|
);
|
|
}
|
|
}
|
|
|
|
get isAvailable(): boolean {
|
|
return this.initialized;
|
|
}
|
|
|
|
async send(dto: SendPushDto): Promise<string> {
|
|
if (!this.initialized) {
|
|
throw new Error('FCM not initialized — FIREBASE_SERVICE_ACCOUNT not configured');
|
|
}
|
|
|
|
try {
|
|
const messageId = await messaging().send({
|
|
token: dto.token,
|
|
notification: {
|
|
title: dto.title,
|
|
body: dto.body,
|
|
},
|
|
data: dto.data,
|
|
android: { priority: 'high' },
|
|
apns: { payload: { aps: { sound: 'default' } } },
|
|
});
|
|
|
|
this.logger.log(`Push sent to token ${dto.token.slice(0, 10)}...: ${messageId}`, 'FcmService');
|
|
return messageId;
|
|
} catch (error) {
|
|
this.logger.error(
|
|
`Failed to send push: ${error instanceof Error ? error.message : String(error)}`,
|
|
'FcmService',
|
|
);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|