@cxpinsight/react-native 0.2.0

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 (253) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/babel.js +101 -0
  4. package/instrumented/Pressable.d.ts +2 -0
  5. package/instrumented/Pressable.js +2 -0
  6. package/instrumented/ScrollView.d.ts +2 -0
  7. package/instrumented/ScrollView.js +2 -0
  8. package/instrumented/TextInput.d.ts +2 -0
  9. package/instrumented/TextInput.js +2 -0
  10. package/instrumented/TouchableOpacity.d.ts +2 -0
  11. package/instrumented/TouchableOpacity.js +2 -0
  12. package/lib/CXPinsight.d.ts +113 -0
  13. package/lib/CXPinsight.d.ts.map +1 -0
  14. package/lib/CXPinsight.js +831 -0
  15. package/lib/CXPinsight.js.map +1 -0
  16. package/lib/CXPinsightProvider.d.ts +19 -0
  17. package/lib/CXPinsightProvider.d.ts.map +1 -0
  18. package/lib/CXPinsightProvider.js +382 -0
  19. package/lib/CXPinsightProvider.js.map +1 -0
  20. package/lib/core/autoScreenTracker.d.ts +20 -0
  21. package/lib/core/autoScreenTracker.d.ts.map +1 -0
  22. package/lib/core/autoScreenTracker.js +66 -0
  23. package/lib/core/autoScreenTracker.js.map +1 -0
  24. package/lib/core/deepLinkTracker.d.ts +17 -0
  25. package/lib/core/deepLinkTracker.d.ts.map +1 -0
  26. package/lib/core/deepLinkTracker.js +81 -0
  27. package/lib/core/deepLinkTracker.js.map +1 -0
  28. package/lib/core/deviceInfo.d.ts +14 -0
  29. package/lib/core/deviceInfo.d.ts.map +1 -0
  30. package/lib/core/deviceInfo.js +166 -0
  31. package/lib/core/deviceInfo.js.map +1 -0
  32. package/lib/core/eventQueue.d.ts +23 -0
  33. package/lib/core/eventQueue.d.ts.map +1 -0
  34. package/lib/core/eventQueue.js +240 -0
  35. package/lib/core/eventQueue.js.map +1 -0
  36. package/lib/core/lifecycle.d.ts +18 -0
  37. package/lib/core/lifecycle.d.ts.map +1 -0
  38. package/lib/core/lifecycle.js +127 -0
  39. package/lib/core/lifecycle.js.map +1 -0
  40. package/lib/core/mobileRecorder.d.ts +15 -0
  41. package/lib/core/mobileRecorder.d.ts.map +1 -0
  42. package/lib/core/mobileRecorder.js +231 -0
  43. package/lib/core/mobileRecorder.js.map +1 -0
  44. package/lib/core/network.d.ts +10 -0
  45. package/lib/core/network.d.ts.map +1 -0
  46. package/lib/core/network.js +74 -0
  47. package/lib/core/network.js.map +1 -0
  48. package/lib/core/networkCapture.d.ts +22 -0
  49. package/lib/core/networkCapture.d.ts.map +1 -0
  50. package/lib/core/networkCapture.js +100 -0
  51. package/lib/core/networkCapture.js.map +1 -0
  52. package/lib/core/scrollCapture.d.ts +48 -0
  53. package/lib/core/scrollCapture.d.ts.map +1 -0
  54. package/lib/core/scrollCapture.js +221 -0
  55. package/lib/core/scrollCapture.js.map +1 -0
  56. package/lib/core/session.d.ts +15 -0
  57. package/lib/core/session.d.ts.map +1 -0
  58. package/lib/core/session.js +157 -0
  59. package/lib/core/session.js.map +1 -0
  60. package/lib/core/storage.d.ts +11 -0
  61. package/lib/core/storage.d.ts.map +1 -0
  62. package/lib/core/storage.js +59 -0
  63. package/lib/core/storage.js.map +1 -0
  64. package/lib/core/triggerEngine.d.ts +56 -0
  65. package/lib/core/triggerEngine.d.ts.map +1 -0
  66. package/lib/core/triggerEngine.js +432 -0
  67. package/lib/core/triggerEngine.js.map +1 -0
  68. package/lib/index.d.ts +7 -0
  69. package/lib/index.d.ts.map +1 -0
  70. package/lib/index.js +11 -0
  71. package/lib/index.js.map +1 -0
  72. package/lib/instrumented/Pressable.d.ts +9 -0
  73. package/lib/instrumented/Pressable.d.ts.map +1 -0
  74. package/lib/instrumented/Pressable.js +96 -0
  75. package/lib/instrumented/Pressable.js.map +1 -0
  76. package/lib/instrumented/ScrollView.d.ts +6 -0
  77. package/lib/instrumented/ScrollView.d.ts.map +1 -0
  78. package/lib/instrumented/ScrollView.js +101 -0
  79. package/lib/instrumented/ScrollView.js.map +1 -0
  80. package/lib/instrumented/TextInput.d.ts +9 -0
  81. package/lib/instrumented/TextInput.d.ts.map +1 -0
  82. package/lib/instrumented/TextInput.js +75 -0
  83. package/lib/instrumented/TextInput.js.map +1 -0
  84. package/lib/instrumented/TouchableOpacity.d.ts +11 -0
  85. package/lib/instrumented/TouchableOpacity.d.ts.map +1 -0
  86. package/lib/instrumented/TouchableOpacity.js +96 -0
  87. package/lib/instrumented/TouchableOpacity.js.map +1 -0
  88. package/lib/instrumented/index.d.ts +19 -0
  89. package/lib/instrumented/index.d.ts.map +1 -0
  90. package/lib/instrumented/index.js +28 -0
  91. package/lib/instrumented/index.js.map +1 -0
  92. package/lib/instrumented/interactionObserver.d.ts +29 -0
  93. package/lib/instrumented/interactionObserver.d.ts.map +1 -0
  94. package/lib/instrumented/interactionObserver.js +38 -0
  95. package/lib/instrumented/interactionObserver.js.map +1 -0
  96. package/lib/setup/AccessibilityScanner.d.ts +32 -0
  97. package/lib/setup/AccessibilityScanner.d.ts.map +1 -0
  98. package/lib/setup/AccessibilityScanner.js +127 -0
  99. package/lib/setup/AccessibilityScanner.js.map +1 -0
  100. package/lib/setup/ElementIdentifier.d.ts +65 -0
  101. package/lib/setup/ElementIdentifier.d.ts.map +1 -0
  102. package/lib/setup/ElementIdentifier.js +114 -0
  103. package/lib/setup/ElementIdentifier.js.map +1 -0
  104. package/lib/setup/ElementRegistry.d.ts +22 -0
  105. package/lib/setup/ElementRegistry.d.ts.map +1 -0
  106. package/lib/setup/ElementRegistry.js +47 -0
  107. package/lib/setup/ElementRegistry.js.map +1 -0
  108. package/lib/setup/SetupCodeEntry.d.ts +15 -0
  109. package/lib/setup/SetupCodeEntry.d.ts.map +1 -0
  110. package/lib/setup/SetupCodeEntry.js +198 -0
  111. package/lib/setup/SetupCodeEntry.js.map +1 -0
  112. package/lib/setup/SetupController.d.ts +29 -0
  113. package/lib/setup/SetupController.d.ts.map +1 -0
  114. package/lib/setup/SetupController.js +189 -0
  115. package/lib/setup/SetupController.js.map +1 -0
  116. package/lib/setup/SetupOverlay.d.ts +10 -0
  117. package/lib/setup/SetupOverlay.d.ts.map +1 -0
  118. package/lib/setup/SetupOverlay.js +408 -0
  119. package/lib/setup/SetupOverlay.js.map +1 -0
  120. package/lib/setup/TapInterceptor.d.ts +19 -0
  121. package/lib/setup/TapInterceptor.d.ts.map +1 -0
  122. package/lib/setup/TapInterceptor.js +98 -0
  123. package/lib/setup/TapInterceptor.js.map +1 -0
  124. package/lib/setup/TouchObserver.d.ts +25 -0
  125. package/lib/setup/TouchObserver.d.ts.map +1 -0
  126. package/lib/setup/TouchObserver.js +88 -0
  127. package/lib/setup/TouchObserver.js.map +1 -0
  128. package/lib/setup/TouchPatcher.d.ts +27 -0
  129. package/lib/setup/TouchPatcher.d.ts.map +1 -0
  130. package/lib/setup/TouchPatcher.js +182 -0
  131. package/lib/setup/TouchPatcher.js.map +1 -0
  132. package/lib/setup/index.d.ts +13 -0
  133. package/lib/setup/index.d.ts.map +1 -0
  134. package/lib/setup/index.js +45 -0
  135. package/lib/setup/index.js.map +1 -0
  136. package/lib/setup/useCXPElement.d.ts +25 -0
  137. package/lib/setup/useCXPElement.d.ts.map +1 -0
  138. package/lib/setup/useCXPElement.js +33 -0
  139. package/lib/setup/useCXPElement.js.map +1 -0
  140. package/lib/survey/SurveyModal.d.ts +10 -0
  141. package/lib/survey/SurveyModal.d.ts.map +1 -0
  142. package/lib/survey/SurveyModal.js +1650 -0
  143. package/lib/survey/SurveyModal.js.map +1 -0
  144. package/lib/survey/expressionEval.d.ts +10 -0
  145. package/lib/survey/expressionEval.d.ts.map +1 -0
  146. package/lib/survey/expressionEval.js +287 -0
  147. package/lib/survey/expressionEval.js.map +1 -0
  148. package/lib/survey/frequencyCap.d.ts +15 -0
  149. package/lib/survey/frequencyCap.d.ts.map +1 -0
  150. package/lib/survey/frequencyCap.js +116 -0
  151. package/lib/survey/frequencyCap.js.map +1 -0
  152. package/lib/survey/handsFreeVoice.d.ts +30 -0
  153. package/lib/survey/handsFreeVoice.d.ts.map +1 -0
  154. package/lib/survey/handsFreeVoice.js +312 -0
  155. package/lib/survey/handsFreeVoice.js.map +1 -0
  156. package/lib/survey/interpolate.d.ts +6 -0
  157. package/lib/survey/interpolate.d.ts.map +1 -0
  158. package/lib/survey/interpolate.js +61 -0
  159. package/lib/survey/interpolate.js.map +1 -0
  160. package/lib/survey/pagesFromV1.d.ts +6 -0
  161. package/lib/survey/pagesFromV1.d.ts.map +1 -0
  162. package/lib/survey/pagesFromV1.js +83 -0
  163. package/lib/survey/pagesFromV1.js.map +1 -0
  164. package/lib/survey/questions/CSATQuestion.d.ts +16 -0
  165. package/lib/survey/questions/CSATQuestion.d.ts.map +1 -0
  166. package/lib/survey/questions/CSATQuestion.js +37 -0
  167. package/lib/survey/questions/CSATQuestion.js.map +1 -0
  168. package/lib/survey/questions/DateQuestion.d.ts +20 -0
  169. package/lib/survey/questions/DateQuestion.d.ts.map +1 -0
  170. package/lib/survey/questions/DateQuestion.js +103 -0
  171. package/lib/survey/questions/DateQuestion.js.map +1 -0
  172. package/lib/survey/questions/ImagePickerQuestion.d.ts +33 -0
  173. package/lib/survey/questions/ImagePickerQuestion.d.ts.map +1 -0
  174. package/lib/survey/questions/ImagePickerQuestion.js +68 -0
  175. package/lib/survey/questions/ImagePickerQuestion.js.map +1 -0
  176. package/lib/survey/questions/ImageQuestion.d.ts +26 -0
  177. package/lib/survey/questions/ImageQuestion.d.ts.map +1 -0
  178. package/lib/survey/questions/ImageQuestion.js +24 -0
  179. package/lib/survey/questions/ImageQuestion.js.map +1 -0
  180. package/lib/survey/questions/MatrixCell.d.ts +45 -0
  181. package/lib/survey/questions/MatrixCell.d.ts.map +1 -0
  182. package/lib/survey/questions/MatrixCell.js +54 -0
  183. package/lib/survey/questions/MatrixCell.js.map +1 -0
  184. package/lib/survey/questions/MatrixDropdownQuestion.d.ts +29 -0
  185. package/lib/survey/questions/MatrixDropdownQuestion.d.ts.map +1 -0
  186. package/lib/survey/questions/MatrixDropdownQuestion.js +42 -0
  187. package/lib/survey/questions/MatrixDropdownQuestion.js.map +1 -0
  188. package/lib/survey/questions/MatrixDynamicQuestion.d.ts +26 -0
  189. package/lib/survey/questions/MatrixDynamicQuestion.d.ts.map +1 -0
  190. package/lib/survey/questions/MatrixDynamicQuestion.js +52 -0
  191. package/lib/survey/questions/MatrixDynamicQuestion.js.map +1 -0
  192. package/lib/survey/questions/MatrixQuestion.d.ts +38 -0
  193. package/lib/survey/questions/MatrixQuestion.d.ts.map +1 -0
  194. package/lib/survey/questions/MatrixQuestion.js +64 -0
  195. package/lib/survey/questions/MatrixQuestion.js.map +1 -0
  196. package/lib/survey/questions/MultiTextQuestion.d.ts +19 -0
  197. package/lib/survey/questions/MultiTextQuestion.d.ts.map +1 -0
  198. package/lib/survey/questions/MultiTextQuestion.js +64 -0
  199. package/lib/survey/questions/MultiTextQuestion.js.map +1 -0
  200. package/lib/survey/questions/MultipleChoiceQuestion.d.ts +25 -0
  201. package/lib/survey/questions/MultipleChoiceQuestion.d.ts.map +1 -0
  202. package/lib/survey/questions/MultipleChoiceQuestion.js +111 -0
  203. package/lib/survey/questions/MultipleChoiceQuestion.js.map +1 -0
  204. package/lib/survey/questions/NPSQuestion.d.ts +18 -0
  205. package/lib/survey/questions/NPSQuestion.d.ts.map +1 -0
  206. package/lib/survey/questions/NPSQuestion.js +62 -0
  207. package/lib/survey/questions/NPSQuestion.js.map +1 -0
  208. package/lib/survey/questions/PanelDynamicQuestion.d.ts +50 -0
  209. package/lib/survey/questions/PanelDynamicQuestion.d.ts.map +1 -0
  210. package/lib/survey/questions/PanelDynamicQuestion.js +62 -0
  211. package/lib/survey/questions/PanelDynamicQuestion.js.map +1 -0
  212. package/lib/survey/questions/RankingQuestion.d.ts +34 -0
  213. package/lib/survey/questions/RankingQuestion.d.ts.map +1 -0
  214. package/lib/survey/questions/RankingQuestion.js +85 -0
  215. package/lib/survey/questions/RankingQuestion.js.map +1 -0
  216. package/lib/survey/questions/RatingQuestion.d.ts +20 -0
  217. package/lib/survey/questions/RatingQuestion.d.ts.map +1 -0
  218. package/lib/survey/questions/RatingQuestion.js +53 -0
  219. package/lib/survey/questions/RatingQuestion.js.map +1 -0
  220. package/lib/survey/questions/TextQuestion.d.ts +17 -0
  221. package/lib/survey/questions/TextQuestion.d.ts.map +1 -0
  222. package/lib/survey/questions/TextQuestion.js +46 -0
  223. package/lib/survey/questions/TextQuestion.js.map +1 -0
  224. package/lib/survey/styleContract.d.ts +230 -0
  225. package/lib/survey/styleContract.d.ts.map +1 -0
  226. package/lib/survey/styleContract.js +365 -0
  227. package/lib/survey/styleContract.js.map +1 -0
  228. package/lib/survey/themePalette.d.ts +56 -0
  229. package/lib/survey/themePalette.d.ts.map +1 -0
  230. package/lib/survey/themePalette.js +63 -0
  231. package/lib/survey/themePalette.js.map +1 -0
  232. package/lib/survey/translationLookup.d.ts +4 -0
  233. package/lib/survey/translationLookup.d.ts.map +1 -0
  234. package/lib/survey/translationLookup.js +62 -0
  235. package/lib/survey/translationLookup.js.map +1 -0
  236. package/lib/survey/validate.d.ts +3 -0
  237. package/lib/survey/validate.d.ts.map +1 -0
  238. package/lib/survey/validate.js +159 -0
  239. package/lib/survey/validate.js.map +1 -0
  240. package/lib/survey/variablesResolver.d.ts +10 -0
  241. package/lib/survey/variablesResolver.d.ts.map +1 -0
  242. package/lib/survey/variablesResolver.js +107 -0
  243. package/lib/survey/variablesResolver.js.map +1 -0
  244. package/lib/survey/voiceParsers.d.ts +47 -0
  245. package/lib/survey/voiceParsers.d.ts.map +1 -0
  246. package/lib/survey/voiceParsers.js +310 -0
  247. package/lib/survey/voiceParsers.js.map +1 -0
  248. package/lib/types.d.ts +349 -0
  249. package/lib/types.d.ts.map +1 -0
  250. package/lib/types.js +20 -0
  251. package/lib/types.js.map +1 -0
  252. package/metro.js +55 -0
  253. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CXPinsight
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # @cxpinsight/react-native
2
+
3
+ Engagement tracking, native survey modals, session replay and visual setup mode for React Native and Expo apps.
4
+
5
+ Install once. New surveys, triggers and capture settings ship from the CXPinsight dashboard — no app release required.
6
+
7
+ ```sh
8
+ npm install @cxpinsight/react-native
9
+ npx expo install react-native-view-shot # optional — screenshots in the replay
10
+ ```
11
+
12
+ ## Quick start
13
+
14
+ ### 1. Auto-instrument taps, inputs and scroll
15
+
16
+ Add the Babel plugin so taps, text input and scroll are captured without touching your screens.
17
+
18
+ ```js
19
+ // babel.config.js
20
+ module.exports = function (api) {
21
+ api.cache(true);
22
+ return {
23
+ presets: ['babel-preset-expo'],
24
+ plugins: ['@cxpinsight/react-native/babel'],
25
+ };
26
+ };
27
+ ```
28
+
29
+ The plugin rewrites `TouchableOpacity`, `Pressable`, `TextInput` and `ScrollView` imports in **your** source only — never inside `node_modules`, and never inside the SDK itself.
30
+
31
+ ### 2. Initialise at startup
32
+
33
+ ```js
34
+ import { CXPinsight } from '@cxpinsight/react-native';
35
+ import { captureScreen } from 'react-native-view-shot';
36
+
37
+ CXPinsight.init({
38
+ applicationId: 'YOUR_APPLICATION_ID',
39
+ apiKey: 'YOUR_API_KEY',
40
+ apiBase: 'https://your-gateway.example.com',
41
+
42
+ record: true, // session replay: screens, taps, scroll, inputs
43
+ recordMaskInputs: true, // never store typed text
44
+ captureScreen: () => // optional screenshots in the replay timeline
45
+ captureScreen({ format: 'jpg', quality: 0.3, result: 'base64' }),
46
+ });
47
+ ```
48
+
49
+ On a physical device `apiBase` must be reachable from the device — use your machine's LAN IP, not `localhost`. The SDK checks this at startup and logs a specific message if it looks wrong.
50
+
51
+ ### 3. Report screen changes
52
+
53
+ ```jsx
54
+ import { useRef } from 'react';
55
+ import { CXPinsightProvider, CXPinsight } from '@cxpinsight/react-native';
56
+
57
+ const navigationRef = useRef(null);
58
+
59
+ <CXPinsightProvider navigationRef={navigationRef}>
60
+ <NavigationContainer
61
+ ref={navigationRef}
62
+ onStateChange={() => {
63
+ const name = navigationRef.current?.getCurrentRoute()?.name;
64
+ if (name) CXPinsight.trackScreen(name);
65
+ }}
66
+ >
67
+ {/* your navigators */}
68
+ </NavigationContainer>
69
+ </CXPinsightProvider>
70
+ ```
71
+
72
+ `CXPinsightProvider` also hosts the survey modal and setup overlay, so it must wrap the app for surveys to appear.
73
+
74
+ ### 4. Identify the user after sign-in
75
+
76
+ ```js
77
+ CXPinsight.identify({ id: user.id, email: user.email, name: user.name });
78
+ ```
79
+
80
+ Events recorded before `identify()` are re-attributed to the user automatically, so one visitor does not show up as two.
81
+
82
+ ## API
83
+
84
+ | Method | Purpose |
85
+ | --- | --- |
86
+ | `init(config, callbacks?)` | Start the SDK. Call once at startup. |
87
+ | `identify(user)` | Attach a real user identity; re-attributes prior anonymous activity. |
88
+ | `track(name, data?)` | Record a custom event. |
89
+ | `trackScreen(name, data?)` | Record a screen view. |
90
+ | `trackFunnelStep(...)` / `trackExperiment(...)` / `trackConversion(...)` | Typed helpers over `track`. |
91
+ | `showSurvey(surveyId)` | Present a survey immediately. |
92
+ | `startRecording()` / `stopRecording()` | Session replay, for hosts that gate on their own consent UI. |
93
+ | `enterSetupMode()` / `exitSetupMode()` | Visual element mapping — tap an element to make it trackable. |
94
+ | `flush()` | Force-send queued events. |
95
+ | `reset()` | Clear the stored identity, session and frequency caps. |
96
+
97
+ ## Configuration
98
+
99
+ | Option | Default | |
100
+ | --- | --- | --- |
101
+ | `applicationId` | — | **Required.** |
102
+ | `apiKey` | — | **Required.** |
103
+ | `apiBase` | — | Your CXPinsight gateway URL. |
104
+ | `record` | dashboard | Session replay. Omit to follow the dashboard toggle. |
105
+ | `recordMaskInputs` | `true` | Never persist typed text. |
106
+ | `captureScreen` | — | Screenshot provider; omit for a timeline-only replay. |
107
+ | `captureNetwork` | `true` | Sanitised `api_call` events — method, host, path, status. Never bodies or headers. |
108
+ | `sessionTimeout` | 30 min | Inactivity before a new session starts. |
109
+ | `flushInterval` / `flushThreshold` | 30 s / 10 | Event batching. |
110
+ | `theme` | OS | `'light'` / `'dark'` if your app has its own toggle. |
111
+ | `brandingPalette` | — | Your app's colours, so surveys can match them. |
112
+ | `debug` | `false` | Verbose logging. |
113
+
114
+ Values omitted here are filled from the application's dashboard settings at startup, so capture behaviour can change without an app release.
115
+
116
+ ## Privacy
117
+
118
+ - Typed text is never stored in replays when `recordMaskInputs` is on (the default).
119
+ - Network capture records method, host, path, status and duration only. Query strings are stripped; request and response bodies and headers are never read.
120
+ - The SDK's own backend calls are excluded from network capture.
121
+ - Events are queued locally and persist across launches, so nothing is lost offline.
122
+
123
+ ## Requirements
124
+
125
+ - React Native 0.72+ or Expo SDK 49+
126
+ - `@react-native-async-storage/async-storage` (required peer dependency)
127
+ - Optional: `@react-native-community/datetimepicker` for date questions, `expo-speech` and `expo-speech-recognition` for voice surveys, `react-native-view-shot` for replay screenshots, `expo-constants` and `expo-localization` for richer device metadata
128
+
129
+ ## License
130
+
131
+ MIT
package/babel.js ADDED
@@ -0,0 +1,101 @@
1
+ /**
2
+ * CXP Babel Plugin — automatically replaces React Native touch component
3
+ * imports with CXP's instrumented versions at build time.
4
+ *
5
+ * Usage in babel.config.js:
6
+ *
7
+ * module.exports = function(api) {
8
+ * api.cache(true);
9
+ * return {
10
+ * presets: ['babel-preset-expo'],
11
+ * plugins: ['@cxpinsight/react-native/babel'],
12
+ * };
13
+ * };
14
+ *
15
+ * This transforms:
16
+ * import { TouchableOpacity, Pressable, TextInput } from 'react-native';
17
+ *
18
+ * Into:
19
+ * import { TouchableOpacity } from '@cxpinsight/react-native/instrumented/TouchableOpacity';
20
+ *
21
+ * That path is a re-export of the package's own build output (see
22
+ * scripts/make-shims.js), so the instrumented components an app loads are the
23
+ * SAME module instance the SDK subscribes to. Pointing it anywhere else — src/,
24
+ * or a second module format — gives the app one copy and the SDK another, and
25
+ * taps are then delivered to a listener list nobody is subscribed to.
26
+ * import { Pressable } from '@cxpinsight/react-native/instrumented/Pressable';
27
+ * import { TextInput } from '@cxpinsight/react-native/instrumented/TextInput';
28
+ * // (other imports from 'react-native' are left untouched)
29
+ */
30
+
31
+ const INSTRUMENTED_COMPONENTS = {
32
+ TouchableOpacity: '@cxpinsight/react-native/instrumented/TouchableOpacity',
33
+ Pressable: '@cxpinsight/react-native/instrumented/Pressable',
34
+ TextInput: '@cxpinsight/react-native/instrumented/TextInput',
35
+ ScrollView: '@cxpinsight/react-native/instrumented/ScrollView',
36
+ };
37
+
38
+ module.exports = function cxpInsightBabelPlugin({ types: t }) {
39
+ return {
40
+ name: 'cxpinsight-auto-instrument',
41
+ visitor: {
42
+ ImportDeclaration(path, state) {
43
+ if (path.node.source.value !== 'react-native') return;
44
+
45
+ // CRITICAL: Only instrument the app's own source. Never rewrite files inside
46
+ // node_modules — rewriting react-native's own internals (e.g. VirtualizedList,
47
+ // which imports ScrollView from 'react-native') creates a circular dependency
48
+ // that leaves react-native's contexts half-initialized ("Cannot read property
49
+ // 'Consumer' of undefined"). Also skip the SDK itself, whose instrumented
50
+ // components must import from the real 'react-native'.
51
+ const filename = state.filename || state.file?.opts?.filename || '';
52
+ if (
53
+ filename.includes('/node_modules/') ||
54
+ filename.includes('cxpinsight-react-native') ||
55
+ filename.includes('@cxpinsight/react-native') ||
56
+ filename.includes('cxpinsight/react-native')
57
+ ) {
58
+ return;
59
+ }
60
+
61
+ const specifiersToRedirect = [];
62
+ const specifiersToKeep = [];
63
+
64
+ for (const specifier of path.node.specifiers) {
65
+ if (
66
+ t.isImportSpecifier(specifier) &&
67
+ t.isIdentifier(specifier.imported) &&
68
+ INSTRUMENTED_COMPONENTS[specifier.imported.name]
69
+ ) {
70
+ specifiersToRedirect.push(specifier);
71
+ } else {
72
+ specifiersToKeep.push(specifier);
73
+ }
74
+ }
75
+
76
+ if (specifiersToRedirect.length === 0) return;
77
+
78
+ // Create new import declarations for instrumented components
79
+ const newImports = specifiersToRedirect.map((specifier) => {
80
+ const componentName = specifier.imported.name;
81
+ const source = INSTRUMENTED_COMPONENTS[componentName];
82
+ return t.importDeclaration(
83
+ [t.importSpecifier(specifier.local, t.identifier(componentName))],
84
+ t.stringLiteral(source),
85
+ );
86
+ });
87
+
88
+ if (specifiersToKeep.length > 0) {
89
+ // Replace original with remaining specifiers + add new imports
90
+ path.node.specifiers = specifiersToKeep;
91
+ for (const imp of newImports) {
92
+ path.insertAfter(imp);
93
+ }
94
+ } else {
95
+ // All specifiers were redirected — replace entire import
96
+ path.replaceWithMultiple(newImports);
97
+ }
98
+ },
99
+ },
100
+ };
101
+ };
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ export * from '../lib/instrumented/Pressable';
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ module.exports = require('../lib/instrumented/Pressable');
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ export * from '../lib/instrumented/ScrollView';
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ module.exports = require('../lib/instrumented/ScrollView');
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ export * from '../lib/instrumented/TextInput';
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ module.exports = require('../lib/instrumented/TextInput');
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ export * from '../lib/instrumented/TouchableOpacity';
@@ -0,0 +1,2 @@
1
+ // Generated by scripts/make-shims.js — do not edit.
2
+ module.exports = require('../lib/instrumented/TouchableOpacity');
@@ -0,0 +1,113 @@
1
+ import type { CXPinsightConfig, CXPinsightCallbacks, UserIdentity, FunnelStepOptions, ExperimentOptions, ConversionOptions } from './types';
2
+ type SurveyPresenter = (surveyId: string) => void;
3
+ type SetupPresenter = (show: boolean) => void;
4
+ declare class CXPinsightSDK {
5
+ private initialized;
6
+ private config;
7
+ private callbacks;
8
+ private userId;
9
+ private userIdentity;
10
+ private surveyPresenter;
11
+ private setupPresenter;
12
+ private autoEventUnsub;
13
+ private currentScreen;
14
+ private previousScreen;
15
+ private engagementStartTs;
16
+ private engagementAccumMs;
17
+ private engagementActive;
18
+ private startEngagementClock;
19
+ private pauseEngagementClock;
20
+ private resumeEngagementClock;
21
+ private getEngagementMs;
22
+ private static errorHandlerInstalled;
23
+ /** Initialize the SDK. Call once at app startup. */
24
+ init(config: CXPinsightConfig, callbacks?: CXPinsightCallbacks): Promise<void>;
25
+ /**
26
+ * P1 — merge the server's canonical SdkConfig into `config`, filling only the
27
+ * flat init() fields the app left undefined (client always wins). Bounded to a
28
+ * short timeout so a slow network never stalls init; any failure is swallowed
29
+ * and the app's config/defaults stand. Runs before the capture/session/queue
30
+ * consumers in init().
31
+ */
32
+ private applyServerSdkConfig;
33
+ /** Roll the recording + engagement clock onto a freshly-started session. */
34
+ private onSessionRollover;
35
+ /** Wire native signals → typed analytics events (shared taxonomy). */
36
+ private startAutoEvents;
37
+ /** Track a custom event */
38
+ /**
39
+ * One-shot reachability check of `apiBase` at init. Logs a precise, actionable
40
+ * warning for the common misconfigurations (frontend port, a service instead of the
41
+ * gateway, or localhost on a physical device). Never throws or blocks init.
42
+ */
43
+ private verifyConnectivity;
44
+ track(eventName: string, data?: Record<string, unknown>, eventType?: string, teeToRecording?: boolean): void;
45
+ /** Track a screen view (triggers remote page_view rules) */
46
+ trackScreen(screenName: string, data?: Record<string, unknown>): void;
47
+ /** Identify the current user */
48
+ identify(user: UserIdentity): Promise<void>;
49
+ /** Track a funnel step */
50
+ trackFunnelStep(funnelId: string, stepNumber: number, stepName?: string, options?: FunnelStepOptions): void;
51
+ /** Track an experiment impression */
52
+ trackExperiment(experimentId: string, variantId: string, options?: ExperimentOptions): void;
53
+ /** Track a conversion event */
54
+ trackConversion(eventName: string, options?: ConversionOptions): void;
55
+ /** Enter setup mode. Shows the setup code entry UI. */
56
+ enterSetupMode(): void;
57
+ /** Exit setup mode and clean up. */
58
+ exitSetupMode(): Promise<void>;
59
+ /** Check if setup mode is currently active. */
60
+ isInSetupMode(): boolean;
61
+ /** Get the current setup session state. */
62
+ getSetupState(): import("./setup/SetupController").SetupSessionState | null;
63
+ /** Get the stable device ID (generates one if first time). */
64
+ getDeviceId(): Promise<string>;
65
+ /** Programmatically show a survey */
66
+ showSurvey(surveyId: string): void;
67
+ /**
68
+ * Start mobile session (timeline) recording. Use this when gating on your own
69
+ * consent UI: show your banner, then call after the user accepts. No-op if
70
+ * already recording or the SDK isn't initialized.
71
+ */
72
+ startRecording(): Promise<void>;
73
+ /** Stop mobile session recording and flush the final chunk. */
74
+ stopRecording(): Promise<void>;
75
+ /** Reset all SDK state (call on logout) */
76
+ reset(): Promise<void>;
77
+ /** Manual flush for testing */
78
+ flush(): Promise<void>;
79
+ /** @internal Register the survey presenter from CXPinsightProvider */
80
+ _registerSurveyPresenter(presenter: SurveyPresenter): void;
81
+ /** @internal Unregister the survey presenter */
82
+ _unregisterSurveyPresenter(): void;
83
+ /** @internal Register the setup presenter from CXPinsightProvider */
84
+ _registerSetupPresenter(presenter: SetupPresenter): void;
85
+ /** @internal Unregister the setup presenter */
86
+ _unregisterSetupPresenter(): void;
87
+ /** @internal Get callbacks */
88
+ _getCallbacks(): CXPinsightCallbacks;
89
+ /** @internal Get userId */
90
+ _getUserId(): string;
91
+ /** @internal Get the full identity blob (or null if identify() was
92
+ * never called). Consumed by the variables resolver so
93
+ * {source: 'sdk'} v1.1 variables interpolate to identify()-supplied
94
+ * values. Return type kept broad ({[k]:unknown}) because the caller
95
+ * looks up variable-name keys against it, not typed properties. */
96
+ _getUserIdentity(): Record<string, unknown> | null;
97
+ /** @internal Get config */
98
+ _getConfig(): CXPinsightConfig | null;
99
+ /** @internal Host-supplied palette override from CXPinsight.init({ brandingPalette }).
100
+ * Read by SurveyModal to layer over survey.branding.palette + defaults.
101
+ * Returns null when the app didn't pass one — palette resolver falls back. */
102
+ _getInitBrandingPalette(): {
103
+ light?: Record<string, string>;
104
+ dark?: Record<string, string>;
105
+ } | null;
106
+ /** @internal Check initialization */
107
+ _isInitialized(): boolean;
108
+ private log;
109
+ }
110
+ /** Singleton SDK instance */
111
+ export declare const CXPinsight: CXPinsightSDK;
112
+ export {};
113
+ //# sourceMappingURL=CXPinsight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CXPinsight.d.ts","sourceRoot":"","sources":["../src/CXPinsight.ts"],"names":[],"mappings":"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"}