@dashx/react-native 1.1.2 → 1.1.3

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.
package/.DS_Store ADDED
Binary file
@@ -0,0 +1,14 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(xcodebuild -scheme DashX -destination 'generic/platform=iOS')",
5
+ "Bash(grep -v \"^$\")",
6
+ "Bash(find /Users/gulshan/Work/dashx-demo-ios -name *.entitlements)",
7
+ "Bash(wc -l /Users/gulshan/Work/dashx-ios/Sources/DashX/*.swift)",
8
+ "Bash(swift build:*)",
9
+ "Bash(xcodebuild -scheme DashX -destination 'generic/platform=iOS' build)",
10
+ "Bash(./gradlew :dashx:compileDebugKotlin)",
11
+ "Bash(./gradlew :dashx:compileDebugKotlin --info)"
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main,develop]
6
+ pull_request:
7
+ branches: [main,develop]
8
+
9
+ jobs:
10
+ lint-and-test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Setup Node.js
16
+ uses: actions/setup-node@v4
17
+ with:
18
+ node-version: 18
19
+ cache: yarn
20
+
21
+ - name: Install dependencies
22
+ run: yarn install --frozen-lockfile
23
+
24
+ - name: Lint
25
+ run: yarn lint
26
+
27
+ - name: Test
28
+ run: yarn test
@@ -0,0 +1,153 @@
1
+ # Contributing to @dashx/react-native
2
+
3
+ ## Prerequisites
4
+
5
+ - Node.js >= 16
6
+ - Yarn
7
+ - Xcode (for iOS)
8
+ - Android Studio with JDK 17 (for Android)
9
+ - CocoaPods (`gem install cocoapods`)
10
+
11
+ ## Getting Started
12
+
13
+ 1. Clone the repository:
14
+
15
+ ```sh
16
+ git clone https://github.com/dashxhq/dashx-react-native.git
17
+ cd dashx-react-native
18
+ ```
19
+
20
+ 2. Install dependencies:
21
+
22
+ ```sh
23
+ yarn install
24
+ ```
25
+
26
+ 3. Run tests:
27
+
28
+ ```sh
29
+ yarn test
30
+ ```
31
+
32
+ 4. Run lint:
33
+
34
+ ```sh
35
+ yarn lint
36
+ ```
37
+
38
+ ## Building the SDK Locally
39
+
40
+ ### Android
41
+
42
+ The Android bridge lives in `android/` and is a Gradle library module that is built as part of a React Native app — it cannot be built standalone because it depends on the React Native Gradle plugin and Android SDK provided by the host app.
43
+
44
+ To build and test locally, use a React Native demo app (e.g. `dashx-demo-react-native`):
45
+
46
+ 1. In the demo app's `package.json`, point to your local SDK checkout:
47
+
48
+ ```json
49
+ "dependencies": {
50
+ "@dashx/react-native": "file:../dashx-react-native"
51
+ }
52
+ ```
53
+
54
+ 2. Install and build:
55
+
56
+ ```sh
57
+ cd dashx-demo-react-native
58
+ yarn install
59
+ cd android
60
+ ./gradlew assembleDebug
61
+ ```
62
+
63
+ 3. **To test with a local `dashx-android` SDK build**, publish it to local Maven and add `mavenLocal()` to the demo app's `android/build.gradle` repositories:
64
+
65
+ ```sh
66
+ # In dashx-android:
67
+ ./gradlew publishToMavenLocal
68
+
69
+ # In dashx-react-native/android/build.gradle, add:
70
+ repositories {
71
+ mavenLocal()
72
+ // ...
73
+ }
74
+ ```
75
+
76
+ ### iOS
77
+
78
+ The iOS bridge lives in `ios/` and is distributed as a CocoaPod (`DashXReactNative.podspec`). Like Android, it is built as part of a React Native app's Xcode workspace.
79
+
80
+ To build and test locally, use a React Native demo app (e.g. `dashx-demo-react-native`):
81
+
82
+ 1. In the demo app's `package.json`, point to your local SDK checkout:
83
+
84
+ ```json
85
+ "dependencies": {
86
+ "@dashx/react-native": "file:../dashx-react-native"
87
+ }
88
+ ```
89
+
90
+ 2. Install dependencies and pods:
91
+
92
+ ```sh
93
+ cd dashx-demo-react-native
94
+ yarn install
95
+ cd ios
96
+ pod install
97
+ ```
98
+
99
+ 3. Build from Xcode by opening the `.xcworkspace`, or from the command line:
100
+
101
+ ```sh
102
+ xcodebuild -workspace ios/DashXDemoReactNative.xcworkspace \
103
+ -scheme DashXDemoReactNative \
104
+ -destination 'generic/platform=iOS Simulator' \
105
+ build
106
+ ```
107
+
108
+ 4. **To test with a local `dashx-ios` SDK build**, add a path override in the demo app's `Podfile`:
109
+
110
+ ```ruby
111
+ pod 'DashX', :path => '../../dashx-ios'
112
+ ```
113
+
114
+ Then re-run `pod install`.
115
+
116
+ ## Project Structure
117
+
118
+ ```
119
+ dashx-react-native/
120
+ index.js # JS bridge — public API surface
121
+ index.d.ts # TypeScript type definitions
122
+ android/
123
+ src/main/java/com/dashx/rn/sdk/
124
+ DashXReactNativeModule.kt # Android native module
125
+ DashXReactNativePackage.kt # Package registration
126
+ DashXReactNativeFirebaseMessagingService.kt # FCM service
127
+ util/ # Bridge conversion utilities
128
+ build.gradle # Android build config
129
+ ios/
130
+ DashXReactNative.swift # iOS native module
131
+ DashXReactNative.mm # Obj-C++ bridge exports
132
+ DashXEventEmitter.swift # Event emitter for push notifications
133
+ DashXRCTAppDelegate.swift # AppDelegate with Firebase/push handling
134
+ DashXReactNative.podspec # CocoaPods spec
135
+ __tests__/ # Jest tests
136
+ ```
137
+
138
+ ## Running Tests
139
+
140
+ ```sh
141
+ yarn test
142
+ ```
143
+
144
+ Tests mock the React Native native modules and verify the JS bridge layer: input validation, native method delegation, promise handling, and event listener registration.
145
+
146
+ ## Publishing
147
+
148
+ Use `yarn publish` to bump the version and release to npm:
149
+
150
+ ```sh
151
+ yarn publish
152
+ git push origin main
153
+ ```
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
11
11
  s.license = package["license"]
12
12
  s.authors = package["author"]
13
13
 
14
- s.platforms = { :ios => "12.0" }
14
+ s.platforms = { :ios => "13.0" }
15
15
  s.source = { :git => "https://github.com/dashxhq/dashx-react-native.git", :tag => "#{s.version}" }
16
16
 
17
17
  s.source_files = "ios/**/*.{h,m,mm,swift}"
@@ -40,6 +40,10 @@ Pod::Spec.new do |s|
40
40
  end
41
41
  end
42
42
 
43
- s.dependency "DashX", "1.0.19"
44
43
  s.dependency "React-RCTAppDelegate"
44
+ # DashX iOS SDK — consumers must provide the source in their Podfile:
45
+ # pod 'DashX', :git => 'https://github.com/dashxhq/dashx-ios.git', :tag => '1.1.4'
46
+ # For local development:
47
+ # pod 'DashX', :path => '../dashx-ios'
48
+ s.dependency "DashX", "~> 1.1.4"
45
49
  end
package/README.md CHANGED
@@ -30,7 +30,7 @@ _DashX SDK for React Native_
30
30
 
31
31
  | Platform | Minimum Version |
32
32
  |----------|----------------|
33
- | iOS | 12.0+ |
33
+ | iOS | 13.0+ |
34
34
  | Android | SDK 26 (Android 8.0)+ |
35
35
  | React Native | 0.71+ |
36
36
  | Node.js | 16.0+ |
@@ -76,33 +76,67 @@ apply plugin: 'com.google.gms.google-services'
76
76
 
77
77
  ### Setup for iOS
78
78
 
79
- 1. Add Firebase pods to your `Podfile`:
79
+ #### Step 1: Add pods to your Podfile
80
+
81
+ The DashX iOS SDK is not published to CocoaPods trunk. Add it directly from GitHub along with the Firebase pods required for FCM push notifications.
82
+
83
+ Add `use_modular_headers!` at the top of your `ios/Podfile`, then add the pods inside the target block:
80
84
 
81
85
  ```ruby
82
- pod 'FirebaseMessaging', :modular_headers => true
86
+ use_modular_headers!
87
+
88
+ target 'YourApp' do
89
+ # ... other pods
90
+
91
+ pod 'DashX', :git => 'https://github.com/dashxhq/dashx-ios.git', :tag => '1.1.4'
92
+ pod 'FirebaseCore'
93
+ pod 'FirebaseMessaging'
94
+
95
+ use_react_native!(...)
96
+ end
83
97
  ```
84
98
 
85
- 2. Run pod install:
99
+ Then run:
86
100
 
87
101
  ```sh
88
102
  cd ios && pod install
89
103
  ```
90
104
 
91
- 3. Add your iOS app on [Firebase Console](https://console.firebase.google.com/): **Project Overview > Add App > iOS**
105
+ #### Step 2: Add GoogleService-Info.plist
106
+
107
+ 1. Add your iOS app on [Firebase Console](https://console.firebase.google.com/): **Project Overview > Add App > iOS**
108
+ 2. Download `GoogleService-Info.plist` and add it to your Xcode project (right-click project root > **Add Files to "YourApp"**, ensure **Copy items if needed** is checked)
92
109
 
93
- 4. Download `GoogleService-Info.plist` and add it to your Xcode project (right-click project > **Add Files**, ensure **Copy items if needed** is checked).
110
+ #### Step 3: Enable Push Notifications capability
94
111
 
95
- #### Option A: Using `DashXRCTAppDelegate` (Recommended)
112
+ In Xcode, select your app target > **Signing & Capabilities** > **+ Capability** > add **Push Notifications**.
96
113
 
97
- The SDK ships a `DashXRCTAppDelegate` class that handles Firebase configuration, FCM token management, and push notification display out of the box. Subclass it in your `AppDelegate`:
114
+ #### Step 4: Configure your AppDelegate
115
+
116
+ The SDK ships `DashXRCTAppDelegate` which handles permission requests, notification display, and universal link forwarding. Subclass it in your `AppDelegate.swift` and configure Firebase directly:
98
117
 
99
118
  ```swift
100
119
  import DashXReactNative
120
+ import ReactAppDependencyProvider
121
+ import FirebaseCore
122
+ import FirebaseMessaging
123
+ import DashX
124
+ import UserNotifications
101
125
 
102
126
  @main
103
127
  class AppDelegate: DashXRCTAppDelegate {
104
- override func sourceURL(for bridge: RCTBridge) -> URL? {
105
- bundleURL()
128
+ override var moduleName: String { "YourAppName" }
129
+
130
+ override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
131
+ self.dependencyProvider = RCTAppDependencyProvider()
132
+ FirebaseApp.configure()
133
+ Messaging.messaging().delegate = self
134
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
135
+ }
136
+
137
+ // Forward the APNS token to Firebase so it can exchange it for an FCM token
138
+ override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
139
+ Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
106
140
  }
107
141
 
108
142
  override func bundleURL() -> URL? {
@@ -112,47 +146,63 @@ class AppDelegate: DashXRCTAppDelegate {
112
146
  Bundle.main.url(forResource: "main", withExtension: "jsbundle")
113
147
  #endif
114
148
  }
149
+ }
115
150
 
116
- // Called when a notification is tapped
117
- override func notificationClicked(message: [AnyHashable: Any], actionIdentifier: String) {
118
- // Handle notification tap
119
- }
120
-
121
- // Called when a notification arrives while the app is in the foreground
122
- override func notificationDeliveredInForeground(message: [AnyHashable: Any]) -> UNNotificationPresentationOptions {
123
- return [.banner, .sound]
151
+ // Receive the FCM token and pass it to DashX
152
+ extension AppDelegate: MessagingDelegate {
153
+ func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
154
+ guard let token = fcmToken else { return }
155
+ DashX.setFCMToken(to: token)
124
156
  }
125
157
  }
126
158
  ```
127
159
 
128
- #### Option B: Manual setup in AppDelegate
160
+ `DashXRCTAppDelegate` handles the rest automatically:
161
+ - Requests notification permission on launch
162
+ - Displays notifications (banner + sound by default, even while app is in the foreground)
163
+ - Tracks delivery, clicks, and dismissals
164
+ - Forwards universal links to the JS `onLinkReceived` listener
165
+
166
+ **Override points** (all optional):
129
167
 
130
- If you prefer manual control, import Firebase at the top of `/ios/{projectName}/AppDelegate.m`:
168
+ ```swift
169
+ /// Control foreground notification presentation (default: [.banner, .sound])
170
+ override func notificationDeliveredInForeground(message: [AnyHashable: Any]) -> UNNotificationPresentationOptions {
171
+ return [.banner, .sound, .badge]
172
+ }
131
173
 
132
- ```objective-c
133
- #import <FirebaseCore/FirebaseCore.h>
134
- #import <FirebaseMessaging/FirebaseMessaging.h>
174
+ // Called when the user taps a notification or one of its action buttons
175
+ override func notificationClicked(message: [AnyHashable: Any], actionIdentifier: String) {
176
+ // custom tap handling
177
+ }
178
+
179
+ // Called when a universal/deep link arrives
180
+ override func handleLink(url: URL) {
181
+ // custom link handling
182
+ }
135
183
  ```
136
184
 
137
- Then inside `didFinishLaunchingWithOptions`:
185
+ #### Step 5: Subscribe in JavaScript
138
186
 
139
- ```objective-c
140
- [UNUserNotificationCenter currentNotificationCenter].delegate = self;
141
- UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
142
- [[UNUserNotificationCenter currentNotificationCenter]
143
- requestAuthorizationWithOptions:authOptions
144
- completionHandler:^(BOOL granted, NSError * _Nullable error) {
145
- }];
187
+ Call `DashX.subscribe()` at app startup so the SDK registers the device as soon as the FCM token is available:
146
188
 
147
- [application registerForRemoteNotifications];
189
+ ```js
190
+ import { useEffect } from 'react';
191
+ import DashX from '@dashx/react-native';
148
192
 
149
- if ([FIRApp defaultApp] == nil) {
150
- [FIRApp configure];
151
- }
193
+ DashX.configure({ publicKey: 'your-public-key' });
194
+
195
+ export default function App() {
196
+ useEffect(() => {
197
+ DashX.subscribe();
198
+ }, []);
152
199
 
153
- [FIRMessaging messaging].delegate = self;
200
+ // ...
201
+ }
154
202
  ```
155
203
 
204
+ > **Without Firebase:** If you are not using FCM, omit the Firebase pods and the Firebase-related `AppDelegate` code. The SDK will still handle APNS permission requests and notification display via `DashXRCTAppDelegate`.
205
+
156
206
  ## Usage
157
207
 
158
208
  ```js
@@ -229,10 +279,10 @@ DashX.screen('HomeScreen', {
229
279
 
230
280
  ### Fetch a record
231
281
 
232
- Fetch a single record by URN (e.g. `"article/123"`) with optional options (matches [dashx-android](https://github.com/dashxhq/dashx-android) `fetchRecord`). **Android only**; on iOS the promise rejects until the native SDK supports it.
282
+ Fetch a single record by URN (e.g. `"article/uuid"`). The URN must use the full UUID form of the record ID.
233
283
 
234
284
  ```js
235
- const record = await DashX.fetchRecord('article/123', {
285
+ const record = await DashX.fetchRecord('article/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', {
236
286
  preview: false,
237
287
  language: 'en',
238
288
  // fields, include, exclude as arrays of objects if needed
@@ -249,13 +299,12 @@ const record = await DashX.fetchRecord('article/123', {
249
299
 
250
300
  ### Search records
251
301
 
252
- Search records by resource with optional filter, order, limit, and other options (matches [dashx-android](https://github.com/dashxhq/dashx-android) `searchRecords`). **Android only**; on iOS the promise rejects until the native SDK supports it.
253
-
254
302
  ```js
255
303
  const records = await DashX.searchRecords('article', {
256
304
  filter: { status: 'published' },
257
305
  order: [{ field: 'createdAt', direction: 'desc' }],
258
306
  limit: 10,
307
+ page: 1,
259
308
  preview: false,
260
309
  language: 'en',
261
310
  });
@@ -266,6 +315,7 @@ const records = await DashX.searchRecords('article', {
266
315
  | `filter` | `object` | Filter criteria |
267
316
  | `order` | `object[]` | Sort order (e.g. `[{ field, direction }]`) |
268
317
  | `limit` | `number` | Max records to return |
318
+ | `page` | `number` | Page number for pagination |
269
319
  | `preview` | `boolean` | Preview/draft content |
270
320
  | `language` | `string` | Content language |
271
321
  | `fields` | `object[]` | Fields to return |
@@ -286,6 +336,31 @@ Unsubscribe:
286
336
  DashX.unsubscribe();
287
337
  ```
288
338
 
339
+ ### Request notification permission (iOS)
340
+
341
+ Prompt the user for push notification permission. Returns a `NotificationPermissionStatus` integer matching `UNAuthorizationStatus`:
342
+
343
+ | Value | Meaning |
344
+ |-------|---------|
345
+ | `0` | Not determined |
346
+ | `1` | Denied |
347
+ | `2` | Authorized |
348
+ | `3` | Provisional |
349
+ | `4` | Ephemeral |
350
+
351
+ ```js
352
+ const status = await DashX.requestNotificationPermission();
353
+ if (status === 2) {
354
+ DashX.subscribe();
355
+ }
356
+ ```
357
+
358
+ To check the current status without prompting the user:
359
+
360
+ ```js
361
+ const status = await DashX.getNotificationPermissionStatus();
362
+ ```
363
+
289
364
  ### Listen for incoming messages
290
365
 
291
366
  Register a listener to handle push notifications when they arrive:
@@ -302,13 +377,26 @@ useEffect(() => {
302
377
  }, []);
303
378
  ```
304
379
 
380
+ ### Listen for deep links / universal links (iOS)
381
+
382
+ Register a listener that fires when the SDK receives a universal link. On the native side, `DashXRCTAppDelegate` forwards links via `DashX.handleUserActivity` automatically.
383
+
384
+ ```js
385
+ useEffect(() => {
386
+ const subscription = DashX.onLinkReceived((url) => {
387
+ console.log('Link received:', url);
388
+ });
389
+
390
+ return () => subscription.remove();
391
+ }, []);
392
+ ```
393
+
305
394
  ### Notification preferences
306
395
 
307
396
  Fetch the user's stored notification preferences:
308
397
 
309
398
  ```js
310
399
  const preferences = await DashX.fetchStoredPreferences();
311
- console.log(preferences);
312
400
  ```
313
401
 
314
402
  Save updated preferences:
@@ -320,84 +408,103 @@ await DashX.saveStoredPreferences({
320
408
  });
321
409
  ```
322
410
 
323
- ### Logging
411
+ ### Upload an asset (iOS)
324
412
 
325
- Set the SDK log level for debugging:
413
+ Upload a local file to DashX and associate it with a resource and attribute:
326
414
 
327
415
  ```js
328
- DashX.setLogLevel(1); // 0 = off, 1 = errors, 2 = debug
416
+ const response = await DashX.uploadAsset(
417
+ '/path/to/local/file.jpg',
418
+ 'user', // resource name
419
+ 'avatar' // attribute name
420
+ );
421
+ // response: { status, data: { asset: { status, url, playbackIds } } }
329
422
  ```
330
423
 
331
- ### Android example
424
+ ### Fetch an asset (iOS)
332
425
 
333
- Below is a full example of integrating DashX in a React Native Android app:
426
+ Retrieve the status and URL of a previously uploaded asset by its ID:
334
427
 
335
428
  ```js
336
- // App.js
337
- import React from 'react';
338
- import { View, Text, Button, StyleSheet } from 'react-native';
339
- import DashX from '@dashx/react-native';
429
+ const asset = await DashX.fetchAsset('asset-id');
430
+ // asset: { status, data: { asset: { status, url, playbackIds } } }
431
+ ```
340
432
 
341
- // Initialize once at app load
342
- DashX.configure({ publicKey: 'your-public-key' });
343
- DashX.subscribe();
433
+ ### Lifecycle tracking (iOS)
344
434
 
345
- export default function App() {
346
- const handleLogin = () => {
347
- DashX.setIdentity('user-123', 'auth-token');
348
- DashX.identify({
349
- firstName: 'Jane',
350
- lastName: 'Doe',
351
- email: 'jane@example.com',
352
- });
353
- };
354
-
355
- const handleTrack = () => {
356
- DashX.track('Button Pressed', { screen: 'Home' });
357
- };
358
-
359
- const handleLogout = () => {
360
- DashX.unsubscribe();
361
- DashX.reset();
362
- };
363
-
364
- return (
365
- <View style={styles.container}>
366
- <Text style={styles.title}>DashX React Native Demo</Text>
367
- <Button title="Login" onPress={handleLogin} />
368
- <Button title="Track Event" onPress={handleTrack} />
369
- <Button title="Logout" onPress={handleLogout} />
370
- </View>
371
- );
372
- }
435
+ Enable automatic app lifecycle event tracking (app opened, backgrounded, etc.):
373
436
 
374
- const styles = StyleSheet.create({
375
- container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
376
- title: { fontSize: 24, marginBottom: 20 },
377
- });
437
+ ```js
438
+ DashX.enableLifecycleTracking(); // no-op on Android
439
+ ```
440
+
441
+ ### Ad tracking / ATT (iOS)
442
+
443
+ Request App Tracking Transparency permission and enable IDFA tracking:
444
+
445
+ ```js
446
+ DashX.enableAdTracking(); // no-op on Android
447
+ ```
448
+
449
+ Make sure `NSUserTrackingUsageDescription` is set in your `Info.plist`.
450
+
451
+ ### Logging
452
+
453
+ Set the SDK log level for debugging:
454
+
455
+ ```js
456
+ DashX.setLogLevel(1); // 0 = off, 1 = errors, 2 = debug
378
457
  ```
379
458
 
380
459
  ## API Reference
381
460
 
382
- | Method | Signature | Returns | Description |
383
- |--------|-----------|---------|-------------|
384
- | `configure` | `(options: object)` | `void` | Initialize the SDK with your public key |
385
- | `identify` | `(options: object)` | `void` | Identify the current user with traits |
386
- | `setIdentity` | `(uid: string, token: string)` | `void` | Set user identity with UID and auth token |
387
- | `reset` | `()` | `void` | Clear the current user identity |
388
- | `track` | `(event: string, data?: object)` | `void` | Track a named event with optional data |
389
- | `screen` | `(screenName: string, data?: object)` | `void` | Track a screen view with optional data |
390
- | `fetchRecord` | `(urn: string, options?: object)` | `Promise<object>` | Fetch a single record by URN (e.g. `"article/123"`). Options: preview, language, fields, include, exclude. Android only; iOS rejects until implemented. |
391
- | `searchRecords` | `(resource: string, options?: object)` | `Promise<object[]>` | Search records (filter, order, limit, preview, language, fields, include, exclude). Android only; iOS rejects until implemented. |
392
- | `subscribe` | `()` | `void` | Subscribe device for push notifications |
393
- | `unsubscribe` | `()` | `void` | Unsubscribe device from push notifications |
394
- | `fetchStoredPreferences` | `()` | `Promise<object>` | Fetch stored notification preferences |
395
- | `saveStoredPreferences` | `(data: object)` | `Promise<object>` | Save notification preferences |
396
- | `setLogLevel` | `(level: number)` | `void` | Set SDK log verbosity |
397
- | `onMessageReceived` | `(callback: function)` | `EmitterSubscription` | Listen for incoming push notifications |
461
+ | Method | Signature | Platforms | Returns | Description |
462
+ |--------|-----------|-----------|---------|-------------|
463
+ | `configure` | `(options: object)` | iOS, Android | `void` | Initialize the SDK with your public key |
464
+ | `identify` | `(options: object)` | iOS, Android | `void` | Identify the current user with traits |
465
+ | `setIdentity` | `(uid: string, token: string)` | iOS, Android | `void` | Set user identity with UID and auth token |
466
+ | `reset` | `()` | iOS, Android | `void` | Clear the current user identity |
467
+ | `track` | `(event: string, data?: object)` | iOS, Android | `void` | Track a named event with optional data |
468
+ | `screen` | `(screenName: string, data?: object)` | iOS, Android | `void` | Track a screen view |
469
+ | `fetchRecord` | `(urn: string, options?: object)` | iOS, Android | `Promise<object>` | Fetch a single record by URN (`"resource/uuid"`) |
470
+ | `searchRecords` | `(resource: string, options?: object)` | iOS, Android | `Promise<object[]>` | Search records with filter, order, limit, page, etc. |
471
+ | `subscribe` | `()` | iOS, Android | `void` | Subscribe device for push notifications |
472
+ | `unsubscribe` | `()` | iOS, Android | `void` | Unsubscribe device from push notifications |
473
+ | `fetchStoredPreferences` | `()` | iOS, Android | `Promise<object>` | Fetch stored notification preferences |
474
+ | `saveStoredPreferences` | `(data: object)` | iOS, Android | `Promise<object>` | Save notification preferences |
475
+ | `setLogLevel` | `(level: number)` | iOS, Android | `void` | Set SDK log verbosity (0=off, 1=errors, 2=debug) |
476
+ | `onMessageReceived` | `(callback: function)` | iOS, Android | `EmitterSubscription` | Listen for incoming push notifications |
477
+ | `requestNotificationPermission` | `()` | iOS | `Promise<number>` | Prompt for push permission; resolves with `UNAuthorizationStatus` (0-4) |
478
+ | `getNotificationPermissionStatus` | `()` | iOS | `Promise<number>` | Get current push permission status without prompting |
479
+ | `onLinkReceived` | `(callback: function)` | iOS | `EmitterSubscription` | Listen for universal/deep link events |
480
+ | `uploadAsset` | `(filePath: string, resource: string, attribute: string)` | iOS | `Promise<AssetResponse>` | Upload a local file and associate it with a resource attribute |
481
+ | `fetchAsset` | `(assetId: string)` | iOS | `Promise<AssetResponse>` | Fetch status and URL of an uploaded asset |
482
+ | `enableLifecycleTracking` | `()` | iOS | `void` | Enable automatic app lifecycle event tracking |
483
+ | `enableAdTracking` | `()` | iOS | `void` | Request ATT permission and enable IDFA tracking |
398
484
 
399
485
  For detailed usage and advanced features, refer to the [DashX documentation](https://docs.dashx.com/developer).
400
486
 
487
+ ### Error Codes
488
+
489
+ Promise rejections from native methods use a consistent error code across both platforms:
490
+
491
+ | Code | Description |
492
+ |------|-------------|
493
+ | `EUNSPECIFIED` | An unspecified error occurred |
494
+
495
+ The error code is available on the `code` property of the rejected error:
496
+
497
+ ```js
498
+ try {
499
+ await DashX.fetchRecord('article/123');
500
+ } catch (error) {
501
+ console.log(error.code); // "EUNSPECIFIED"
502
+ console.log(error.message); // human-readable description
503
+ }
504
+ ```
505
+
506
+ A `DashXErrorCode` enum is exported from the TypeScript definitions for type-safe comparisons.
507
+
401
508
  ## Contributing
402
509
 
403
510
  Please follow [these steps](https://github.com/dashxhq/dashx-js/tree/master/examples/react-native#setting-up-development-environment) to set up the development environment.