react-native-notification-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +3082 -0
  2. package/dist/NotificationSDK.d.ts +6 -0
  3. package/dist/NotificationSDK.d.ts.map +1 -0
  4. package/dist/background/BackgroundHandler.d.ts +7 -0
  5. package/dist/background/BackgroundHandler.d.ts.map +1 -0
  6. package/dist/background/registerBackgroundHandler.d.ts +5 -0
  7. package/dist/background/registerBackgroundHandler.d.ts.map +1 -0
  8. package/dist/constants/SDK.d.ts +2 -0
  9. package/dist/constants/SDK.d.ts.map +1 -0
  10. package/dist/core/NotificationManager.d.ts +28 -0
  11. package/dist/core/NotificationManager.d.ts.map +1 -0
  12. package/dist/core/NotificationSDK.d.ts +25 -0
  13. package/dist/core/NotificationSDK.d.ts.map +1 -0
  14. package/dist/core/SDKContainer.d.ts +16 -0
  15. package/dist/core/SDKContainer.d.ts.map +1 -0
  16. package/dist/errors/FirebaseInitializationError.d.ts +5 -0
  17. package/dist/errors/FirebaseInitializationError.d.ts.map +1 -0
  18. package/dist/errors/InvalidNotificationError.d.ts +5 -0
  19. package/dist/errors/InvalidNotificationError.d.ts.map +1 -0
  20. package/dist/errors/NotifeeInitializationError.d.ts +5 -0
  21. package/dist/errors/NotifeeInitializationError.d.ts.map +1 -0
  22. package/dist/errors/NotificationSDKError.d.ts +4 -0
  23. package/dist/errors/NotificationSDKError.d.ts.map +1 -0
  24. package/dist/errors/PermissionDeniedError.d.ts +5 -0
  25. package/dist/errors/PermissionDeniedError.d.ts.map +1 -0
  26. package/dist/errors/SDKNotInitializedError.d.ts +5 -0
  27. package/dist/errors/SDKNotInitializedError.d.ts.map +1 -0
  28. package/dist/errors/index.d.ts +7 -0
  29. package/dist/errors/index.d.ts.map +1 -0
  30. package/dist/events/EventBus.d.ts +11 -0
  31. package/dist/events/EventBus.d.ts.map +1 -0
  32. package/dist/firebase/FirebaseListener.d.ts +28 -0
  33. package/dist/firebase/FirebaseListener.d.ts.map +1 -0
  34. package/dist/firebase/FirebaseService.d.ts +24 -0
  35. package/dist/firebase/FirebaseService.d.ts.map +1 -0
  36. package/dist/index.cjs +858 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.ts +228 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +853 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/interfaces/IEventManager.d.ts +18 -0
  43. package/dist/interfaces/IEventManager.d.ts.map +1 -0
  44. package/dist/interfaces/ILogger.d.ts +6 -0
  45. package/dist/interfaces/ILogger.d.ts.map +1 -0
  46. package/dist/logger/Logger.d.ts +9 -0
  47. package/dist/logger/Logger.d.ts.map +1 -0
  48. package/dist/logging/ConsoleLogger.d.ts +9 -0
  49. package/dist/logging/ConsoleLogger.d.ts.map +1 -0
  50. package/dist/mappers/NotificationMapper.d.ts +14 -0
  51. package/dist/mappers/NotificationMapper.d.ts.map +1 -0
  52. package/dist/notifee/NotifeeService.d.ts +52 -0
  53. package/dist/notifee/NotifeeService.d.ts.map +1 -0
  54. package/dist/permissions/PermissionService.d.ts +35 -0
  55. package/dist/permissions/PermissionService.d.ts.map +1 -0
  56. package/dist/sdk/NotificationContainer.d.ts +16 -0
  57. package/dist/sdk/NotificationContainer.d.ts.map +1 -0
  58. package/dist/sdk/NotificationManager.d.ts +30 -0
  59. package/dist/sdk/NotificationManager.d.ts.map +1 -0
  60. package/dist/sdk/NotificationSDK.d.ts +29 -0
  61. package/dist/sdk/NotificationSDK.d.ts.map +1 -0
  62. package/dist/types/AndroidNotificationOptions.d.ts +12 -0
  63. package/dist/types/AndroidNotificationOptions.d.ts.map +1 -0
  64. package/dist/types/DisplayNotification.d.ts +37 -0
  65. package/dist/types/DisplayNotification.d.ts.map +1 -0
  66. package/dist/types/IOSNotificationOptions.d.ts +6 -0
  67. package/dist/types/IOSNotificationOptions.d.ts.map +1 -0
  68. package/dist/types/NotificationAction.d.ts +9 -0
  69. package/dist/types/NotificationAction.d.ts.map +1 -0
  70. package/dist/types/NotificationChannel.d.ts +11 -0
  71. package/dist/types/NotificationChannel.d.ts.map +1 -0
  72. package/dist/types/NotificationConfig.d.ts +47 -0
  73. package/dist/types/NotificationConfig.d.ts.map +1 -0
  74. package/dist/types/NotificationEvents.d.ts +30 -0
  75. package/dist/types/NotificationEvents.d.ts.map +1 -0
  76. package/dist/types/NotificationPayload.d.ts +15 -0
  77. package/dist/types/NotificationPayload.d.ts.map +1 -0
  78. package/dist/types/NotificationSDKStatus.d.ts +11 -0
  79. package/dist/types/NotificationSDKStatus.d.ts.map +1 -0
  80. package/dist/types/NotificationTrigger.d.ts +20 -0
  81. package/dist/types/NotificationTrigger.d.ts.map +1 -0
  82. package/dist/types/PermissionStatus.d.ts +2 -0
  83. package/dist/types/PermissionStatus.d.ts.map +1 -0
  84. package/dist/types/ScheduledNotification.d.ts +6 -0
  85. package/dist/types/ScheduledNotification.d.ts.map +1 -0
  86. package/dist/types/index.d.ts +10 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/utils/NotificationMapper.d.ts +14 -0
  89. package/dist/utils/NotificationMapper.d.ts.map +1 -0
  90. package/dist/validators/DisplayNotificationValidator.d.ts +5 -0
  91. package/dist/validators/DisplayNotificationValidator.d.ts.map +1 -0
  92. package/dist/validators/NotificationActionValidator.d.ts +5 -0
  93. package/dist/validators/NotificationActionValidator.d.ts.map +1 -0
  94. package/dist/validators/NotificationChannelValidator.d.ts +5 -0
  95. package/dist/validators/NotificationChannelValidator.d.ts.map +1 -0
  96. package/dist/validators/ScheduledNotificationValidator.d.ts +5 -0
  97. package/dist/validators/ScheduledNotificationValidator.d.ts.map +1 -0
  98. package/dist/validators/ValidationAssertions.d.ts +6 -0
  99. package/dist/validators/ValidationAssertions.d.ts.map +1 -0
  100. package/package.json +77 -0
  101. package/plugins/android/withMaven.js +22 -0
  102. package/plugins/app.plugin.js +7 -0
  103. package/plugins/ios/withModularHeaders.js +16 -0
package/dist/index.js ADDED
@@ -0,0 +1,853 @@
1
+ import { Platform, PermissionsAndroid, Linking } from 'react-native';
2
+ import messaging, { AuthorizationStatus } from '@react-native-firebase/messaging';
3
+ import notifee, { AndroidImportance, EventType, RepeatFrequency, TriggerType, AuthorizationStatus as AuthorizationStatus$1 } from '@notifee/react-native';
4
+
5
+ class NotificationSDKError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = "NotificationSDKError";
9
+ Object.setPrototypeOf(this, new.target.prototype);
10
+ }
11
+ }
12
+
13
+ class FirebaseInitializationError extends NotificationSDKError {
14
+ constructor() {
15
+ super("Firebase has not been initialized.");
16
+ this.name = "FirebaseInitializationError";
17
+ }
18
+ }
19
+
20
+ class SDKNotInitializedError extends NotificationSDKError {
21
+ constructor() {
22
+ super("Notification SDK must be initialized before calling this method.");
23
+ this.name = "SDKNotInitializedError";
24
+ }
25
+ }
26
+
27
+ class EventBus {
28
+ listeners = {};
29
+ on(event, listener) {
30
+ if (!this.listeners[event]) {
31
+ //@ts-ignore
32
+ this.listeners[event] = new Set();
33
+ }
34
+ this.listeners[event].add(listener);
35
+ return () => {
36
+ this.off(event, listener);
37
+ };
38
+ }
39
+ off(event, listener) {
40
+ this.listeners[event]?.delete(listener);
41
+ }
42
+ emit(event, payload) {
43
+ this.listeners[event]?.forEach((listener) => listener(payload));
44
+ }
45
+ removeAll() {
46
+ Object.values(this.listeners).forEach((set) => set?.clear());
47
+ }
48
+ }
49
+
50
+ class NotificationMapper {
51
+ /**
52
+ * Converts a Firebase RemoteMessage into the SDK NotificationPayload.
53
+ */
54
+ static fromRemoteMessage(remoteMessage) {
55
+ const rawData = remoteMessage.data ?? {};
56
+ const data = Object.keys(rawData).reduce((acc, key) => {
57
+ const value = rawData[key];
58
+ acc[key] =
59
+ typeof value === "string"
60
+ ? value
61
+ : value == null
62
+ ? ""
63
+ : JSON.stringify(value);
64
+ return acc;
65
+ }, {});
66
+ return {
67
+ id: remoteMessage.messageId ?? "",
68
+ title: remoteMessage.notification?.title ?? data.title,
69
+ body: remoteMessage.notification?.body ?? data.body,
70
+ data,
71
+ };
72
+ }
73
+ /**
74
+ * Converts NotificationPayload into DisplayNotification.
75
+ */
76
+ static toDisplayNotification(notification) {
77
+ return {
78
+ id: notification.id,
79
+ title: notification.title ?? "",
80
+ body: notification.body ?? "",
81
+ data: notification.data,
82
+ };
83
+ }
84
+ }
85
+
86
+ const SDK_VERSION = "0.0.1";
87
+
88
+ class NotificationManager {
89
+ container;
90
+ eventBus;
91
+ constructor(container, eventBus) {
92
+ this.container = container;
93
+ this.eventBus = eventBus;
94
+ }
95
+ initialized = false;
96
+ async initializeFirebase() {
97
+ await this.container.firebaseService.initialize((token) => {
98
+ this.eventBus.emit("tokenRefresh", {
99
+ token,
100
+ });
101
+ });
102
+ this.container.firebaseListener.start();
103
+ }
104
+ registerListeners() {
105
+ this.container.firebaseListener.onMessage(async (notification) => {
106
+ this.eventBus.emit("notificationReceived", {
107
+ notification,
108
+ });
109
+ if (this.container.config.foreground?.displayNotifications) {
110
+ await this.container.notifeeService.displayNotification(NotificationMapper.toDisplayNotification(notification));
111
+ }
112
+ });
113
+ this.container.notifeeService.onNotificationPressed((notification) => {
114
+ this.container.logger.log("Local notification opened.");
115
+ this.eventBus.emit("notificationOpened", {
116
+ notification,
117
+ });
118
+ });
119
+ this.container.notifeeService.onNotificationDismissed((notification) => {
120
+ this.container.logger.log("Local notification dismissed.");
121
+ this.eventBus.emit("notificationDismissed", {
122
+ notification,
123
+ });
124
+ });
125
+ this.container.notifeeService.onNotificationActionPressed((notification, actionId, input) => {
126
+ this.eventBus.emit("notificationActionPressed", {
127
+ notification,
128
+ actionId,
129
+ input,
130
+ });
131
+ });
132
+ }
133
+ async initialize() {
134
+ if (this.initialized) {
135
+ return;
136
+ }
137
+ this.container.logger.log("Initializing SDK...");
138
+ this.registerListeners();
139
+ await this.container.notifeeService.initialize(this.container.config.channels);
140
+ if (this.container.config.ios?.requestPermissionOnLaunch) {
141
+ await this.requestPermission();
142
+ }
143
+ await this.initializeFirebase();
144
+ this.eventBus.emit("initialized", undefined);
145
+ this.container.logger.log("SDK initialized.");
146
+ this.initialized = true;
147
+ }
148
+ async requestPermission() {
149
+ const status = await this.container.permissionService.requestPermission();
150
+ const granted = this.container.permissionService.isGranted(status);
151
+ this.eventBus.emit("permissionChanged", {
152
+ status,
153
+ granted,
154
+ });
155
+ if (granted) {
156
+ await this.initializeFirebase();
157
+ }
158
+ return status;
159
+ }
160
+ async getPermissionStatus() {
161
+ return this.container.permissionService.getPermissionStatus();
162
+ }
163
+ async getToken() {
164
+ await this.initializeFirebase();
165
+ const token = await this.container.firebaseService.getToken();
166
+ this.eventBus.emit("tokenGenerated", { token });
167
+ return token;
168
+ }
169
+ async deleteToken() {
170
+ await this.container.firebaseService.deleteToken();
171
+ }
172
+ async displayNotification(notification) {
173
+ await this.container.notifeeService.displayNotification(notification);
174
+ }
175
+ async cancelNotification(id) {
176
+ await this.container.notifeeService.cancelNotification(id);
177
+ }
178
+ async cancelAllNotifications() {
179
+ await this.container.notifeeService.cancelAllNotifications();
180
+ }
181
+ destroy() {
182
+ this.container.logger.log("Destroying SDK...");
183
+ this.container.firebaseListener.destroy();
184
+ this.container.firebaseService.destroy();
185
+ this.initialized = false;
186
+ }
187
+ async scheduleNotification(notification) {
188
+ return this.container.notifeeService.scheduleNotification(notification);
189
+ }
190
+ async cancelScheduledNotification(id) {
191
+ await this.container.notifeeService.cancelScheduledNotification(id);
192
+ }
193
+ async cancelAllScheduledNotifications() {
194
+ await this.container.notifeeService.cancelAllScheduledNotifications();
195
+ }
196
+ async getScheduledNotifications() {
197
+ return this.container.notifeeService.getScheduledNotifications();
198
+ }
199
+ async getStatus() {
200
+ const permission = await this.container.permissionService.getPermissionStatus();
201
+ let tokenAvailable = false;
202
+ try {
203
+ const token = await this.container.firebaseService.getToken();
204
+ tokenAvailable = !!token;
205
+ }
206
+ catch {
207
+ tokenAvailable = false;
208
+ }
209
+ return {
210
+ initialized: this.initialized,
211
+ firebaseInitialized: this.container.firebaseService.isInitialized(),
212
+ notifeeInitialized: this.container.notifeeService.isInitialized(),
213
+ permission,
214
+ tokenAvailable,
215
+ platform: Platform.OS === "android" ? "android" : "ios",
216
+ sdkVersion: SDK_VERSION,
217
+ };
218
+ }
219
+ registerBackgroundHandler(handler) {
220
+ this.container.firebaseListener.registerBackgroundHandler(async (notification) => {
221
+ if (this.container.config.background?.displayNotifications !== false) {
222
+ await this.container.notifeeService.displayNotification(NotificationMapper.toDisplayNotification(notification));
223
+ }
224
+ await handler?.(notification);
225
+ });
226
+ }
227
+ }
228
+
229
+ class ConsoleLogger {
230
+ enabled;
231
+ constructor(enabled) {
232
+ this.enabled = enabled;
233
+ }
234
+ log(...args) {
235
+ if (!this.enabled)
236
+ return;
237
+ console.log("[NotificationSDK]", ...args);
238
+ }
239
+ warn(...args) {
240
+ if (!this.enabled)
241
+ return;
242
+ console.warn("[NotificationSDK]", ...args);
243
+ }
244
+ error(...args) {
245
+ if (!this.enabled)
246
+ return;
247
+ console.error("[NotificationSDK]", ...args);
248
+ }
249
+ }
250
+
251
+ class FirebaseService {
252
+ logger;
253
+ tokenRefreshUnsubscribe;
254
+ initialized = false;
255
+ constructor(logger) {
256
+ this.logger = logger;
257
+ }
258
+ /**
259
+ * Initializes Firebase Messaging and starts token refresh tracking.
260
+ */
261
+ async initialize(onTokenRefresh) {
262
+ if (this.initialized) {
263
+ this.logger.log("FirebaseService already initialized.");
264
+ return;
265
+ }
266
+ // iOS requires explicit registration with APNs
267
+ if (Platform.OS === "ios") {
268
+ const isRegistered = messaging().isDeviceRegisteredForRemoteMessages;
269
+ if (!isRegistered) {
270
+ this.logger.log("Registering device for remote messages...");
271
+ await messaging().registerDeviceForRemoteMessages();
272
+ this.logger.log("Device registered for remote messages.");
273
+ }
274
+ }
275
+ await messaging().setAutoInitEnabled(true);
276
+ this.tokenRefreshUnsubscribe = messaging().onTokenRefresh((token) => {
277
+ this.logger.log("Firebase token refreshed.");
278
+ onTokenRefresh(token);
279
+ });
280
+ this.initialized = true;
281
+ this.logger.log("FirebaseService initialized.");
282
+ }
283
+ /**
284
+ * Gets the current Firebase Cloud Messaging token.
285
+ */
286
+ async getToken() {
287
+ if (!this.initialized) {
288
+ throw new FirebaseInitializationError();
289
+ }
290
+ // Extra safety for iOS
291
+ if (Platform.OS === "ios") {
292
+ const registered = messaging().isDeviceRegisteredForRemoteMessages;
293
+ if (!registered) {
294
+ try {
295
+ await messaging().registerDeviceForRemoteMessages();
296
+ }
297
+ catch (e) {
298
+ this.logger.warn("Unable to register for remote messages.");
299
+ throw e;
300
+ }
301
+ }
302
+ }
303
+ const token = await messaging().getToken();
304
+ this.logger.log("FCM token generated.");
305
+ return token;
306
+ }
307
+ /**
308
+ * Deletes the current Firebase Cloud Messaging token.
309
+ */
310
+ async deleteToken() {
311
+ await messaging().deleteToken();
312
+ this.logger.log("FCM token deleted.");
313
+ }
314
+ destroy() {
315
+ this.tokenRefreshUnsubscribe?.();
316
+ this.tokenRefreshUnsubscribe = undefined;
317
+ this.initialized = false;
318
+ }
319
+ isInitialized() {
320
+ return this.initialized;
321
+ }
322
+ }
323
+
324
+ class PermissionService {
325
+ logger;
326
+ constructor(logger) {
327
+ this.logger = logger;
328
+ }
329
+ /**
330
+ * Requests notification permission.
331
+ */
332
+ async requestPermission() {
333
+ try {
334
+ this.logger.log("Requesting notification permission...");
335
+ // Android
336
+ if (Platform.OS === "android") {
337
+ if (Platform.Version >= 33) {
338
+ const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
339
+ const status = result === PermissionsAndroid.RESULTS.GRANTED
340
+ ? "authorized"
341
+ : "denied";
342
+ this.logger.log(`Permission status: ${status}`);
343
+ return status;
344
+ }
345
+ this.logger.log("Android < 13 detected. Notification permission is granted by default.");
346
+ return "authorized";
347
+ }
348
+ // iOS
349
+ const authorizationStatus = await messaging().requestPermission();
350
+ const status = this.normalizeStatus(authorizationStatus);
351
+ this.logger.log(`Permission status: ${status}`);
352
+ if (this.isGranted(status) &&
353
+ !messaging().isDeviceRegisteredForRemoteMessages) {
354
+ this.logger.log("Registering device for remote messages...");
355
+ await messaging().registerDeviceForRemoteMessages();
356
+ this.logger.log("Device registered for remote messages.");
357
+ }
358
+ return status;
359
+ }
360
+ catch (error) {
361
+ this.logger.error("Failed to request notification permission.", error);
362
+ throw error;
363
+ }
364
+ }
365
+ /**
366
+ * Returns current notification permission status.
367
+ */
368
+ async getPermissionStatus() {
369
+ try {
370
+ // Android
371
+ if (Platform.OS === "android") {
372
+ if (Platform.Version < 33) {
373
+ return "authorized";
374
+ }
375
+ const granted = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
376
+ return granted ? "authorized" : "denied";
377
+ }
378
+ // iOS
379
+ const authorizationStatus = await messaging().hasPermission();
380
+ return this.normalizeStatus(authorizationStatus);
381
+ }
382
+ catch (error) {
383
+ this.logger.error("Failed to get notification permission status.", error);
384
+ throw error;
385
+ }
386
+ }
387
+ /**
388
+ * Opens the application settings.
389
+ */
390
+ async openSettings() {
391
+ this.logger.log("Opening application settings...");
392
+ await Linking.openSettings();
393
+ }
394
+ /**
395
+ * Returns true if permission is granted.
396
+ */
397
+ isGranted(status) {
398
+ return status === "authorized" || status === "provisional";
399
+ }
400
+ /**
401
+ * Registers device for remote messages (iOS only).
402
+ */
403
+ async registerForRemoteMessages() {
404
+ if (Platform.OS !== "ios") {
405
+ return;
406
+ }
407
+ if (messaging().isDeviceRegisteredForRemoteMessages) {
408
+ this.logger.log("Device already registered for remote messages.");
409
+ return;
410
+ }
411
+ this.logger.log("Registering device for remote messages...");
412
+ await messaging().registerDeviceForRemoteMessages();
413
+ this.logger.log("Device registered for remote messages.");
414
+ }
415
+ /**
416
+ * Unregisters device for remote messages (iOS only).
417
+ */
418
+ async unregisterForRemoteMessages() {
419
+ if (Platform.OS !== "ios") {
420
+ return;
421
+ }
422
+ if (!messaging().isDeviceRegisteredForRemoteMessages) {
423
+ return;
424
+ }
425
+ this.logger.log("Unregistering device for remote messages...");
426
+ await messaging().unregisterDeviceForRemoteMessages();
427
+ this.logger.log("Device unregistered.");
428
+ }
429
+ /**
430
+ * Converts Firebase authorization status.
431
+ */
432
+ normalizeStatus(status) {
433
+ switch (status) {
434
+ case AuthorizationStatus.AUTHORIZED:
435
+ return "authorized";
436
+ case AuthorizationStatus.PROVISIONAL:
437
+ return "provisional";
438
+ case AuthorizationStatus.DENIED:
439
+ return "denied";
440
+ case AuthorizationStatus.NOT_DETERMINED:
441
+ return "notDetermined";
442
+ default:
443
+ return "unknown";
444
+ }
445
+ }
446
+ }
447
+
448
+ class FirebaseListener {
449
+ logger;
450
+ foregroundUnsubscribe;
451
+ notificationOpenedUnsubscribe;
452
+ messageListener;
453
+ notificationOpenedListener;
454
+ initialNotificationListener;
455
+ constructor(logger) {
456
+ this.logger = logger;
457
+ }
458
+ /**
459
+ * Starts listening for foreground Firebase messages.
460
+ */
461
+ start() {
462
+ if (this.foregroundUnsubscribe || this.notificationOpenedUnsubscribe) {
463
+ return;
464
+ }
465
+ this.logger.log("Starting Firebase listeners...");
466
+ this.foregroundUnsubscribe = messaging().onMessage((remoteMessage) => {
467
+ this.logger.log("Foreground notification received.");
468
+ this.messageListener?.(NotificationMapper.fromRemoteMessage(remoteMessage));
469
+ });
470
+ this.notificationOpenedUnsubscribe = messaging().onNotificationOpenedApp((remoteMessage) => {
471
+ this.logger.log("Notification opened from background.");
472
+ this.notificationOpenedListener?.(NotificationMapper.fromRemoteMessage(remoteMessage));
473
+ });
474
+ void this.checkInitialNotification();
475
+ }
476
+ /**
477
+ * Stops all Firebase listeners.
478
+ */
479
+ destroy() {
480
+ this.foregroundUnsubscribe?.();
481
+ this.notificationOpenedUnsubscribe?.();
482
+ this.foregroundUnsubscribe = undefined;
483
+ this.notificationOpenedUnsubscribe = undefined;
484
+ }
485
+ onMessage(listener) {
486
+ this.messageListener = listener;
487
+ }
488
+ /**
489
+ * Maps Firebase RemoteMessage to SDK NotificationPayload.
490
+ */
491
+ async checkInitialNotification() {
492
+ try {
493
+ const remoteMessage = await messaging().getInitialNotification();
494
+ if (!remoteMessage) {
495
+ return;
496
+ }
497
+ this.logger.log("Notification opened from terminated state.");
498
+ this.initialNotificationListener?.(NotificationMapper.fromRemoteMessage(remoteMessage));
499
+ }
500
+ catch (error) {
501
+ this.logger.error("Failed to get initial notification.", error);
502
+ }
503
+ }
504
+ registerBackgroundHandler(handler) {
505
+ messaging().setBackgroundMessageHandler(async (remoteMessage) => {
506
+ const notification = NotificationMapper.fromRemoteMessage(remoteMessage);
507
+ await handler(notification);
508
+ });
509
+ }
510
+ }
511
+
512
+ class NotifeeService {
513
+ logger;
514
+ defaultChannelId;
515
+ mapImportance(importance) {
516
+ switch (importance) {
517
+ case "none":
518
+ return AndroidImportance.NONE;
519
+ case "min":
520
+ return AndroidImportance.MIN;
521
+ case "low":
522
+ return AndroidImportance.LOW;
523
+ case "default":
524
+ return AndroidImportance.DEFAULT;
525
+ case "high":
526
+ return AndroidImportance.HIGH;
527
+ case "max":
528
+ return AndroidImportance.HIGH;
529
+ default:
530
+ return AndroidImportance.HIGH;
531
+ }
532
+ }
533
+ async createChannel(channel) {
534
+ return notifee.createChannel({
535
+ id: channel.id,
536
+ name: channel.name,
537
+ description: channel.description,
538
+ importance: this.mapImportance(channel.importance),
539
+ });
540
+ }
541
+ notificationPressedListener;
542
+ notificationDismissedListener;
543
+ handleForegroundEvent = ({ type, detail }) => {
544
+ if (!detail.notification) {
545
+ return;
546
+ }
547
+ const notification = this.mapNotification(detail.notification);
548
+ switch (type) {
549
+ case EventType.PRESS:
550
+ this.logger.log("Local notification pressed.");
551
+ this.notificationPressedListener?.(notification);
552
+ break;
553
+ case EventType.DISMISSED:
554
+ this.logger.log("Local notification dismissed.");
555
+ this.notificationDismissedListener?.(notification);
556
+ break;
557
+ case EventType.ACTION_PRESS:
558
+ this.logger.log("Notification action pressed.");
559
+ this.notificationActionPressedListener?.(notification, detail.pressAction?.id ?? "", detail.input);
560
+ break;
561
+ }
562
+ };
563
+ mapNotification(notification) {
564
+ return {
565
+ id: notification?.id ?? "",
566
+ title: notification?.title ?? "",
567
+ body: notification?.body ?? "",
568
+ data: (notification?.data ?? {}),
569
+ };
570
+ }
571
+ initialized = false;
572
+ unsubscribeForeground;
573
+ buildTrigger(notification) {
574
+ const trigger = notification.trigger;
575
+ switch (trigger.type) {
576
+ case "timestamp":
577
+ return {
578
+ type: TriggerType.TIMESTAMP,
579
+ timestamp: trigger.timestamp,
580
+ };
581
+ case "interval":
582
+ return {
583
+ type: TriggerType.TIMESTAMP,
584
+ timestamp: Date.now() + trigger.interval * 1000,
585
+ repeatFrequency: trigger.repeat ? RepeatFrequency.DAILY : undefined,
586
+ };
587
+ }
588
+ }
589
+ buildAndroidNotification(notification) {
590
+ const android = {
591
+ channelId: notification.android?.channelId ?? this.defaultChannelId ?? "default",
592
+ autoCancel: notification.android?.autoCancel ?? true,
593
+ pressAction: {
594
+ id: notification.android?.pressActionId ?? "default",
595
+ },
596
+ };
597
+ if (notification.android?.smallIcon) {
598
+ android.smallIcon = notification.android.smallIcon;
599
+ }
600
+ if (notification.android?.largeIcon) {
601
+ android.largeIcon = notification.android.largeIcon;
602
+ }
603
+ if (notification.android?.color) {
604
+ android.color = notification.android.color;
605
+ }
606
+ if (notification.actions?.length) {
607
+ android.actions = notification.actions.map((action) => ({
608
+ title: action.title,
609
+ pressAction: {
610
+ id: action.id,
611
+ launchActivity: action.launchActivity === "default" ? "default" : undefined,
612
+ },
613
+ destructive: action.destructive,
614
+ input: action.allowInput ? true : undefined,
615
+ }));
616
+ }
617
+ return android;
618
+ }
619
+ buildIOSNotification(notification) {
620
+ const ios = {};
621
+ if (notification.ios?.badge !== undefined) {
622
+ ios.badgeCount = notification.ios.badge;
623
+ }
624
+ if (notification.ios?.sound) {
625
+ ios.sound = notification.ios.sound;
626
+ }
627
+ if (notification.ios?.categoryId) {
628
+ ios.categoryId = notification.ios.categoryId;
629
+ }
630
+ return ios;
631
+ }
632
+ buildNotification(notification) {
633
+ return {
634
+ title: notification.title,
635
+ subtitle: notification.subtitle,
636
+ body: notification.body,
637
+ data: notification.data,
638
+ android: Platform.OS === "android"
639
+ ? this.buildAndroidNotification(notification)
640
+ : undefined,
641
+ ios: Platform.OS === "ios"
642
+ ? this.buildIOSNotification(notification)
643
+ : undefined,
644
+ };
645
+ }
646
+ notificationActionPressedListener;
647
+ constructor(logger) {
648
+ this.logger = logger;
649
+ }
650
+ /**
651
+ * Initializes Notifee.
652
+ */
653
+ async initialize(channels) {
654
+ if (this.initialized) {
655
+ return;
656
+ }
657
+ this.unsubscribeForeground = notifee.onForegroundEvent(this.handleForegroundEvent);
658
+ if (Platform.OS === "android") {
659
+ if (!channels?.length) {
660
+ await this.createDefaultChannel();
661
+ }
662
+ else {
663
+ for (const channel of channels) {
664
+ await this.createChannel(channel);
665
+ }
666
+ }
667
+ }
668
+ this.initialized = true;
669
+ this.logger.log("Notifee initialized.");
670
+ }
671
+ /**
672
+ * Creates the SDK default notification channel.
673
+ */
674
+ async createDefaultChannel() {
675
+ if (this.defaultChannelId) {
676
+ return this.defaultChannelId;
677
+ }
678
+ this.defaultChannelId = await notifee.createChannel({
679
+ id: "default",
680
+ name: "Default",
681
+ importance: AndroidImportance.HIGH,
682
+ });
683
+ this.logger.log(`Default notification channel created (${this.defaultChannelId})`);
684
+ return this.defaultChannelId;
685
+ }
686
+ /**
687
+ * Requests notification permission.
688
+ */
689
+ async requestPermission() {
690
+ if (Platform.OS === "android") {
691
+ return true;
692
+ }
693
+ const settings = await notifee.requestPermission();
694
+ return settings.authorizationStatus === AuthorizationStatus$1.AUTHORIZED;
695
+ }
696
+ /**
697
+ * Displays a local notification.
698
+ */
699
+ async displayNotification(notification) {
700
+ if (Platform.OS === "android" && !this.defaultChannelId) {
701
+ await this.createDefaultChannel();
702
+ }
703
+ await notifee.displayNotification(this.buildNotification(notification));
704
+ this.logger.log("Notification displayed.");
705
+ }
706
+ async cancelNotification(id) {
707
+ await notifee.cancelNotification(id);
708
+ }
709
+ async cancelAllNotifications() {
710
+ await notifee.cancelAllNotifications();
711
+ }
712
+ onNotificationPressed(listener) {
713
+ this.notificationPressedListener = listener;
714
+ }
715
+ onNotificationDismissed(listener) {
716
+ this.notificationDismissedListener = listener;
717
+ }
718
+ destroy() {
719
+ this.unsubscribeForeground?.();
720
+ this.unsubscribeForeground = undefined;
721
+ this.notificationPressedListener = undefined;
722
+ this.notificationDismissedListener = undefined;
723
+ this.initialized = false;
724
+ this.logger.log("Notifee destroyed.");
725
+ }
726
+ async scheduleNotification(notification) {
727
+ if (Platform.OS === "android" && !this.defaultChannelId) {
728
+ await this.createDefaultChannel();
729
+ }
730
+ const trigger = this.buildTrigger(notification);
731
+ const id = await notifee.createTriggerNotification(this.buildNotification(notification), trigger);
732
+ this.logger.log(`Notification scheduled (${id})`);
733
+ return id;
734
+ }
735
+ async cancelScheduledNotification(id) {
736
+ await notifee.cancelTriggerNotification(id);
737
+ }
738
+ async cancelAllScheduledNotifications() {
739
+ await notifee.cancelTriggerNotifications();
740
+ }
741
+ async getScheduledNotifications() {
742
+ return notifee.getTriggerNotifications();
743
+ }
744
+ onNotificationActionPressed(listener) {
745
+ this.notificationActionPressedListener = listener;
746
+ }
747
+ isInitialized() {
748
+ return this.initialized;
749
+ }
750
+ }
751
+
752
+ class SDKContainer {
753
+ config;
754
+ logger;
755
+ permissionService;
756
+ firebaseService;
757
+ firebaseListener;
758
+ notifeeService;
759
+ // readonly deepLinkService: DeepLinkService;
760
+ constructor(config) {
761
+ this.config = Object.freeze({
762
+ ...config,
763
+ });
764
+ this.logger = new ConsoleLogger(config.debug ?? false);
765
+ this.permissionService = new PermissionService(this.logger);
766
+ this.firebaseService = new FirebaseService(this.logger);
767
+ this.firebaseListener = new FirebaseListener(this.logger);
768
+ this.notifeeService = new NotifeeService(this.logger);
769
+ // this.deepLinkService = new DeepLinkService(this.logger);
770
+ }
771
+ }
772
+
773
+ class NotificationSDK {
774
+ eventBus = new EventBus();
775
+ manager;
776
+ async initialize(config) {
777
+ if (this.manager) {
778
+ return;
779
+ }
780
+ const container = new SDKContainer(config);
781
+ this.manager = new NotificationManager(container, this.eventBus);
782
+ await this.manager.initialize();
783
+ }
784
+ on(event, listener) {
785
+ return this.eventBus.on(event, listener);
786
+ }
787
+ off(event, listener) {
788
+ this.eventBus.off(event, listener);
789
+ }
790
+ async requestPermission() {
791
+ return this.getManager().requestPermission();
792
+ }
793
+ async getPermissionStatus() {
794
+ return this.getManager().getPermissionStatus();
795
+ }
796
+ async getToken() {
797
+ return this.getManager().getToken();
798
+ }
799
+ async deleteToken() {
800
+ await this.getManager().deleteToken();
801
+ }
802
+ async displayNotification(notification) {
803
+ await this.getManager().displayNotification(notification);
804
+ }
805
+ async cancelNotification(id) {
806
+ await this.getManager().cancelNotification(id);
807
+ }
808
+ async cancelAllNotifications() {
809
+ await this.getManager().cancelAllNotifications();
810
+ }
811
+ async scheduleNotification(notification) {
812
+ return this.getManager().scheduleNotification(notification);
813
+ }
814
+ async cancelScheduledNotification(id) {
815
+ await this.getManager().cancelScheduledNotification(id);
816
+ }
817
+ async cancelAllScheduledNotifications() {
818
+ await this.getManager().cancelAllScheduledNotifications();
819
+ }
820
+ async getScheduledNotifications() {
821
+ return this.getManager().getScheduledNotifications();
822
+ }
823
+ destroy() {
824
+ this.manager?.destroy();
825
+ this.manager = undefined;
826
+ this.eventBus.removeAll();
827
+ }
828
+ async getStatus() {
829
+ return this.getManager().getStatus();
830
+ }
831
+ getManager() {
832
+ if (!this.manager) {
833
+ throw new SDKNotInitializedError();
834
+ }
835
+ return this.manager;
836
+ }
837
+ }
838
+
839
+ function registerBackgroundHandler(handler) {
840
+ messaging().setBackgroundMessageHandler(async (remoteMessage) => {
841
+ const notification = NotificationMapper.fromRemoteMessage(remoteMessage);
842
+ const logger = new ConsoleLogger(false);
843
+ const notifee = new NotifeeService(logger);
844
+ await notifee.initialize();
845
+ await notifee.displayNotification(NotificationMapper.toDisplayNotification(notification));
846
+ await handler?.(notification);
847
+ });
848
+ }
849
+
850
+ const Notifications = new NotificationSDK();
851
+
852
+ export { Notifications as default, registerBackgroundHandler };
853
+ //# sourceMappingURL=index.js.map