@loyalytics/swan-react-native-sdk 2.5.1-beta.2 → 2.5.1-beta.4

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.
@@ -160,6 +160,8 @@ function _resetClickDedup() {
160
160
 
161
161
  class SwanSDK {
162
162
  listeners = {};
163
+ coldStartCheckDone = false;
164
+ pendingNotificationPayload = null;
163
165
  SDK_VERSION = _version.SDK_VERSION;
164
166
  isProduction = 'STAGE';
165
167
  appId = '';
@@ -628,6 +630,25 @@ class SwanSDK {
628
630
  }
629
631
  this.listeners[event].push(callback);
630
632
 
633
+ // On first NOTIFICATION_OPENED listener, check for pending cold-start notifications.
634
+ // The native side holds click data until consumed — we just need to ask when ready.
635
+ if (event === SwanSDK.EVENTS.NOTIFICATION_OPENED && !this.coldStartCheckDone) {
636
+ this.coldStartCheckDone = true;
637
+ // Defer to next microtask so the listener is fully registered before events emit
638
+ Promise.resolve().then(() => {
639
+ // Deliver buffered standard/image push notification (one-shot APIs like
640
+ // getInitialNotification() can't be re-read — data was buffered in emitNotificationOpened).
641
+ // Skip carousel notifications — checkPendingCarouselClick() handles those with per-item routes.
642
+ const payload = this.pendingNotificationPayload;
643
+ this.pendingNotificationPayload = null;
644
+ if (payload && payload.notificationType !== 'carousel') {
645
+ this.emitNotificationOpened(payload);
646
+ }
647
+ // Check for pending carousel click (native side holds data until consumed)
648
+ this.checkPendingCarouselClick();
649
+ });
650
+ }
651
+
631
652
  // Return a subscription object for easy cleanup
632
653
  return {
633
654
  remove: () => {
@@ -653,6 +674,15 @@ class SwanSDK {
653
674
  * @internal - Used by module-level notification handlers
654
675
  */
655
676
  emitNotificationOpened(payload) {
677
+ const listeners = this.listeners[SwanSDK.EVENTS.NOTIFICATION_OPENED];
678
+ if ((!listeners || listeners.length === 0) && !this.coldStartCheckDone) {
679
+ // Cold start: buffer for delivery when first listener registers.
680
+ // One-shot APIs like getInitialNotification() won't have this data later.
681
+ _Logger.default.log('[SwanSDK] Buffering notification payload for deferred delivery');
682
+ this.pendingNotificationPayload = payload;
683
+ return;
684
+ }
685
+ this.pendingNotificationPayload = null;
656
686
  this.emit(SwanSDK.EVENTS.NOTIFICATION_OPENED, payload);
657
687
  // Also emit unified deep link event for push source
658
688
  this.emitDeepLinkOpened({
@@ -958,9 +988,6 @@ class SwanSDK {
958
988
  _Logger.default.log('[SwanSDK] Tracking initial app launch event...');
959
989
  this.appLaunched();
960
990
 
961
- // Check for pending carousel click (covers killed/quit → fresh launch)
962
- this.checkPendingCarouselClick();
963
-
964
991
  // AppState listener setup (always runs)
965
992
  _Logger.default.log('[SwanSDK] Setting up AppState listener...');
966
993
  this.setupAppStateListener();
@@ -1826,11 +1853,12 @@ class SwanSDK {
1826
1853
  // Read click data from App Group (written by Content Extension)
1827
1854
  clickData = await _SharedCredentialsManager.SharedCredentialsManager.readTemplateClickData();
1828
1855
 
1829
- // If no data yet, retry after a short delay.
1830
- // The Content Extension may still be writing when the app foregrounds.
1856
+ // Exponential backoff: Content Extension may still be writing to App Group
1831
1857
  if (!clickData) {
1832
- await new Promise(r => setTimeout(r, 500));
1833
- clickData = await _SharedCredentialsManager.SharedCredentialsManager.readTemplateClickData();
1858
+ for (let attempt = 0; attempt < 4 && !clickData; attempt++) {
1859
+ await new Promise(r => setTimeout(r, 100 * Math.pow(2, attempt)));
1860
+ clickData = await _SharedCredentialsManager.SharedCredentialsManager.readTemplateClickData();
1861
+ }
1834
1862
  }
1835
1863
  }
1836
1864
  if (!clickData) return;