@loyalytics/swan-react-native-sdk 2.5.1-beta.7 → 2.5.1-beta.8

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.
@@ -638,22 +638,32 @@ class SwanSDK {
638
638
  }
639
639
  this.listeners[event].push(callback);
640
640
 
641
- // On first NOTIFICATION_OPENED listener, check for pending cold-start notifications.
642
- // The native side holds click data until consumed we just need to ask when ready.
643
- if (event === SwanSDK.EVENTS.NOTIFICATION_OPENED && !this.coldStartCheckDone) {
644
- this.coldStartCheckDone = true;
641
+ // On every NOTIFICATION_OPENED listener registration, check for buffered notifications.
642
+ // Runs on cold start (process dead getInitialNotification buffered), warm restart
643
+ // (process alive but Activity destroyed by swipe-from-recents on Android), and
644
+ // Metro hot-reload (component unmount/remount cycles).
645
+ if (event === SwanSDK.EVENTS.NOTIFICATION_OPENED) {
645
646
  // Defer to next microtask so the listener is fully registered before events emit
646
647
  Promise.resolve().then(() => {
647
- // Deliver buffered standard/image push notification (one-shot APIs like
648
- // getInitialNotification() can't be re-read data was buffered in emitNotificationOpened).
649
- // Skip carousel notifications — checkPendingCarouselClick() handles those with per-item routes.
650
- const payload = this.pendingNotificationPayload;
651
- this.pendingNotificationPayload = null;
652
- if (payload && payload.notificationType !== 'carousel') {
653
- this.emitNotificationOpened(payload);
648
+ // Deliver buffered standard/image push notification.
649
+ // Skip carousel checkPendingCarouselClick() handles those with per-item routes.
650
+ if (this.pendingNotificationPayload) {
651
+ const payload = this.pendingNotificationPayload;
652
+ this.pendingNotificationPayload = null;
653
+ if (payload.notificationType !== 'carousel') {
654
+ this.emit(SwanSDK.EVENTS.NOTIFICATION_OPENED, payload);
655
+ this.emitDeepLinkOpened({
656
+ ...payload,
657
+ source: 'push'
658
+ });
659
+ }
654
660
  }
655
- // Check for pending carousel click (native side holds data until consumed)
661
+ // Check for pending carousel click (native side holds data until consumed).
662
+ // Unconditional: handles both cold start and warm restart carousel taps.
656
663
  this.checkPendingCarouselClick();
664
+ if (!this.coldStartCheckDone) {
665
+ this.coldStartCheckDone = true;
666
+ }
657
667
  });
658
668
  }
659
669
 
@@ -683,9 +693,11 @@ class SwanSDK {
683
693
  */
684
694
  emitNotificationOpened(payload) {
685
695
  const listeners = this.listeners[SwanSDK.EVENTS.NOTIFICATION_OPENED];
686
- if ((!listeners || listeners.length === 0) && !this.coldStartCheckDone) {
687
- // Cold start: buffer for delivery when first listener registers.
688
- // One-shot APIs like getInitialNotification() won't have this data later.
696
+ if (!listeners || listeners.length === 0) {
697
+ // No listeners yet — buffer for delivery when first listener registers.
698
+ // Handles: true cold start (process dead), Activity recreation (process alive
699
+ // but Activity destroyed by swipe-from-recents on Android), and Metro
700
+ // hot-reload (component unmount/remount cycles).
689
701
  _Logger.default.log('[SwanSDK] Buffering notification payload for deferred delivery');
690
702
  this.pendingNotificationPayload = payload;
691
703
  return;