notification-kit
Version:
A unified notification library for React + Capacitor apps. One API for push notifications, in-app notifications, and local notifications across Web, iOS, and Android.
1 lines • 31.6 kB
Source Map (JSON)
{"version":3,"file":"FirebaseProvider-B-Rv8AC7.mjs","sources":["../src/providers/FirebaseNativeBridge.ts","../src/providers/FirebaseProvider.ts"],"sourcesContent":["import { DynamicLoader } from '@/utils/dynamic-loader'\nimport { Logger } from '@/utils/logger'\nimport type { FirebaseConfig } from '@/types'\n\n/**\n * Native bridge for Firebase configuration\n * Handles secure runtime configuration for iOS and Android\n */\nexport class FirebaseNativeBridge {\n private static isInitialized = false\n\n /**\n * Initialize Firebase on native platforms with runtime configuration\n */\n static async initializeNative(config: FirebaseConfig): Promise<void> {\n if (this.isInitialized) {\n Logger.warn('Firebase native bridge already initialized')\n return\n }\n\n const isNative = await DynamicLoader.isNativePlatform()\n if (!isNative) {\n // Not a native platform, skip native initialization\n return\n }\n\n const platform = await DynamicLoader.getPlatform()\n \n try {\n // Validate configuration\n this.validateConfig(config)\n \n // Configure platform-specific settings\n await this.configureNativePlatform(platform, config)\n \n this.isInitialized = true\n Logger.info(`Firebase native bridge initialized for ${platform}`)\n } catch (error) {\n Logger.error('Failed to initialize Firebase native bridge:', error)\n throw error\n }\n }\n\n /**\n * Validate Firebase configuration\n */\n private static validateConfig(config: FirebaseConfig): void {\n const requiredFields = [\n 'apiKey',\n 'authDomain',\n 'projectId',\n 'storageBucket',\n 'messagingSenderId',\n 'appId'\n ]\n\n const missingFields = requiredFields.filter(field => !config[field as keyof FirebaseConfig])\n \n if (missingFields.length > 0) {\n throw new Error(`Missing required Firebase configuration fields: ${missingFields.join(', ')}`)\n }\n\n // Log configuration status without exposing sensitive data\n Logger.debug('Firebase configuration validated', {\n hasApiKey: !!config.apiKey,\n hasAuthDomain: !!config.authDomain,\n hasProjectId: !!config.projectId,\n hasMessagingSenderId: !!config.messagingSenderId,\n hasAppId: !!config.appId,\n hasVapidKey: !!config.vapidKey,\n })\n }\n\n /**\n * Configure Firebase for specific native platform\n */\n private static async configureNativePlatform(\n platform: string,\n config: FirebaseConfig\n ): Promise<void> {\n if (platform === 'ios') {\n await this.configureIOS(config)\n } else if (platform === 'android') {\n await this.configureAndroid(config)\n }\n }\n\n /**\n * Configure Firebase for iOS\n * \n * IMPORTANT: This approach ensures that:\n * 1. GoogleService-Info.plist is NOT required in the repository\n * 2. Firebase configuration is provided at runtime\n * 3. Sensitive data never appears in version control\n */\n private static async configureIOS(_config: FirebaseConfig): Promise<void> {\n // iOS Firebase configuration approach:\n // Instead of using GoogleService-Info.plist, we configure Firebase programmatically\n // This would be done through a Capacitor plugin that bridges to native iOS code\n \n Logger.debug('iOS Firebase configuration prepared (credentials hidden)')\n\n // Note: The actual implementation would require a Capacitor plugin\n // that bridges to native iOS code to call:\n // \n // let options = FirebaseOptions(\n // googleAppID: config.appId,\n // gcmSenderID: config.messagingSenderId,\n // projectID: config.projectId,\n // apiKey: config.apiKey,\n // databaseURL: config.authDomain,\n // storageBucket: config.storageBucket\n // )\n // FirebaseApp.configure(options: options)\n \n // This avoids the need for GoogleService-Info.plist in the repository\n }\n\n /**\n * Configure Firebase for Android\n * \n * IMPORTANT: This approach ensures that:\n * 1. google-services.json is NOT required in the repository\n * 2. Firebase configuration is provided at runtime\n * 3. Sensitive data never appears in version control\n */\n private static async configureAndroid(_config: FirebaseConfig): Promise<void> {\n // Android Firebase configuration approach:\n // Instead of using google-services.json, we configure Firebase programmatically\n // This would be done through a Capacitor plugin that bridges to native Android code\n \n Logger.debug('Android Firebase configuration prepared (credentials hidden)')\n\n // Note: The actual implementation would require a Capacitor plugin\n // that bridges to native Android code to call:\n // \n // FirebaseOptions options = new FirebaseOptions.Builder()\n // .setApplicationId(config.appId)\n // .setApiKey(config.apiKey)\n // .setDatabaseUrl(config.authDomain)\n // .setProjectId(config.projectId)\n // .setStorageBucket(config.storageBucket)\n // .setGcmSenderId(config.messagingSenderId)\n // .build();\n // FirebaseApp.initializeApp(context, options);\n \n // This avoids the need for google-services.json in the repository\n }\n\n /**\n * Get initialization status\n */\n static isNativeInitialized(): boolean {\n return this.isInitialized\n }\n\n /**\n * Reset initialization (useful for testing)\n */\n static reset(): void {\n this.isInitialized = false\n }\n\n /**\n * Validate environment variables\n */\n static validateEnvironmentVariables(): void {\n const requiredEnvVars = [\n 'FIREBASE_API_KEY',\n 'FIREBASE_AUTH_DOMAIN',\n 'FIREBASE_PROJECT_ID',\n 'FIREBASE_STORAGE_BUCKET',\n 'FIREBASE_MESSAGING_SENDER_ID',\n 'FIREBASE_APP_ID'\n ]\n\n const missingEnvVars = requiredEnvVars.filter(envVar => !process.env[envVar])\n \n if (missingEnvVars.length > 0) {\n Logger.warn(\n `Missing Firebase environment variables: ${missingEnvVars.join(', ')}. ` +\n 'Make sure to set these in your .env file or deployment environment.'\n )\n }\n }\n}","import { DynamicLoader } from '@/utils/dynamic-loader'\nimport { FirebaseNativeBridge } from './FirebaseNativeBridge'\nimport { ConfigValidator } from '@/utils/config-validator'\nimport type { FirebaseApp } from 'firebase/app'\nimport type { Messaging, MessagePayload } from 'firebase/messaging'\nimport type {\n NotificationProvider,\n FirebaseConfig,\n PushNotificationPayload,\n PermissionStatus,\n ProviderCapabilities,\n} from '@/types'\n\n/**\n * Firebase provider for push notifications\n */\nexport class FirebaseProvider implements NotificationProvider {\n readonly name = 'firebase'\n readonly type = 'firebase' as const\n\n private app: FirebaseApp | null = null\n private messaging: Messaging | null = null\n private config: FirebaseConfig | null = null\n private currentToken: string | null = null\n private messageListeners: ((payload: PushNotificationPayload) => void)[] = []\n private tokenListeners: ((token: string) => void)[] = []\n private errorListeners: ((error: Error) => void)[] = []\n private unsubscribeMessage: (() => void) | null = null\n\n /**\n * Initialize Firebase provider\n */\n async init(config: FirebaseConfig): Promise<void> {\n try {\n // Validate configuration\n ConfigValidator.validateFirebaseConfig(config)\n ConfigValidator.validateEnvironmentVariables('firebase')\n \n this.config = config\n\n // Initialize native bridge for secure configuration on mobile platforms\n const isNative = await DynamicLoader.isNativePlatform()\n if (isNative) {\n await FirebaseNativeBridge.initializeNative(config)\n }\n\n // Initialize Firebase app\n const firebaseConfig: Record<string, string> = {\n apiKey: config.apiKey,\n authDomain: config.authDomain,\n projectId: config.projectId,\n storageBucket: config.storageBucket,\n messagingSenderId: config.messagingSenderId,\n appId: config.appId,\n }\n\n if (config.measurementId) {\n firebaseConfig.measurementId = config.measurementId\n }\n\n // Dynamically import and initialize Firebase\n const firebaseApp = await DynamicLoader.loadFirebase()\n if (!firebaseApp) {\n throw new Error('Firebase is required but not installed')\n }\n this.app = firebaseApp.initializeApp(firebaseConfig)\n\n // Initialize messaging if supported\n if (await this.isSupported()) {\n await this.initializeMessaging()\n }\n } catch (error) {\n this.handleError(new Error(`Firebase initialization failed: ${error}`))\n throw error\n }\n }\n\n /**\n * Destroy Firebase provider\n */\n async destroy(): Promise<void> {\n try {\n if (this.unsubscribeMessage) {\n this.unsubscribeMessage()\n this.unsubscribeMessage = null\n }\n\n if (this.currentToken && this.messaging) {\n const firebaseMessaging = await DynamicLoader.loadFirebaseMessaging()\n if (firebaseMessaging) {\n await firebaseMessaging.deleteToken(this.messaging)\n }\n }\n\n this.app = null\n this.messaging = null\n this.config = null\n this.currentToken = null\n this.messageListeners = []\n this.tokenListeners = []\n this.errorListeners = []\n } catch (error) {\n this.handleError(new Error(`Firebase destroy failed: ${error}`))\n throw error\n }\n }\n\n /**\n * Request notification permission\n */\n async requestPermission(): Promise<boolean> {\n try {\n const isNative = await DynamicLoader.isNativePlatform()\n if (isNative) {\n return await this.requestNativePermission()\n } else {\n return await this.requestWebPermission()\n }\n } catch (error) {\n this.handleError(new Error(`Permission request failed: ${error}`))\n return false\n }\n }\n\n /**\n * Check notification permission status\n */\n async checkPermission(): Promise<PermissionStatus> {\n try {\n const isNative = await DynamicLoader.isNativePlatform()\n if (isNative) {\n return await this.checkNativePermission()\n } else {\n return await this.checkWebPermission()\n }\n } catch (error) {\n this.handleError(new Error(`Permission check failed: ${error}`))\n return 'denied'\n }\n }\n\n /**\n * Get FCM token\n */\n async getToken(): Promise<string> {\n if (!this.messaging) {\n throw new Error('Firebase messaging not initialized')\n }\n\n try {\n const firebaseMessaging = await DynamicLoader.loadFirebaseMessaging()\n if (!firebaseMessaging) {\n throw new Error('Firebase messaging is required but not installed')\n }\n const token = await firebaseMessaging.getToken(\n this.messaging,\n this.config?.vapidKey\n ? {\n vapidKey: this.config.vapidKey,\n }\n : undefined\n )\n\n if (token) {\n this.currentToken = token\n return token\n } else {\n throw new Error('No registration token available')\n }\n } catch (error) {\n this.handleError(new Error(`Token retrieval failed: ${error}`))\n throw error\n }\n }\n\n /**\n * Refresh FCM token\n */\n async refreshToken(): Promise<string> {\n if (!this.messaging) {\n throw new Error('Firebase messaging not initialized')\n }\n\n try {\n // Delete current token\n if (this.currentToken) {\n const firebaseMessaging = await DynamicLoader.loadFirebaseMessaging()\n if (firebaseMessaging) {\n await firebaseMessaging.deleteToken(this.messaging)\n }\n }\n\n // Get new token\n const newToken = await this.getToken()\n this.notifyTokenListeners(newToken)\n return newToken\n } catch (error) {\n this.handleError(new Error(`Token refresh failed: ${error}`))\n throw error\n }\n }\n\n /**\n * Delete FCM token\n */\n async deleteToken(): Promise<void> {\n if (!this.messaging) {\n throw new Error('Firebase messaging not initialized')\n }\n\n try {\n const firebaseMessaging = await DynamicLoader.loadFirebaseMessaging()\n if (!firebaseMessaging) {\n throw new Error('Firebase messaging is required but not installed')\n }\n await firebaseMessaging.deleteToken(this.messaging)\n this.currentToken = null\n } catch (error) {\n this.handleError(new Error(`Token deletion failed: ${error}`))\n throw error\n }\n }\n\n /**\n * Subscribe to topic\n */\n async subscribe(topic: string): Promise<void> {\n if (!this.currentToken) {\n throw new Error('No FCM token available')\n }\n\n // Topic subscription is typically handled server-side\n // This is a placeholder for the API call\n await this.callTopicAPI('subscribe', topic, this.currentToken)\n }\n\n /**\n * Unsubscribe from topic\n */\n async unsubscribe(topic: string): Promise<void> {\n if (!this.currentToken) {\n throw new Error('No FCM token available')\n }\n\n // Topic unsubscription is typically handled server-side\n // This is a placeholder for the API call\n await this.callTopicAPI('unsubscribe', topic, this.currentToken)\n }\n\n /**\n * Get subscribed topics\n */\n async getSubscriptions(): Promise<string[]> {\n if (!this.currentToken) {\n throw new Error('No FCM token available')\n }\n\n // This would typically be handled server-side\n // Return empty array as placeholder\n return []\n }\n\n /**\n * Send notification (server-side only)\n */\n async sendNotification(_payload: PushNotificationPayload): Promise<void> {\n try {\n // This would typically be handled server-side with Admin SDK\n // Client-side sending is not supported for security reasons\n throw new Error('Client-side notification sending not supported')\n } catch (error) {\n this.handleError(new Error(`Send notification failed: ${error}`))\n throw error\n }\n }\n\n /**\n * Listen for messages\n */\n onMessage(callback: (payload: PushNotificationPayload) => void): () => void {\n this.messageListeners.push(callback)\n\n return () => {\n const index = this.messageListeners.indexOf(callback)\n if (index > -1) {\n this.messageListeners.splice(index, 1)\n }\n }\n }\n\n /**\n * Listen for token refresh\n */\n onTokenRefresh(callback: (token: string) => void): () => void {\n this.tokenListeners.push(callback)\n\n return () => {\n const index = this.tokenListeners.indexOf(callback)\n if (index > -1) {\n this.tokenListeners.splice(index, 1)\n }\n }\n }\n\n /**\n * Listen for errors\n */\n onError(callback: (error: Error) => void): () => void {\n this.errorListeners.push(callback)\n\n return () => {\n const index = this.errorListeners.indexOf(callback)\n if (index > -1) {\n this.errorListeners.splice(index, 1)\n }\n }\n }\n\n /**\n * Check if Firebase messaging is supported\n */\n async isSupported(): Promise<boolean> {\n try {\n const isNative = await DynamicLoader.isNativePlatform()\n if (isNative) {\n return true\n } else {\n const firebaseMessaging = await DynamicLoader.loadFirebaseMessaging()\n return firebaseMessaging ? await firebaseMessaging.isSupported() : false\n }\n } catch (_error) {\n return false\n }\n }\n\n /**\n * Get provider capabilities\n */\n async getCapabilities(): Promise<ProviderCapabilities> {\n const isWeb = !(await DynamicLoader.isNativePlatform())\n\n return {\n pushNotifications: true,\n topics: true,\n richMedia: true,\n actions: true,\n backgroundSync: true,\n analytics: true,\n segmentation: true,\n scheduling: false, // Server-side only\n geofencing: false,\n inAppMessages: false,\n webPush: isWeb,\n badges: !isWeb,\n sounds: true,\n vibration: !isWeb,\n lights: !isWeb,\n bigText: !isWeb,\n bigPicture: !isWeb,\n inbox: false,\n progress: false,\n channels: !isWeb,\n groups: !isWeb,\n categories: false,\n quietHours: false,\n deliveryReceipts: true,\n clickTracking: true,\n impressionTracking: true,\n customData: true,\n multipleDevices: true,\n userTags: false,\n triggers: false,\n templates: false,\n abTesting: false,\n automation: false,\n journeys: false,\n realTimeUpdates: true,\n }\n }\n\n /**\n * Initialize Firebase messaging\n */\n private async initializeMessaging(): Promise<void> {\n if (!this.app) {\n throw new Error('Firebase app not initialized')\n }\n\n try {\n const firebaseMessaging = await DynamicLoader.loadFirebaseMessaging()\n if (!firebaseMessaging) {\n throw new Error('Firebase messaging is required but not installed')\n }\n \n this.messaging = firebaseMessaging.getMessaging(this.app)\n\n // Setup message listener\n this.unsubscribeMessage = firebaseMessaging.onMessage(\n this.messaging,\n (payload: MessagePayload) => {\n const notificationPayload: PushNotificationPayload = {\n data: payload.data || {},\n to: payload.from,\n collapse_key: payload.collapseKey,\n }\n\n if (payload.notification) {\n const notification: Record<string, unknown> = {}\n if (payload.notification.title)\n notification.title = payload.notification.title\n if (payload.notification.body)\n notification.body = payload.notification.body\n if (payload.notification.icon)\n notification.icon = payload.notification.icon\n if (payload.notification.image)\n notification.image = payload.notification.image\n if (payload.data) notification.data = payload.data\n\n notificationPayload.notification = notification\n }\n\n this.notifyMessageListeners(notificationPayload)\n }\n )\n } catch (error) {\n throw new Error(`Firebase messaging initialization failed: ${error}`)\n }\n }\n\n /**\n * Request native permission\n */\n private async requestNativePermission(): Promise<boolean> {\n try {\n const pushNotificationsModule = await DynamicLoader.loadPushNotifications()\n if (!pushNotificationsModule) {\n throw new Error('Push notifications require @capacitor/push-notifications')\n }\n const { PushNotifications } = pushNotificationsModule\n const result = await PushNotifications.requestPermissions()\n return result.receive === 'granted'\n } catch (_error) {\n return false\n }\n }\n\n /**\n * Check native permission\n */\n private async checkNativePermission(): Promise<PermissionStatus> {\n try {\n const pushNotificationsModule = await DynamicLoader.loadPushNotifications()\n if (!pushNotificationsModule) {\n throw new Error('Push notifications require @capacitor/push-notifications')\n }\n const { PushNotifications } = pushNotificationsModule\n const result = await PushNotifications.checkPermissions()\n\n if (result.receive === 'granted') {\n return 'granted'\n } else if (result.receive === 'denied') {\n return 'denied'\n } else if (result.receive === 'prompt') {\n return 'prompt'\n } else {\n return 'unknown'\n }\n } catch (_error) {\n return 'denied'\n }\n }\n\n /**\n * Request web permission\n */\n private async requestWebPermission(): Promise<boolean> {\n if (!('Notification' in window)) {\n return false\n }\n\n if (Notification.permission === 'granted') {\n return true\n }\n\n if (Notification.permission === 'denied') {\n return false\n }\n\n const permission = await Notification.requestPermission()\n return permission === 'granted'\n }\n\n /**\n * Check web permission\n */\n private async checkWebPermission(): Promise<PermissionStatus> {\n if (!('Notification' in window)) {\n return 'denied'\n }\n\n const permission = Notification.permission\n if (permission === 'default') {\n return 'prompt'\n }\n return permission as PermissionStatus\n }\n\n /**\n * Call topic API (placeholder)\n */\n private async callTopicAPI(\n action: 'subscribe' | 'unsubscribe',\n _topic: string,\n _token: string\n ): Promise<void> {\n // This would typically call your backend API\n // For now, we'll throw an error to indicate server-side implementation needed\n throw new Error(`Topic ${action} must be implemented server-side`)\n }\n\n /**\n * Notify message listeners\n */\n private notifyMessageListeners(payload: PushNotificationPayload): void {\n this.messageListeners.forEach(listener => {\n try {\n listener(payload)\n } catch (error) {\n this.handleError(new Error(`Message listener error: ${error}`))\n }\n })\n }\n\n /**\n * Notify token listeners\n */\n private notifyTokenListeners(token: string): void {\n this.tokenListeners.forEach(listener => {\n try {\n listener(token)\n } catch (error) {\n this.handleError(new Error(`Token listener error: ${error}`))\n }\n })\n }\n\n /**\n * Handle errors\n */\n private handleError(error: Error): void {\n this.errorListeners.forEach(listener => {\n try {\n listener(error)\n } catch (listenerError) {\n // Silently ignore error listener failures\n }\n })\n }\n}\n"],"names":[],"mappings":"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"}