@dashx/react-native 1.5.0 → 1.5.1

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 (85) hide show
  1. package/README.md +1 -1
  2. package/ios/DashXReactNative.mm +7 -7
  3. package/ios/DashXReactNative.swift +15 -11
  4. package/package.json +13 -11
  5. package/.claude/settings.local.json +0 -7
  6. package/.claude/worktrees/autocapture-conventions-review-78f665/.gitattributes +0 -1
  7. package/.claude/worktrees/autocapture-conventions-review-78f665/.github/workflows/ci.yml +0 -67
  8. package/.claude/worktrees/autocapture-conventions-review-78f665/.gitignore +0 -49
  9. package/.claude/worktrees/autocapture-conventions-review-78f665/.nvmrc +0 -1
  10. package/.claude/worktrees/autocapture-conventions-review-78f665/CHANGELOG.md +0 -144
  11. package/.claude/worktrees/autocapture-conventions-review-78f665/CONTRIBUTING.md +0 -190
  12. package/.claude/worktrees/autocapture-conventions-review-78f665/DashXReactNative.podspec +0 -38
  13. package/.claude/worktrees/autocapture-conventions-review-78f665/LICENSE +0 -21
  14. package/.claude/worktrees/autocapture-conventions-review-78f665/README.md +0 -97
  15. package/.claude/worktrees/autocapture-conventions-review-78f665/__tests__/fallback.test.js +0 -72
  16. package/.claude/worktrees/autocapture-conventions-review-78f665/__tests__/index.test.js +0 -702
  17. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gitignore +0 -10
  18. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/checksums/checksums.lock +0 -0
  19. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/fileChanges/last-build.bin +0 -0
  20. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/fileHashes/fileHashes.lock +0 -0
  21. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/gc.properties +0 -0
  22. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  23. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  24. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/vcs-1/gc.properties +0 -0
  25. package/.claude/worktrees/autocapture-conventions-review-78f665/android/build/reports/problems/problems-report.html +0 -663
  26. package/.claude/worktrees/autocapture-conventions-review-78f665/android/build.gradle +0 -121
  27. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  28. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  29. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle.properties +0 -1
  30. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradlew +0 -185
  31. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradlew.bat +0 -89
  32. package/.claude/worktrees/autocapture-conventions-review-78f665/android/settings.gradle +0 -27
  33. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/AndroidManifest.xml +0 -19
  34. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXNotificationClickedListener.kt +0 -113
  35. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeFirebaseMessagingService.kt +0 -72
  36. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModuleImpl.kt +0 -445
  37. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/MessageReceivedEventHolder.kt +0 -14
  38. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/ReactNativeLibraryInfoProvider.kt +0 -8
  39. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/util/Utils.kt +0 -208
  40. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/resources/META-INF/services/com.dashx.android.DashXLibraryInfoProvider +0 -1
  41. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -85
  42. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -33
  43. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -106
  44. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -33
  45. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/test/java/com/dashx/rn/sdk/util/UtilsTest.kt +0 -305
  46. package/.claude/worktrees/autocapture-conventions-review-78f665/babel.config.js +0 -3
  47. package/.claude/worktrees/autocapture-conventions-review-78f665/index.d.ts +0 -321
  48. package/.claude/worktrees/autocapture-conventions-review-78f665/index.js +0 -300
  49. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXEventEmitter.swift +0 -15
  50. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXNotificationHandler.swift +0 -301
  51. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative-Bridging-Header.h +0 -3
  52. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.mm +0 -77
  53. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.swift +0 -244
  54. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcodeproj/project.pbxproj +0 -280
  55. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcworkspace/contents.xcworkspacedata +0 -7
  56. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  57. package/.claude/worktrees/autocapture-conventions-review-78f665/package.json +0 -123
  58. package/.claude/worktrees/autocapture-conventions-review-78f665/scripts/generate-bridge-shim.js +0 -259
  59. package/.claude/worktrees/autocapture-conventions-review-78f665/src/NativeDashXReactNative.ts +0 -42
  60. package/.claude/worktrees/autocapture-conventions-review-78f665/yarn.lock +0 -6244
  61. package/.gitattributes +0 -1
  62. package/.github/workflows/ci.yml +0 -67
  63. package/.gitignore +0 -49
  64. package/.nvmrc +0 -1
  65. package/CHANGELOG.md +0 -144
  66. package/CONTRIBUTING.md +0 -190
  67. package/__tests__/fallback.test.js +0 -72
  68. package/__tests__/index.test.js +0 -702
  69. package/android/.gitignore +0 -10
  70. package/android/.gradle/8.14.3/checksums/checksums.lock +0 -0
  71. package/android/.gradle/8.14.3/fileChanges/last-build.bin +0 -0
  72. package/android/.gradle/8.14.3/fileHashes/fileHashes.lock +0 -0
  73. package/android/.gradle/8.14.3/gc.properties +0 -0
  74. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  75. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  76. package/android/.gradle/vcs-1/gc.properties +0 -0
  77. package/android/build/reports/problems/problems-report.html +0 -663
  78. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  79. package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  80. package/android/gradlew +0 -185
  81. package/android/gradlew.bat +0 -89
  82. package/android/src/test/java/com/dashx/rn/sdk/util/UtilsTest.kt +0 -305
  83. package/babel.config.js +0 -3
  84. package/scripts/generate-bridge-shim.js +0 -259
  85. package/yarn.lock +0 -6244
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center">
2
2
  <br />
3
- <a href="https://dashx.com"><img src="https://raw.githubusercontent.com/dashxhq/dashx-brand-book/master/assets/logo-black-text-color-icon@2x.png" alt="DashX" height="40" /></a>
3
+ <a href="https://dashx.com"><img src="https://raw.githubusercontent.com/dashxhq/brand-book/master/assets/logo-black-text-color-icon@2x.png" alt="DashX" height="40" /></a>
4
4
  <br />
5
5
  <br />
6
6
  <strong>Your All-in-One Product Stack</strong>
@@ -21,17 +21,17 @@ RCT_EXTERN_METHOD(configure:(NSDictionary *)options);
21
21
 
22
22
  RCT_EXTERN_METHOD(identify:(NSDictionary *)options);
23
23
 
24
- RCT_EXTERN_METHOD(setIdentity:(NSString * _Nullable)uid token:(NSString * _Nullable)token);
24
+ RCT_EXTERN_METHOD(setIdentity:(id _Nullable)uid token:(id _Nullable)token);
25
25
 
26
26
  RCT_EXTERN_METHOD(reset);
27
27
 
28
- RCT_EXTERN_METHOD(track:(NSString *)event data:(NSDictionary * _Nullable)data);
28
+ RCT_EXTERN_METHOD(track:(NSString *)event data:(id _Nullable)data);
29
29
 
30
- RCT_EXTERN_METHOD(screen:(NSString *)screenName data:(NSDictionary * _Nullable)data);
30
+ RCT_EXTERN_METHOD(screen:(NSString *)screenName data:(id _Nullable)data);
31
31
 
32
- RCT_EXTERN_METHOD(fetchRecord:(NSString *)urn options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
32
+ RCT_EXTERN_METHOD(fetchRecord:(NSString *)urn options:(id _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
33
33
 
34
- RCT_EXTERN_METHOD(searchRecords:(NSString *)resource options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
34
+ RCT_EXTERN_METHOD(searchRecords:(NSString *)resource options:(id _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
35
35
 
36
36
  RCT_EXTERN_METHOD(fetchStoredPreferences:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
37
37
 
@@ -51,9 +51,9 @@ RCT_EXTERN_METHOD(enableLifecycleTracking);
51
51
 
52
52
  RCT_EXTERN_METHOD(enableAdTracking);
53
53
 
54
- RCT_EXTERN_METHOD(processURL:(NSString *)url source:(NSString * _Nullable)source forwardToLinkHandler:(BOOL)forwardToLinkHandler);
54
+ RCT_EXTERN_METHOD(processURL:(NSString *)url source:(id _Nullable)source forwardToLinkHandler:(BOOL)forwardToLinkHandler);
55
55
 
56
- RCT_EXTERN_METHOD(trackNotificationNavigation:(NSDictionary * _Nullable)action notificationId:(NSString * _Nullable)notificationId);
56
+ RCT_EXTERN_METHOD(trackNotificationNavigation:(id _Nullable)action notificationId:(id _Nullable)notificationId);
57
57
 
58
58
  RCT_EXTERN_METHOD(requestNotificationPermission:(BOOL)fallbackToSettings resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
59
59
 
@@ -40,9 +40,11 @@ class DashXReactNative: RCTEventEmitter {
40
40
  try? DashX.identify(options: stringOptions)
41
41
  }
42
42
 
43
+ // Nullable args are `id`: the new-arch interop runs typed ones through
44
+ // RCTConvert, which logs an NSNull conversion error for every null.
43
45
  @objc(setIdentity:token:)
44
- func setIdentity(_ uid: NSString?, _ token: NSString?) {
45
- DashX.setIdentity(uid: uid as String?, token: token as String?)
46
+ func setIdentity(_ uid: Any?, _ token: Any?) {
47
+ DashX.setIdentity(uid: uid as? String, token: token as? String)
46
48
  }
47
49
 
48
50
  @objc
@@ -51,17 +53,18 @@ class DashXReactNative: RCTEventEmitter {
51
53
  }
52
54
 
53
55
  @objc(track:data:)
54
- func track(_ event: String, _ data: NSDictionary?) {
56
+ func track(_ event: String, _ data: Any?) {
55
57
  DashX.track(event, withData: data as? [String: Any])
56
58
  }
57
59
 
58
60
  @objc(screen:data:)
59
- func screen(_ screenName: String, _ data: NSDictionary?) {
61
+ func screen(_ screenName: String, _ data: Any?) {
60
62
  DashX.screen(screenName, withData: data as? [String: Any])
61
63
  }
62
64
 
63
65
  @objc(fetchRecord:options:resolve:reject:)
64
- func fetchRecord(_ urn: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
66
+ func fetchRecord(_ urn: String, options: Any?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
67
+ let options = options as? NSDictionary
65
68
  DashXClient.instance.fetchRecord(
66
69
  urn: urn,
67
70
  preview: options?["preview"] as? Bool,
@@ -78,7 +81,8 @@ class DashXReactNative: RCTEventEmitter {
78
81
  }
79
82
 
80
83
  @objc(searchRecords:options:resolve:reject:)
81
- func searchRecords(_ resource: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
84
+ func searchRecords(_ resource: String, options: Any?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
85
+ let options = options as? NSDictionary
82
86
  DashXClient.instance.searchRecords(
83
87
  resource: resource,
84
88
  filter: options?["filter"] as? [String: Any],
@@ -199,15 +203,15 @@ class DashXReactNative: RCTEventEmitter {
199
203
  }
200
204
 
201
205
  @objc(processURL:source:forwardToLinkHandler:)
202
- func processURL(_ url: String, source: NSString?, forwardToLinkHandler: Bool) {
206
+ func processURL(_ url: String, source: Any?, forwardToLinkHandler: Bool) {
203
207
  guard let parsedURL = URL(string: url) else { return }
204
- DashX.processURL(parsedURL, source: source as String?, forwardToLinkHandler: forwardToLinkHandler)
208
+ DashX.processURL(parsedURL, source: source as? String, forwardToLinkHandler: forwardToLinkHandler)
205
209
  }
206
210
 
207
211
  @objc(trackNotificationNavigation:notificationId:)
208
- func trackNotificationNavigation(_ action: NSDictionary?, notificationId: NSString?) {
212
+ func trackNotificationNavigation(_ action: Any?, notificationId: Any?) {
209
213
  var navigationAction: NavigationAction? = nil
210
- if let action = action, let type = action["type"] as? String {
214
+ if let action = action as? NSDictionary, let type = action["type"] as? String {
211
215
  switch type {
212
216
  case "deepLink":
213
217
  if let urlString = action["url"] as? String, let url = URL(string: urlString) {
@@ -229,7 +233,7 @@ class DashXReactNative: RCTEventEmitter {
229
233
  break
230
234
  }
231
235
  }
232
- DashX.trackNotificationNavigation(navigationAction, notificationId: notificationId as String?)
236
+ DashX.trackNotificationNavigation(navigationAction, notificationId: notificationId as? String)
233
237
  }
234
238
 
235
239
  @objc(requestNotificationPermission:resolve:reject:)
package/package.json CHANGED
@@ -1,11 +1,18 @@
1
1
  {
2
2
  "name": "@dashx/react-native",
3
3
  "title": "DashX React Native",
4
- "version": "1.5.0",
4
+ "version": "1.5.1",
5
5
  "description": "DashX SDK for React Native",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "files": [
9
+ "android",
10
+ "DashXReactNative.podspec",
11
+ "index.js",
12
+ "index.d.ts",
13
+ "ios",
14
+ "src",
15
+ "README.md",
9
16
  "!**/__fixtures__",
10
17
  "!**/__mocks__",
11
18
  "!**/__tests__",
@@ -15,15 +22,8 @@
15
22
  "!android/gradlew.bat",
16
23
  "!android/gradlew",
17
24
  "!android/local.properties",
18
- "!ios/build",
19
- "*.podspec",
20
- "android",
21
- "DashXReactNative.podspec",
22
- "index.js",
23
- "index.d.ts",
24
- "ios",
25
- "src",
26
- "README.md"
25
+ "!android/src/test",
26
+ "!ios/build"
27
27
  ],
28
28
  "codegenConfig": {
29
29
  "name": "RNDashXReactNativeSpec",
@@ -37,7 +37,9 @@
37
37
  "test": "jest",
38
38
  "lint": "eslint index.js && yarn run check-bridge-shim",
39
39
  "sync-bridge-shim": "node scripts/generate-bridge-shim.js",
40
- "check-bridge-shim": "node scripts/generate-bridge-shim.js && git diff --exit-code ios/DashXReactNative.mm"
40
+ "check-bridge-shim": "node scripts/generate-bridge-shim.js && git diff --exit-code ios/DashXReactNative.mm",
41
+ "check-package": "node scripts/check-package.js",
42
+ "prepublishOnly": "node scripts/check-package.js"
41
43
  },
42
44
  "repository": {
43
45
  "type": "git",
@@ -1,7 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(git fetch *)"
5
- ]
6
- }
7
- }
@@ -1,67 +0,0 @@
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
29
-
30
- # Android JVM unit tests for the bridge (see android/src/test). Runs
31
- # standalone via the minimal `android/settings.gradle` + buildscript block
32
- # added for this purpose — no consumer app checkout required. Scoped to
33
- # PRs against `develop` and pushes to `main` per the team's release
34
- # workflow (feature branches → develop, develop → main on release).
35
- android-test:
36
- runs-on: ubuntu-latest
37
- if: >-
38
- (github.event_name == 'push' && github.ref == 'refs/heads/main') ||
39
- (github.event_name == 'pull_request' && github.base_ref == 'develop')
40
- steps:
41
- - uses: actions/checkout@v4
42
-
43
- - name: Setup JDK 17
44
- uses: actions/setup-java@v4
45
- with:
46
- distribution: temurin
47
- java-version: 17
48
-
49
- - name: Cache Gradle
50
- uses: actions/cache@v4
51
- with:
52
- path: |
53
- ~/.gradle/caches
54
- ~/.gradle/wrapper
55
- key: ${{ runner.os }}-gradle-${{ hashFiles('android/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
56
- restore-keys: ${{ runner.os }}-gradle-
57
-
58
- - name: Run Android unit tests
59
- working-directory: android
60
- run: ./gradlew :testDebugUnitTest --no-daemon
61
-
62
- - name: Upload test report on failure
63
- if: failure()
64
- uses: actions/upload-artifact@v4
65
- with:
66
- name: android-test-report
67
- path: android/build/reports/tests/testDebugUnitTest
@@ -1,49 +0,0 @@
1
-
2
- # OSX
3
- #
4
- .DS_Store
5
-
6
- # node.js
7
- #
8
- node_modules/
9
- npm-debug.log
10
- yarn-error.log
11
-
12
- # Xcode
13
- #
14
- build/
15
- *.pbxuser
16
- !default.pbxuser
17
- *.mode1v3
18
- !default.mode1v3
19
- *.mode2v3
20
- !default.mode2v3
21
- *.perspectivev3
22
- !default.perspectivev3
23
- xcuserdata
24
- *.xccheckout
25
- *.moved-aside
26
- DerivedData
27
- *.hmap
28
- *.ipa
29
- *.xcuserstate
30
- project.xcworkspace
31
-
32
- # Android/IntelliJ
33
- #
34
- build/
35
- .idea
36
- .gradle
37
- # Kotlin 2.x incremental-compile cache (errors/, sessions/). Per-dev,
38
- # regenerated on every compile.
39
- .kotlin/
40
- local.properties
41
- *.iml
42
-
43
- # BUCK
44
- buck-out/
45
- \.buckd/
46
- *.keystore
47
-
48
- # Cursor
49
- .cursor
@@ -1,144 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to `@dashx/react-native` are documented in this file. Format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versions follow [SemVer](https://semver.org/).
4
-
5
- ## [1.5.0] — 2026-10-28
6
-
7
- ### Required upgrade steps
8
-
9
- 1. **Bump the dashx-ios pod tag to 1.6.1 in your `ios/Podfile`**. `pod install` refuses the upgrade otherwise, because the podspec floor is now `>= 1.6.1`:
10
-
11
- ```ruby
12
- pod 'DashX/SDK', :git => 'https://github.com/dashxhq/dashx-ios.git', :tag => '1.6.1'
13
- ```
14
-
15
- ### Breaking
16
-
17
- - **Automatic events are renamed by the native SDKs**, now dashx-ios 1.6.1 and dashx-android 1.5.0. Screen views are `$screen` with the screen name in `$screen_name` (was `Screen Viewed` with `name`), `dx_deep_link_opened` is `Deep Link Opened` and `dx_notification_navigated` is `Push Notification Tapped`, with their data unchanged. Reports, flows or filters on the old names or the `name` key need updating. Lifecycle event names and keys are unchanged.
18
-
19
- ### Added
20
-
21
- - **`DashX.enableLifecycleTracking()` on Android.** Previously iOS only (a no-op on Android). It now registers the dashx-android activity lifecycle callbacks with the application context. Call it after `configure`. With dashx-android 1.5.0 these are app-level: one launch event per cold start, `Application Opened` with `from_background` on return and `Application Backgrounded` on leaving, not one per Activity change.
22
- - **`DashX.trackNavigation(navigationRef)`** for React Navigation. Sends a screen view for the current route once the `NavigationContainer` is ready, then one per change of the focused route's name, and returns a function that stops tracking. Screen views go through `DashX.screen`, which the native SDKs record as `$screen` with the route name in `$screen_name`. Route params are not sent. Works with any React Navigation version through its container ref, without a dependency on `@react-navigation/*`. Prefer it over native screen tracking: React Native screens are routes, not native view controllers or activities.
23
-
24
- ## [1.4.1] — 2026-05-06
25
-
26
- ### Required upgrade steps
27
-
28
- 1. **Bump the dashx-ios pod tag to 1.5.1 in your `ios/Podfile`** — `pod install` will refuse the upgrade otherwise (the podspec floor is now `>= 1.5.1`):
29
-
30
- ```ruby
31
- pod 'DashX/SDK', :git => 'https://github.com/dashxhq/dashx-ios.git', :tag => '1.5.1'
32
- ```
33
-
34
- The floor is required because earlier dashx-ios versions either fall back to silent-push on the backend (pre-1.3.0, throttled by iOS) or omit `.timeSensitive` from the authorization request (pre-1.5.1, causing `interruption-level: time-sensitive` payloads to silently downgrade and stay filterable by Focus / Reduce Interruptions / Scheduled Summary on iOS 18 / 26).
35
-
36
- 2. **Wire `fallbackToSettings: true` somewhere in your permission UI** to recover existing iOS users — fresh installs are auto-fixed by the upgrade, but users who already granted notification permission under the old SDK keep an `.authorized` state without the time-sensitive entitlement, and Apple's `requestAuthorization` is a one-shot grant that can't be silently upgraded. They have to flip the **Time Sensitive Notifications** toggle in iOS Settings themselves.
37
-
38
- ```js
39
- // From a "Notifications acting up?" affordance, or as a one-time
40
- // post-upgrade prompt:
41
- await DashX.requestNotificationPermission({ fallbackToSettings: true });
42
- ```
43
-
44
- When the user is already determined (granted or denied on iOS / permanently denied on Android), this opens the system notification settings page instead of firing a futile `requestAuthorization`. Without this step, your existing iOS users will keep experiencing the original "intermittent / second attempt works" symptom even after upgrading to 1.4.1.
45
-
46
- ### Migration
47
-
48
- - **Consumers who subclass `DashXReactNativeModuleImpl`** and override `requestNotificationPermission(promise:)` need to update the override signature to `requestNotificationPermission(fallbackToSettings: Boolean, promise: Promise)`. Otherwise Kotlin's override resolution silently drops to the impl's version and your custom logic stops running. Same applies to anyone subclassing the new-arch / old-arch `DashXReactNativeModule` wrappers. Most consumers don't subclass these — flagged here for the few that do.
49
-
50
- ### Added
51
-
52
- - **`DashX.requestNotificationPermission({ fallbackToSettings })`.** Optional flag, default `false`. When `true`, the SDK detects platform-specific dead-ends and opens the system notification-settings page instead of firing a futile prompt:
53
- - **iOS** — already granted or denied (iOS no-ops `requestAuthorization` in that state).
54
- - **Android** — `POST_NOTIFICATIONS` permanently denied (Android 13+, two-strikes rule). `requestPermissions()` auto-resolves DENIED without UI in that state.
55
-
56
- Existing call sites (`DashX.requestNotificationPermission()` with no arguments) compile and behave unchanged.
57
-
58
- ### Fixed
59
-
60
- - **Foreground push duplicate-display race in `DashXNotificationHandler.handleRemoteNotification`.** Now short-circuits when the payload already carries `aps.alert`, letting iOS render the notification natively via NSE / `willPresent` instead of racing a duplicate `UNUserNotificationCenter.add(...)` against it. Without the short-circuit the local re-add could clobber the NSE-attached image or briefly flicker on screen.
61
- - **Suspension race in the image-attached reconstruction path.** The `fetchCompletionHandler` now fires only after the async image download and the local `add()` both complete, with a 25-second budget under iOS's background-push limit. Previously the handler fired immediately while the download was still in flight, letting iOS suspend the process before the notification actually displayed.
62
-
63
- ## [1.4.0] — 2026-04-27
64
-
65
- ### Changed
66
-
67
- - **`DashX.unsubscribe()` now returns `Promise<{ success: boolean }>`** (was `void`). Matches `@dashx/browser`'s shape exactly — apps using a Metro `.web.ts` resolver can now share a single typed callsite across web and native.
68
-
69
- **Migration**
70
-
71
- Most existing call sites continue to work unchanged:
72
-
73
- ```ts
74
- DashX.unsubscribe() // ✓ fire-and-forget still works
75
- await DashX.unsubscribe() // ✓ still works (return value just unused)
76
- const { success } = await DashX.unsubscribe() // new capability
77
- ```
78
-
79
- Two situations to watch for after upgrading:
80
-
81
- - **Unhandled-rejection warnings.** Previously the native module surfaced errors only in its own logs; the JS API was silent. Now JS-side promise rejections fire on SDK-state problems (Firebase Messaging dependency missing, `configure()` not yet called) and transport failures (Firebase `deleteToken` failure, GraphQL / network errors). If you never caught errors before because there was nothing to catch, a fire-and-forget `DashX.unsubscribe()` may now surface "Possible Unhandled Promise Rejection" warnings in your console. Wrap with `.catch(...)` or `try / await` if those warnings are noisy.
82
- - **TypeScript `: void` annotations.** `const x: void = DashX.unsubscribe()` no longer compiles. Vanishingly rare in practice but worth a grep.
83
-
84
- **What the resolved value means**
85
-
86
- - **`success: true`** — backend found and unsubscribed a matching contact.
87
- - **`success: false`** — non-error outcome meaning "no matching contact found"; typically the anonymous UID rotated since subscribe, the FCM token is stale, the contact is already unsubscribed, or `unsubscribe()` was called on a device that never subscribed in this session. The device ends up unsubscribed in either case; the boolean is useful for diagnostics and analytics.
88
- - **Promise rejection** — distinct from `success: false` so callers can branch on SDK-misuse vs legitimate no-match.
89
-
90
- - **Native pin bumps to pick up the underlying schema change:**
91
- - `android/build.gradle` → `com.dashx:dashx-android` `1.2.7` → `1.2.8`. The bridge now passes `onSuccess` / `onError(DashXError)` callbacks to the native `DashX.unsubscribe(...)` and resolves/rejects the JS promise accordingly.
92
- - iOS pod consumers should bump `pod 'DashX/SDK'` to `:tag => '1.5.0'` in their Podfile. The bridge now calls `DashX.unsubscribe { result in ... }` and resolves/rejects the JS promise from the `Result<Bool, Error>` completion.
93
-
94
- ## [1.3.2] — 2026-04-22
95
-
96
- ### Added
97
- - **`DashX.onPushNotificationReceived(callback)`** — new name for registering a foreground push listener. Same signature, same subscription shape; matches the `@dashx/browser` API so cross-platform apps using a Metro `.web.ts` wrapper can share the callsite.
98
-
99
- ### Deprecated
100
- - **`DashX.onMessageReceived(callback)`** is now a deprecated alias of `onPushNotificationReceived` and logs a one-time `console.warn` on first call. The name leaked up from Android's Firebase `FirebaseMessagingService.onMessageReceived` override and was ambiguous in the DashX domain ("message" overloaded with `trackMessage` and in-app notifications). Scheduled for removal in the next major version.
101
-
102
- ## [1.3.1] — 2026-04-21
103
-
104
- ### Added
105
- - **`DashX.onNotificationClicked` now fires on Android.** Previously only wired on iOS — the Android bridge didn't register a `DashXNotificationListener` with the SDK, so JS listeners never received tap events. The bridge now registers a listener in `DashXReactNativeModuleImpl.initialize()` and emits a `notificationClicked` event matching the iOS shape: `{ notification, action, actionIdentifier }`. `actionIdentifier` is the tapped button's identifier (body tap → empty string, matching iOS's always-a-string contract).
106
- - Android JVM unit tests for the kotlinx-serialization conversion helpers (`Utils.kt`) — 16 tests covering all primitive types, nested objects/arrays, null handling, round-trips, and regression cases for the two pre-migration crash paths. Runs as a dedicated `android-test` CI job on PRs to `develop` and pushes to `main`.
107
-
108
- ### Changed
109
- - **Android JSON handling consolidated on kotlinx-serialization.** Removed the Gson dependency and the `org.json`-shaped helpers (`MapUtil.java`, `ArrayUtil.java`), rewrote `Utils.kt` to use kotlinx `JsonObject` / `JsonArray` end-to-end. Matches how dashx-android itself serializes (its Apollo scalar mapping is `kotlinx.serialization.json.JsonObject`), eliminates the string round-trips the previous cross-library code was doing, and removes a class of bugs where three JSON libraries coexisted. Internal helper signatures changed (`convertMapToJson` now returns `JsonObject?`, `convertJsonToMap` now takes `JsonObject?`); consumer JS API is unchanged.
110
- - `android/build.gradle` dep on `com.dashx:dashx-android` bumped `1.2.6` → `1.2.7` to receive the new 3-arg `onNotificationClicked(payload, action, actionIdentifier)` listener overload.
111
-
112
- ### Fixed
113
- - `uploadAsset` / `fetchAsset` on Android previously failed to compile against `@dashx/react-native` due to a type mismatch in the TurboModule-migration callsite (`org.json.JSONObject` passed to a Gson `JsonObject`-typed helper, introduced in 1.2.0's TurboModule PR and never caught because no Android consumer had built the bridge since). Fixed by the Gson → kotlinx migration described above.
114
-
115
- ## [1.3.0] — 2026-04-20
116
-
117
- ### Breaking
118
- - **`DashX` pod → `DashX/SDK`.** The podspec now depends on the `DashX/SDK` subspec of [dashx-ios 1.4.0+](https://github.com/dashxhq/dashx-ios) with no version constraint. Consumers must update their Podfile:
119
- ```ruby
120
- # before
121
- pod 'DashX', :git => 'https://github.com/dashxhq/dashx-ios.git', :tag => '1.1.9'
122
-
123
- # after
124
- pod 'DashX/SDK', :git => 'https://github.com/dashxhq/dashx-ios.git', :tag => '1.4.0'
125
- ```
126
- - **`FirebaseMessaging` is now a hard dependency.** Previously the bridge guarded Firebase usage with `#if canImport(FirebaseMessaging)`, but `canImport` doesn't see consumer-Podfile pods at this pod's compile time, so the guard silently elided every FCM code path — push registration stopped working on fresh installs. Consumers must enable modular headers in their Podfile:
127
- ```ruby
128
- use_modular_headers!
129
- # or, per-pod:
130
- pod 'FirebaseMessaging', :modular_headers => true
131
- ```
132
-
133
- ### Added
134
- - `DashX.onNotificationClicked(callback)` — fires when the user taps a DashX notification or one of its action buttons. Callback receives `{ notification, action, actionIdentifier }` where `action` is a resolved `NavigationAction` (`deepLink` / `screen` / `richLanding` / `clickAction`) or `null`.
135
- - `DashXNotificationResponseResult.navigationAction` — new Swift-only field on the helper result type returned by `DashXNotificationHandler.handleNotificationResponse(_:)`.
136
- - `NotificationClickedEvent` exported from `index.d.ts`.
137
-
138
- ### Fixed
139
- - **iOS dev builds silently failing to receive pushes.** `Messaging.messaging().setAPNSToken(_, type: .unknown)` sometimes mis-tagged the APNs environment on dev-signed binaries, producing an FCM token whose pushes 410'd at Apple. The bridge now forces `.sandbox` in `DEBUG` configurations and `.prod` otherwise.
140
- - **`DashX.setIdentity(uid, token)` now passes `null` / `""` / `undefined` through to the native SDK unchanged** (apart from normalizing `undefined → null`, since the RN bridge can't carry `undefined`). Previously the JS wrapper threw on `null` / `""` / `undefined` for `uid`, contradicting the nullable signatures on iOS (`NSString?`) and Android (`String?`). TypeScript signature updated: `setIdentity(uid: string | null, token?: string | null): void`.
141
-
142
- ## [1.2.0] — 2026-04-16
143
-
144
- Previous release — see git log.
@@ -1,190 +0,0 @@
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 — SOURCE OF TRUTH for bridge methods
131
- DashXReactNative.mm # Obj-C++ bridge exports — AUTO-GENERATED, see below
132
- DashXEventEmitter.swift # Event emitter for push notifications
133
- DashXRCTAppDelegate.swift # AppDelegate with Firebase/push handling
134
- scripts/
135
- generate-bridge-shim.js # Regenerates DashXReactNative.mm from the Swift @objc decls
136
- DashXReactNative.podspec # CocoaPods spec
137
- __tests__/ # Jest tests
138
- ```
139
-
140
- ## iOS bridge: editing methods
141
-
142
- `ios/DashXReactNative.mm` is **auto-generated** from `ios/DashXReactNative.swift`.
143
- Don't hand-edit it — your changes will be overwritten on the next regen, and CI
144
- will fail anyway because the committed `.mm` won't match what the script
145
- produces.
146
-
147
- Workflow when adding or changing a bridged method:
148
-
149
- 1. Edit `ios/DashXReactNative.swift`. Each bridged method needs an `@objc`
150
- decoration. Multi-arg methods use the explicit form
151
- `@objc(methodName:label1:label2:)`; zero-arg methods use bare `@objc`.
152
- 2. Run the regen:
153
- ```sh
154
- yarn sync-bridge-shim
155
- ```
156
- 3. Commit both the Swift change AND the regenerated `ios/DashXReactNative.mm`
157
- in the same PR.
158
-
159
- CI verification: `yarn lint` chains `yarn check-bridge-shim`, which re-runs
160
- the generator and fails on a non-empty `git diff` against the committed
161
- `.mm`. So a forgotten `sync-bridge-shim` step is caught at PR time, not in
162
- production.
163
-
164
- Why the `.mm` exists at all: React Native's iOS bridge requires every Swift
165
- method to be declared in BOTH the Swift `@objc` form (for runtime dispatch)
166
- AND in `RCT_EXTERN_METHOD(...)` form in an Obj-C++ shim (for old-arch
167
- consumers' bridge module registration + new-arch compile-time selector
168
- verification). The script makes the Swift declarations the single source of
169
- truth and emits the matching shim mechanically.
170
-
171
- If the script ever fails with `unknown Swift parameter type "..."`, add a
172
- mapping for that type in `scripts/generate-bridge-shim.js`'s
173
- `SWIFT_TO_OBJC` table (one line, then re-run).
174
-
175
- ## Running Tests
176
-
177
- ```sh
178
- yarn test
179
- ```
180
-
181
- Tests mock the React Native native modules and verify the JS bridge layer: input validation, native method delegation, promise handling, and event listener registration.
182
-
183
- ## Publishing
184
-
185
- Use `yarn publish` to bump the version and release to npm:
186
-
187
- ```sh
188
- yarn publish
189
- git push origin main
190
- ```