@teardown/react-native 2.0.29 → 2.0.32

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.
@@ -4,7 +4,7 @@ description: Push notification adapters for token registration and management.
4
4
  icon: Bell
5
5
  ---
6
6
 
7
- Notification adapters handle push notification token registration and management with your push notification provider.
7
+ Notification adapters handle push notification token registration, permission requests, and notification event handling with your push notification provider.
8
8
 
9
9
  ## Available Adapters
10
10
 
@@ -16,40 +16,94 @@ Notification adapters handle push notification token registration and management
16
16
 
17
17
  ## Usage
18
18
 
19
- Notification adapters are optional and used separately from the core SDK:
19
+ Notification adapters are passed to `TeardownCore` to enable push notification support:
20
20
 
21
21
  ```typescript
22
- import { ExpoNotificationsAdapter } from '@teardown/react-native/expo-notifications';
22
+ import { TeardownCore } from '@teardown/react-native';
23
+ import { ExpoNotificationsAdapter } from '@teardown/react-native/expo';
24
+ import { ExpoDeviceAdapter } from '@teardown/react-native/adapters/expo';
25
+ import { MMKVStorageAdapter } from '@teardown/react-native/adapters/mmkv';
26
+
27
+ const teardown = new TeardownCore({
28
+ org_id: 'your-org-id',
29
+ project_id: 'your-project-id',
30
+ api_key: 'your-api-key',
31
+ storageAdapter: new MMKVStorageAdapter(),
32
+ deviceAdapter: new ExpoDeviceAdapter(),
33
+ notificationAdapter: new ExpoNotificationsAdapter(), // Optional
34
+ });
35
+
36
+ // Access notifications via core
37
+ if (teardown.notifications) {
38
+ const token = await teardown.notifications.getToken();
39
+ }
40
+ ```
41
+
42
+ ## Adapter Interface
43
+
44
+ All notification adapters extend the abstract `NotificationAdapter` class:
45
+
46
+ ```typescript
47
+ abstract class NotificationAdapter {
48
+ /** The notification platform this adapter supports (APNS, FCM, EXPO) */
49
+ abstract get platform(): NotificationPlatformEnum;
23
50
 
24
- const notificationsAdapter = new ExpoNotificationsAdapter();
51
+ /** Get the current push notification token */
52
+ abstract getToken(): Promise<string | null>;
25
53
 
26
- // Get push token
27
- const token = await notificationsAdapter.getToken();
54
+ /** Request push notification permissions from the user */
55
+ abstract requestPermissions(): Promise<PermissionStatus>;
28
56
 
29
- // Register token with your backend
30
- await registerPushToken(token);
57
+ /** Subscribe to token refresh events */
58
+ abstract onTokenRefresh(listener: (token: string) => void): Unsubscribe;
59
+
60
+ /** Subscribe to foreground notification events */
61
+ abstract onNotificationReceived(listener: (notification: PushNotification) => void): Unsubscribe;
62
+
63
+ /** Subscribe to notification opened events (user taps) */
64
+ abstract onNotificationOpened(listener: (notification: PushNotification) => void): Unsubscribe;
65
+
66
+ /** Subscribe to data-only message events (silent/background push) */
67
+ abstract onDataMessage(listener: (message: DataMessage) => void): Unsubscribe;
68
+ }
31
69
  ```
32
70
 
33
- ## Adapter Interface
71
+ ### PermissionStatus
72
+
73
+ ```typescript
74
+ interface PermissionStatus {
75
+ /** Whether notifications permission is granted */
76
+ granted: boolean;
77
+ /** Whether the user can be prompted again (iOS specific) */
78
+ canAskAgain: boolean;
79
+ }
80
+ ```
34
81
 
35
- All notification adapters implement:
82
+ ### PushNotification
36
83
 
37
84
  ```typescript
38
- interface NotificationsAdapter {
39
- /** Get the push notification token */
40
- getToken(): Promise<string | null>;
85
+ interface PushNotification {
86
+ title?: string;
87
+ body?: string;
88
+ data?: Record<string, unknown>;
89
+ }
90
+ ```
41
91
 
42
- /** Request notification permissions */
43
- requestPermissions(): Promise<boolean>;
92
+ ### DataMessage
44
93
 
45
- /** Check if notifications are enabled */
46
- isEnabled(): Promise<boolean>;
94
+ ```typescript
95
+ interface DataMessage {
96
+ data: Record<string, unknown>;
97
+ }
98
+ ```
47
99
 
48
- /** Subscribe to incoming notifications */
49
- onNotification(handler: (notification: Notification) => void): () => void;
100
+ ### NotificationPlatformEnum
50
101
 
51
- /** Subscribe to notification responses (user taps) */
52
- onNotificationResponse(handler: (response: NotificationResponse) => void): () => void;
102
+ ```typescript
103
+ enum NotificationPlatformEnum {
104
+ APNS = "APNS", // Apple Push Notification Service
105
+ FCM = "FCM", // Firebase Cloud Messaging
106
+ EXPO = "EXPO", // Expo Push Notifications
53
107
  }
54
108
  ```
55
109
 
@@ -64,37 +118,64 @@ interface NotificationsAdapter {
64
118
 
65
119
  ## Custom Adapter
66
120
 
67
- Implement the `NotificationsAdapter` interface:
121
+ Extend the `NotificationAdapter` abstract class:
68
122
 
69
123
  ```typescript
70
- import type { NotificationsAdapter, Notification, NotificationResponse } from '@teardown/react-native';
124
+ import {
125
+ NotificationAdapter,
126
+ NotificationPlatformEnum,
127
+ type PermissionStatus,
128
+ type PushNotification,
129
+ type DataMessage,
130
+ type Unsubscribe,
131
+ } from '@teardown/react-native';
132
+
133
+ class CustomNotificationsAdapter extends NotificationAdapter {
134
+ get platform(): NotificationPlatformEnum {
135
+ return NotificationPlatformEnum.FCM;
136
+ }
71
137
 
72
- class CustomNotificationsAdapter implements NotificationsAdapter {
73
138
  async getToken(): Promise<string | null> {
74
- // Return push token from your notification library
75
139
  return await myNotificationLib.getToken();
76
140
  }
77
141
 
78
- async requestPermissions(): Promise<boolean> {
79
- // Request notification permissions
80
- return await myNotificationLib.requestPermission();
142
+ async requestPermissions(): Promise<PermissionStatus> {
143
+ const granted = await myNotificationLib.requestPermission();
144
+ return { granted, canAskAgain: !granted };
81
145
  }
82
146
 
83
- async isEnabled(): Promise<boolean> {
84
- // Check if notifications are enabled
85
- return await myNotificationLib.areNotificationsEnabled();
147
+ onTokenRefresh(listener: (token: string) => void): Unsubscribe {
148
+ const subscription = myNotificationLib.onTokenRefresh(listener);
149
+ return () => subscription.remove();
86
150
  }
87
151
 
88
- onNotification(handler: (notification: Notification) => void): () => void {
89
- // Subscribe to incoming notifications
90
- const subscription = myNotificationLib.onNotification(handler);
91
- return () => subscription.remove();
152
+ onNotificationReceived(listener: (notification: PushNotification) => void): Unsubscribe {
153
+ const subscription = myNotificationLib.onMessage((msg) => {
154
+ listener({
155
+ title: msg.notification?.title,
156
+ body: msg.notification?.body,
157
+ data: msg.data,
158
+ });
159
+ });
160
+ return () => subscription();
92
161
  }
93
162
 
94
- onNotificationResponse(handler: (response: NotificationResponse) => void): () => void {
95
- // Subscribe to notification taps
96
- const subscription = myNotificationLib.onNotificationOpened(handler);
97
- return () => subscription.remove();
163
+ onNotificationOpened(listener: (notification: PushNotification) => void): Unsubscribe {
164
+ const subscription = myNotificationLib.onNotificationOpened((msg) => {
165
+ listener({
166
+ title: msg.notification?.title,
167
+ body: msg.notification?.body,
168
+ data: msg.data,
169
+ });
170
+ });
171
+ return () => subscription();
172
+ }
173
+
174
+ onDataMessage(listener: (message: DataMessage) => void): Unsubscribe {
175
+ const subscription = myNotificationLib.onDataMessage((msg) => {
176
+ listener({ data: msg.data ?? {} });
177
+ });
178
+ return () => subscription();
98
179
  }
99
180
  }
100
181
  ```
@@ -21,74 +21,104 @@ cd ios && pod install
21
21
  ## Usage
22
22
 
23
23
  ```typescript
24
- import { WixNotificationsAdapter } from '@teardown/react-native/wix-notifications';
25
-
26
- const notifications = new WixNotificationsAdapter();
27
-
28
- // Request permissions
29
- const granted = await notifications.requestPermissions();
24
+ import { TeardownCore } from '@teardown/react-native';
25
+ import { WixNotificationsAdapter } from '@teardown/react-native/wix';
26
+ import { DeviceInfoAdapter } from '@teardown/react-native/adapters/device-info';
27
+ import { AsyncStorageAdapter } from '@teardown/react-native/adapters/async-storage';
28
+
29
+ const teardown = new TeardownCore({
30
+ org_id: 'your-org-id',
31
+ project_id: 'your-project-id',
32
+ api_key: 'your-api-key',
33
+ storageAdapter: new AsyncStorageAdapter(),
34
+ deviceAdapter: new DeviceInfoAdapter(),
35
+ notificationAdapter: new WixNotificationsAdapter(),
36
+ });
30
37
 
31
- if (granted) {
32
- // Get push token
33
- const token = await notifications.getToken();
34
- console.log('Push token:', token);
38
+ // Access via NotificationsClient
39
+ if (teardown.notifications) {
40
+ const status = await teardown.notifications.requestPermissions();
41
+ if (status.granted) {
42
+ const token = await teardown.notifications.getToken();
43
+ console.log('Push token:', token);
44
+ }
35
45
  }
36
46
  ```
37
47
 
38
48
  ## Import Path
39
49
 
40
50
  ```typescript
41
- import { WixNotificationsAdapter } from '@teardown/react-native/wix-notifications';
51
+ import { WixNotificationsAdapter } from '@teardown/react-native/wix';
42
52
  ```
43
53
 
44
54
  ## API
45
55
 
56
+ All methods are accessed via `NotificationsClient`, not directly on the adapter.
57
+
58
+ ### requestPermissions()
59
+
60
+ Request notification permissions:
61
+
62
+ ```typescript
63
+ const status = await teardown.notifications.requestPermissions();
64
+ // Returns: { granted: boolean, canAskAgain: boolean }
65
+ ```
66
+
46
67
  ### getToken()
47
68
 
48
69
  Get the device push token:
49
70
 
50
71
  ```typescript
51
- const token = await notifications.getToken();
72
+ const token = await teardown.notifications.getToken();
52
73
  // Returns: device token string or null
53
74
  ```
54
75
 
55
- ### requestPermissions()
76
+ ### onNotificationReceived()
56
77
 
57
- Request notification permissions:
78
+ Subscribe to foreground notifications:
58
79
 
59
80
  ```typescript
60
- const granted = await notifications.requestPermissions();
61
- // Returns: true if granted, false otherwise
81
+ const unsubscribe = teardown.notifications.onNotificationReceived((notification) => {
82
+ console.log('Received:', notification.title);
83
+ });
84
+
85
+ // Cleanup
86
+ unsubscribe();
62
87
  ```
63
88
 
64
- ### isEnabled()
89
+ ### onNotificationOpened()
65
90
 
66
- Check if notifications are enabled:
91
+ Subscribe to notification taps:
67
92
 
68
93
  ```typescript
69
- const enabled = await notifications.isEnabled();
94
+ const unsubscribe = teardown.notifications.onNotificationOpened((notification) => {
95
+ console.log('User tapped:', notification.title);
96
+ });
97
+
98
+ // Cleanup
99
+ unsubscribe();
70
100
  ```
71
101
 
72
- ### onNotification()
102
+ ### onTokenRefresh()
73
103
 
74
- Subscribe to incoming notifications:
104
+ Subscribe to token changes:
75
105
 
76
106
  ```typescript
77
- const unsubscribe = notifications.onNotification((notification) => {
78
- console.log('Received:', notification.title);
107
+ const unsubscribe = teardown.notifications.onTokenChange((token) => {
108
+ console.log('New token:', token);
79
109
  });
80
110
 
81
111
  // Cleanup
82
112
  unsubscribe();
83
113
  ```
84
114
 
85
- ### onNotificationResponse()
115
+ ### onDataMessage()
86
116
 
87
- Subscribe to notification opens:
117
+ Subscribe to data-only messages (silent push):
88
118
 
89
119
  ```typescript
90
- const unsubscribe = notifications.onNotificationResponse((response) => {
91
- console.log('User tapped:', response.notification.title);
120
+ const unsubscribe = teardown.notifications.onDataMessage((message) => {
121
+ console.log('Data message:', message.data);
92
122
  });
93
123
 
94
124
  // Cleanup
@@ -128,6 +158,10 @@ unsubscribe();
128
158
  import com.wix.reactnativenotifications.RNNotificationsPackage;
129
159
  ```
130
160
 
161
+ ## Platform
162
+
163
+ Returns `NotificationPlatformEnum.APNS` on iOS, `NotificationPlatformEnum.FCM` on Android.
164
+
131
165
  ## When to Use
132
166
 
133
167
  - Existing projects using react-native-notifications
package/docs/advanced.mdx CHANGED
@@ -31,6 +31,86 @@ export const teardown = new TeardownCore({
31
31
  });
32
32
  ```
33
33
 
34
+ ## Push Notifications Setup
35
+
36
+ Enable push notifications by providing a notification adapter:
37
+
38
+ ```typescript
39
+ import { TeardownCore } from '@teardown/react-native';
40
+ import { ExpoNotificationsAdapter, ExpoDeviceAdapter } from '@teardown/react-native/expo';
41
+ import { MMKVStorageAdapter } from '@teardown/react-native/adapters/mmkv';
42
+
43
+ const teardown = new TeardownCore({
44
+ org_id: 'your-org-id',
45
+ project_id: 'your-project-id',
46
+ api_key: 'your-api-key',
47
+ storageAdapter: new MMKVStorageAdapter(),
48
+ deviceAdapter: new ExpoDeviceAdapter(),
49
+ notificationAdapter: new ExpoNotificationsAdapter(), // Enable notifications
50
+ });
51
+
52
+ // Request permissions and get token
53
+ if (teardown.notifications) {
54
+ const status = await teardown.notifications.requestPermissions();
55
+ if (status.granted) {
56
+ const token = await teardown.notifications.getToken();
57
+ // Token is automatically sent with identify() calls
58
+ }
59
+ }
60
+ ```
61
+
62
+ ### Handle Notifications
63
+
64
+ ```typescript
65
+ const { core } = useTeardown();
66
+
67
+ useEffect(() => {
68
+ if (!core.notifications) return;
69
+
70
+ const unsubs = [
71
+ core.notifications.onNotificationReceived((notification) => {
72
+ // Foreground notification
73
+ console.log('Notification:', notification.title);
74
+ }),
75
+ core.notifications.onNotificationOpened((notification) => {
76
+ // User tapped notification
77
+ navigateToScreen(notification.data?.screen);
78
+ }),
79
+ core.notifications.onDataMessage((message) => {
80
+ // Silent/data message
81
+ syncData(message.data);
82
+ }),
83
+ ];
84
+
85
+ return () => unsubs.forEach(unsub => unsub());
86
+ }, [core.notifications]);
87
+ ```
88
+
89
+ ## Event Tracking
90
+
91
+ Track custom events:
92
+
93
+ ```typescript
94
+ const { core } = useTeardown();
95
+
96
+ // Track single event
97
+ await core.events.track({
98
+ event_name: 'purchase_completed',
99
+ event_type: 'action',
100
+ properties: {
101
+ product_id: 'abc123',
102
+ amount: 99.99,
103
+ currency: 'USD',
104
+ },
105
+ });
106
+
107
+ // Track multiple events
108
+ await core.events.trackBatch([
109
+ { event_name: 'cart_viewed', event_type: 'screen_view' },
110
+ { event_name: 'item_added', properties: { item_id: 'xyz' } },
111
+ ]);
112
+ ```
113
+
34
114
  ## Disable Force Update Checking
35
115
 
36
116
  For debugging or testing:
@@ -133,12 +213,24 @@ export const useTeardown = () => ({
133
213
  core: {
134
214
  identity: {
135
215
  identify: jest.fn().mockResolvedValue({ success: true, data: mockSession }),
136
- reset: jest.fn(),
216
+ signOut: jest.fn().mockResolvedValue({ success: true, data: undefined }),
217
+ signOutAll: jest.fn().mockResolvedValue({ success: true, data: undefined }),
137
218
  getSessionState: () => mockSession,
138
219
  },
139
220
  forceUpdate: {
140
221
  getVersionStatus: () => ({ type: 'up_to_date' }),
141
222
  },
223
+ events: {
224
+ track: jest.fn().mockResolvedValue({ success: true, data: undefined }),
225
+ trackBatch: jest.fn().mockResolvedValue({ success: true, data: undefined }),
226
+ },
227
+ notifications: {
228
+ requestPermissions: jest.fn().mockResolvedValue({ granted: true, canAskAgain: true }),
229
+ getToken: jest.fn().mockResolvedValue('mock-push-token'),
230
+ onNotificationReceived: jest.fn().mockReturnValue(() => {}),
231
+ onNotificationOpened: jest.fn().mockReturnValue(() => {}),
232
+ onDataMessage: jest.fn().mockReturnValue(() => {}),
233
+ },
142
234
  },
143
235
  });
144
236
 
@@ -148,6 +240,7 @@ export const useForceUpdate = () => ({
148
240
  isUpdateRequired: false,
149
241
  isUpdateRecommended: false,
150
242
  isUpdateAvailable: false,
243
+ releaseNotes: null,
151
244
  });
152
245
  ```
153
246
 
@@ -187,8 +280,11 @@ console.log('Device ID:', await core.device.getDeviceId());
187
280
  For debugging or logout:
188
281
 
189
282
  ```typescript
190
- core.identity.reset();
191
- // This clears session data and device association
283
+ // Sign out - clears session, keeps device ID
284
+ await core.identity.signOut();
285
+
286
+ // Full reset - clears session AND device ID (fresh install state)
287
+ await core.identity.signOutAll();
192
288
  ```
193
289
 
194
290
  ## Performance