@snowplow/react-native-tracker 1.4.0 → 2.1.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 (240) hide show
  1. package/.editorconfig +15 -0
  2. package/.eslintignore +6 -0
  3. package/.gitattributes +3 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. package/.github/actions/setup/action.yml +28 -0
  7. package/.github/workflows/build.yml +155 -0
  8. package/.github/workflows/deploy.yml +97 -0
  9. package/.github/workflows/e2e-android.yml +121 -0
  10. package/.github/workflows/e2e-ios.yml +95 -0
  11. package/.github/workflows/snyk.yml +21 -0
  12. package/.gitignore +70 -0
  13. package/.npmignore +60 -0
  14. package/.nvmrc +1 -0
  15. package/.watchmanconfig +1 -0
  16. package/.yarnrc +3 -0
  17. package/CHANGELOG +176 -0
  18. package/CONTRIBUTING.md +80 -0
  19. package/LICENSE +1 -1
  20. package/README.md +24 -111
  21. package/android/build.gradle +93 -37
  22. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  23. package/android/gradle/wrapper/gradle-wrapper.properties +1 -2
  24. package/android/gradle.properties +5 -2
  25. package/android/gradlew +172 -110
  26. package/android/gradlew.bat +24 -19
  27. package/android/src/main/AndroidManifest.xml +1 -3
  28. package/android/src/main/AndroidManifestNew.xml +2 -0
  29. package/android/src/main/java/com/snowplow/reactnativetracker/ReactNativeTrackerModule.kt +744 -0
  30. package/android/src/main/java/com/snowplow/reactnativetracker/ReactNativeTrackerPackage.kt +17 -0
  31. package/android/src/main/java/com/snowplow/reactnativetracker/util/ConfigUtil.kt +274 -0
  32. package/android/src/main/java/com/snowplow/reactnativetracker/util/EventUtil.kt +233 -0
  33. package/android/src/main/java/com/snowplow/reactnativetracker/util/TrackerVersion.kt +5 -0
  34. package/babel.config.js +3 -0
  35. package/example/.watchmanconfig +1 -0
  36. package/example/Gemfile +6 -0
  37. package/example/android/app/build.gradle +129 -0
  38. package/example/android/app/debug.keystore +0 -0
  39. package/example/android/app/proguard-rules.pro +10 -0
  40. package/example/android/app/src/androidTest/java/com/reactnativetrackerexample/DetoxTest.java +36 -0
  41. package/example/android/app/src/androidTest/java/com/reactnativetrackerexample/DetoxTestAppJUnitRunner.java +21 -0
  42. package/example/android/app/src/debug/AndroidManifest.xml +13 -0
  43. package/example/android/app/src/debug/java/com/reactnativetrackerexample/ReactNativeFlipper.java +75 -0
  44. package/example/android/app/src/main/AndroidManifest.xml +26 -0
  45. package/example/android/app/src/main/java/com/reactnativetrackerexample/MainActivity.java +32 -0
  46. package/example/android/app/src/main/java/com/reactnativetrackerexample/MainApplication.java +62 -0
  47. package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +36 -0
  48. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  49. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  50. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  51. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  52. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  53. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  54. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  55. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  56. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  57. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  58. package/example/android/app/src/main/res/values/strings.xml +3 -0
  59. package/example/android/app/src/main/res/values/styles.xml +9 -0
  60. package/example/android/app/src/release/java/com/reactnativetrackerexample/ReactNativeFlipper.java +20 -0
  61. package/example/android/build.gradle +31 -0
  62. package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  63. package/example/android/gradle/wrapper/gradle-wrapper.properties +6 -0
  64. package/example/android/gradle.properties +44 -0
  65. package/example/android/gradlew +244 -0
  66. package/example/android/gradlew.bat +92 -0
  67. package/example/android/settings.gradle +4 -0
  68. package/example/app.json +4 -0
  69. package/example/babel.config.js +17 -0
  70. package/example/detox.config.js +92 -0
  71. package/example/e2e/config.json +10 -0
  72. package/example/e2e/emitEvents.e2e.detox.js +95 -0
  73. package/example/e2e/environment.js +23 -0
  74. package/example/e2e/helpers/microCommands.js +140 -0
  75. package/example/e2e/helpers/microHelpers.js +333 -0
  76. package/example/e2e/helpers/microHelpers.test.js +295 -0
  77. package/example/e2e/helpers/schemas.js +49 -0
  78. package/example/e2e/jest.config.js +16 -0
  79. package/example/e2e/setup.js +4 -0
  80. package/example/e2e/testEvents.micro.test.js +287 -0
  81. package/example/index.js +5 -0
  82. package/example/ios/.xcode.env +11 -0
  83. package/example/ios/Podfile +62 -0
  84. package/example/ios/Podfile.lock +730 -0
  85. package/example/ios/ReactNativeTrackerExample/AppDelegate.h +6 -0
  86. package/example/ios/ReactNativeTrackerExample/AppDelegate.mm +26 -0
  87. package/example/ios/ReactNativeTrackerExample/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  88. package/example/ios/ReactNativeTrackerExample/Images.xcassets/Contents.json +6 -0
  89. package/example/ios/ReactNativeTrackerExample/Info.plist +55 -0
  90. package/example/ios/ReactNativeTrackerExample/LaunchScreen.storyboard +47 -0
  91. package/example/ios/ReactNativeTrackerExample/main.m +10 -0
  92. package/example/ios/ReactNativeTrackerExample-Bridging-Header.h +3 -0
  93. package/example/ios/ReactNativeTrackerExample.xcodeproj/project.pbxproj +722 -0
  94. package/{ios/RNSnowplowTracker.xcodeproj/xcshareddata/xcschemes/RNSnowplowTracker.xcscheme → example/ios/ReactNativeTrackerExample.xcodeproj/xcshareddata/xcschemes/ReactNativeTrackerExample.xcscheme} +29 -21
  95. package/example/ios/ReactNativeTrackerExample.xcworkspace/contents.xcworkspacedata +10 -0
  96. package/example/ios/ReactNativeTrackerExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  97. package/example/ios/ReactNativeTrackerExampleTests/Info.plist +24 -0
  98. package/example/ios/ReactNativeTrackerExampleTests/ReactNativeTrackerExampleTests.m +66 -0
  99. package/example/metro.config.js +45 -0
  100. package/example/package.json +54 -0
  101. package/example/react-native.config.js +10 -0
  102. package/example/src/App.js +566 -0
  103. package/example/tsconfig.json +5 -0
  104. package/example/yarn.lock +7379 -0
  105. package/ios/ReactNativeTracker-Bridging-Header.h +2 -0
  106. package/ios/ReactNativeTracker.mm +175 -0
  107. package/ios/ReactNativeTracker.swift +822 -0
  108. package/ios/{RNSnowplowTracker.xcodeproj → ReactNativeTracker.xcodeproj}/project.pbxproj +55 -79
  109. package/ios/Util/ConfigUtils.swift +209 -0
  110. package/ios/Util/TrackerVersion.swift +3 -0
  111. package/ios/Util/Utilities.swift +37 -0
  112. package/lefthook.yml +11 -0
  113. package/lib/commonjs/api.js +490 -0
  114. package/lib/commonjs/api.js.map +1 -0
  115. package/lib/commonjs/configurations.js +196 -0
  116. package/lib/commonjs/configurations.js.map +1 -0
  117. package/lib/commonjs/constants.js +77 -0
  118. package/lib/commonjs/constants.js.map +1 -0
  119. package/lib/commonjs/events.js +277 -0
  120. package/lib/commonjs/events.js.map +1 -0
  121. package/lib/commonjs/index.js +132 -0
  122. package/lib/commonjs/index.js.map +1 -0
  123. package/lib/commonjs/jsCore.js +427 -0
  124. package/lib/commonjs/jsCore.js.map +1 -0
  125. package/lib/commonjs/native.js +16 -0
  126. package/lib/commonjs/native.js.map +1 -0
  127. package/lib/commonjs/subject.js +235 -0
  128. package/lib/commonjs/subject.js.map +1 -0
  129. package/lib/commonjs/tracker.js +248 -0
  130. package/lib/commonjs/tracker.js.map +1 -0
  131. package/lib/commonjs/types.js +2 -0
  132. package/lib/commonjs/types.js.map +1 -0
  133. package/lib/commonjs/utils.js +72 -0
  134. package/lib/commonjs/utils.js.map +1 -0
  135. package/lib/commonjs/webViewInterface.js +66 -0
  136. package/lib/commonjs/webViewInterface.js.map +1 -0
  137. package/lib/module/api.js +452 -0
  138. package/lib/module/api.js.map +1 -0
  139. package/lib/module/configurations.js +184 -0
  140. package/lib/module/configurations.js.map +1 -0
  141. package/lib/module/constants.js +72 -0
  142. package/lib/module/constants.js.map +1 -0
  143. package/lib/module/events.js +259 -0
  144. package/lib/module/events.js.map +1 -0
  145. package/lib/module/index.js +120 -0
  146. package/lib/module/index.js.map +1 -0
  147. package/lib/module/jsCore.js +424 -0
  148. package/lib/module/jsCore.js.map +1 -0
  149. package/lib/module/native.js +12 -0
  150. package/lib/module/native.js.map +1 -0
  151. package/lib/module/subject.js +222 -0
  152. package/lib/module/subject.js.map +1 -0
  153. package/lib/module/tracker.js +234 -0
  154. package/lib/module/tracker.js.map +1 -0
  155. package/lib/module/types.js +2 -0
  156. package/lib/module/types.js.map +1 -0
  157. package/lib/module/utils.js +66 -0
  158. package/lib/module/utils.js.map +1 -0
  159. package/lib/module/webViewInterface.js +62 -0
  160. package/lib/module/webViewInterface.js.map +1 -0
  161. package/lib/typescript/__tests__/api.test.d.ts +2 -0
  162. package/lib/typescript/__tests__/api.test.d.ts.map +1 -0
  163. package/lib/typescript/__tests__/configurations.test.d.ts +2 -0
  164. package/lib/typescript/__tests__/configurations.test.d.ts.map +1 -0
  165. package/lib/typescript/__tests__/events.test.d.ts +2 -0
  166. package/lib/typescript/__tests__/events.test.d.ts.map +1 -0
  167. package/lib/typescript/__tests__/index.test.d.ts +2 -0
  168. package/lib/typescript/__tests__/index.test.d.ts.map +1 -0
  169. package/lib/typescript/__tests__/jsCore.test.d.ts +2 -0
  170. package/lib/typescript/__tests__/jsCore.test.d.ts.map +1 -0
  171. package/lib/typescript/__tests__/utils.test.d.ts +2 -0
  172. package/lib/typescript/__tests__/utils.test.d.ts.map +1 -0
  173. package/lib/typescript/api.d.ts +240 -0
  174. package/lib/typescript/api.d.ts.map +1 -0
  175. package/lib/typescript/configurations.d.ts +73 -0
  176. package/lib/typescript/configurations.d.ts.map +1 -0
  177. package/lib/typescript/constants.d.ts +64 -0
  178. package/lib/typescript/constants.d.ts.map +1 -0
  179. package/lib/typescript/events.d.ts +115 -0
  180. package/lib/typescript/events.d.ts.map +1 -0
  181. package/lib/typescript/index.d.ts +27 -0
  182. package/lib/typescript/index.d.ts.map +1 -0
  183. package/lib/typescript/jsCore.d.ts +152 -0
  184. package/lib/typescript/jsCore.d.ts.map +1 -0
  185. package/lib/typescript/native.d.ts +4 -0
  186. package/lib/typescript/native.d.ts.map +1 -0
  187. package/lib/typescript/subject.d.ts +91 -0
  188. package/lib/typescript/subject.d.ts.map +1 -0
  189. package/lib/typescript/tracker.d.ts +111 -0
  190. package/lib/typescript/tracker.d.ts.map +1 -0
  191. package/{dist/index.d.ts → lib/typescript/types.d.ts} +264 -73
  192. package/lib/typescript/types.d.ts.map +1 -0
  193. package/lib/typescript/utils.d.ts +35 -0
  194. package/lib/typescript/utils.d.ts.map +1 -0
  195. package/lib/typescript/webViewInterface.d.ts +15 -0
  196. package/lib/typescript/webViewInterface.d.ts.map +1 -0
  197. package/package.json +135 -53
  198. package/scripts/bootstrap.js +29 -0
  199. package/snowplow-react-native-tracker.podspec +42 -0
  200. package/src/__mocks__/react-native.js +7 -0
  201. package/src/__tests__/api.test.ts +21 -0
  202. package/src/__tests__/configurations.test.ts +608 -0
  203. package/src/__tests__/events.test.ts +736 -0
  204. package/src/__tests__/index.test.ts +14 -0
  205. package/src/__tests__/jsCore.test.ts +199 -0
  206. package/src/__tests__/utils.test.ts +10 -0
  207. package/src/api.ts +556 -0
  208. package/src/configurations.ts +325 -0
  209. package/src/constants.ts +97 -0
  210. package/src/events.ts +355 -0
  211. package/src/index.ts +184 -0
  212. package/src/jsCore.ts +603 -0
  213. package/src/native.ts +21 -0
  214. package/src/subject.ts +302 -0
  215. package/src/tracker.ts +377 -0
  216. package/src/types.ts +1162 -0
  217. package/src/utils.ts +65 -0
  218. package/src/webViewInterface.ts +92 -0
  219. package/tsconfig.build.json +5 -0
  220. package/tsconfig.json +28 -0
  221. package/turbo.json +34 -0
  222. package/yarn.lock +9333 -0
  223. package/RNSnowplowTracker.podspec +0 -24
  224. package/android/src/main/java/com/snowplowanalytics/react/tracker/RNSnowplowTrackerModule.java +0 -750
  225. package/android/src/main/java/com/snowplowanalytics/react/tracker/RNSnowplowTrackerPackage.java +0 -29
  226. package/android/src/main/java/com/snowplowanalytics/react/util/ConfigUtil.java +0 -351
  227. package/android/src/main/java/com/snowplowanalytics/react/util/EventUtil.java +0 -339
  228. package/android/src/main/java/com/snowplowanalytics/react/util/TrackerVersion.java +0 -7
  229. package/dist/index.js +0 -2026
  230. package/dist/index.js.map +0 -1
  231. package/ios/RNSnowplowTracker.h +0 -34
  232. package/ios/RNSnowplowTracker.m +0 -911
  233. package/ios/Util/NSDictionary+RNSP_TypeMethods.h +0 -33
  234. package/ios/Util/NSDictionary+RNSP_TypeMethods.m +0 -40
  235. package/ios/Util/RNConfigUtils.h +0 -44
  236. package/ios/Util/RNConfigUtils.m +0 -209
  237. package/ios/Util/RNTrackerVersion.h +0 -27
  238. package/ios/Util/RNTrackerVersion.m +0 -27
  239. package/ios/Util/RNUtilities.h +0 -32
  240. package/ios/Util/RNUtilities.m +0 -68
package/src/jsCore.ts ADDED
@@ -0,0 +1,603 @@
1
+ 'use strict';
2
+
3
+ import type {
4
+ InitTrackerConfiguration,
5
+ SelfDescribing,
6
+ EventContext,
7
+ StructuredProps,
8
+ ScreenViewProps,
9
+ ScreenSize,
10
+ PageViewProps,
11
+ TimingProps,
12
+ ConsentGrantedProps,
13
+ ConsentWithdrawnProps,
14
+ EcommerceTransactionProps,
15
+ DeepLinkReceivedProps,
16
+ MessageNotificationProps,
17
+ NetworkConfiguration,
18
+ ScrollChangedProps,
19
+ ListItemViewProps,
20
+ } from './types';
21
+
22
+ import {
23
+ type Payload,
24
+ trackerCore,
25
+ type PayloadBuilder,
26
+ buildSelfDescribingEvent,
27
+ buildStructEvent,
28
+ buildPageView,
29
+ buildConsentGranted,
30
+ buildConsentWithdrawn,
31
+ buildEcommerceTransaction,
32
+ buildEcommerceTransactionItem,
33
+ } from '@snowplow/tracker-core';
34
+ import type { TrackerCore } from '@snowplow/tracker-core';
35
+ import { errorHandler } from './utils';
36
+ import { schemas } from './constants';
37
+ import { v4 as uuid } from 'uuid';
38
+
39
+ // Tracker version added to the events
40
+ const trackerVersion = 'rn-2.1.0';
41
+
42
+ interface Tracker extends TrackerCore {
43
+ setDomainUserId: (duid: string | undefined) => void;
44
+ setNetworkUserId: (nuid: string | undefined) => void;
45
+ }
46
+
47
+ let trackers: { [namespace: string]: Tracker } = {};
48
+
49
+ function preparePayload(payload: Payload): Record<string, string> {
50
+ const stringifiedPayload: Record<string, string> = {};
51
+
52
+ payload.stm = new Date().getTime().toString();
53
+
54
+ for (const key in payload) {
55
+ if (Object.prototype.hasOwnProperty.call(payload, key)) {
56
+ stringifiedPayload[key] = String(payload[key]);
57
+ }
58
+ }
59
+ return stringifiedPayload;
60
+ }
61
+
62
+ function createEmitCallback(
63
+ networkConfig: NetworkConfiguration
64
+ ): (e: Payload) => void {
65
+ return (e: Payload) => {
66
+ const postJson = {
67
+ schema: schemas.payloadData,
68
+ data: [preparePayload(e)],
69
+ };
70
+ const endpoint = networkConfig.endpoint;
71
+ const postPath =
72
+ networkConfig.customPostPath ?? '/com.snowplowanalytics.snowplow/tp2';
73
+ const headers = networkConfig.requestHeaders ?? {};
74
+ fetch(endpoint + postPath, {
75
+ method: 'POST',
76
+ body: JSON.stringify(postJson),
77
+ headers: {
78
+ 'Content-Type': 'application/json',
79
+ ...headers,
80
+ },
81
+ }).catch(errorHandler);
82
+ };
83
+ }
84
+
85
+ function updateTrackerProperties(
86
+ tracker: Tracker,
87
+ configuration: InitTrackerConfiguration
88
+ ): void {
89
+ tracker.setPlatform(configuration.trackerConfig?.devicePlatform ?? 'mob');
90
+ tracker.setTrackerVersion(trackerVersion);
91
+ tracker.setTrackerNamespace(configuration.namespace);
92
+ if (configuration.trackerConfig?.appId != null) {
93
+ tracker.setAppId(configuration.trackerConfig.appId);
94
+ }
95
+ if (configuration.subjectConfig?.colorDepth != null) {
96
+ tracker.setColorDepth(String(configuration.subjectConfig.colorDepth));
97
+ }
98
+ if (configuration.subjectConfig?.domainUserId != null) {
99
+ tracker.setDomainUserId(configuration.subjectConfig.domainUserId);
100
+ }
101
+ if (configuration.subjectConfig?.ipAddress != null) {
102
+ tracker.setIpAddress(configuration.subjectConfig.ipAddress);
103
+ }
104
+ if (configuration.subjectConfig?.language != null) {
105
+ tracker.setLang(configuration.subjectConfig.language);
106
+ }
107
+ if (configuration.subjectConfig?.screenResolution != null) {
108
+ tracker.setScreenResolution(
109
+ String(configuration.subjectConfig.screenResolution[0]),
110
+ String(configuration.subjectConfig.screenResolution[1])
111
+ );
112
+ }
113
+ if (configuration.subjectConfig?.screenViewport != null) {
114
+ tracker.setViewport(
115
+ String(configuration.subjectConfig.screenViewport[0]),
116
+ String(configuration.subjectConfig.screenViewport[1])
117
+ );
118
+ }
119
+ if (configuration.subjectConfig?.timezone != null) {
120
+ tracker.setTimezone(configuration.subjectConfig.timezone);
121
+ }
122
+ if (configuration.subjectConfig?.userId != null) {
123
+ tracker.setUserId(configuration.subjectConfig.userId);
124
+ }
125
+ if (configuration.subjectConfig?.useragent != null) {
126
+ tracker.setUseragent(configuration.subjectConfig.useragent);
127
+ }
128
+ }
129
+
130
+ function createTracker(
131
+ configuration: InitTrackerConfiguration,
132
+ emitCallback?: (e: Payload) => void
133
+ ): Promise<void> {
134
+ // create an emit callback if not given
135
+ const emitter =
136
+ emitCallback ?? createEmitCallback(configuration.networkConfig);
137
+
138
+ // the tracker core does not provide an option to set the duid, so we need to add custom
139
+ let domainUserId: string | undefined;
140
+ const setDomainUserId = (userId: string | undefined): void => {
141
+ domainUserId = userId;
142
+ };
143
+ let networkUserId: string | undefined;
144
+ const setNetworkUserId = (userId: string | undefined): void => {
145
+ networkUserId = userId;
146
+ };
147
+
148
+ // initialize the tracker core
149
+ const core = trackerCore({
150
+ base64: configuration.trackerConfig?.base64Encoding ?? true,
151
+ callback: (payload: PayloadBuilder) => {
152
+ if (domainUserId != null) {
153
+ payload.add('duid', domainUserId);
154
+ }
155
+ if (networkUserId != null) {
156
+ payload.add('tnuid', networkUserId);
157
+ }
158
+ const builtPayload = payload.build();
159
+ emitter(builtPayload);
160
+ },
161
+ });
162
+ const tracker = { ...core, setDomainUserId, setNetworkUserId };
163
+ trackers[configuration.namespace] = tracker;
164
+
165
+ // update tracker properties to reflect subject and tracker info
166
+ updateTrackerProperties(tracker, configuration);
167
+
168
+ return <Promise<void>>Promise.resolve();
169
+ }
170
+
171
+ function removeTracker(details: { tracker: string }): Promise<boolean> {
172
+ delete trackers[details.tracker];
173
+ return <Promise<boolean>>Promise.resolve(true);
174
+ }
175
+
176
+ function removeAllTrackers(): Promise<boolean> {
177
+ trackers = {};
178
+ return <Promise<boolean>>Promise.resolve(true);
179
+ }
180
+
181
+ function forTracker(
182
+ namespace: string | null,
183
+ callback: (tracker: Tracker) => void
184
+ ): void {
185
+ const tracker =
186
+ namespace != null ? trackers[namespace] : Object.values(trackers)[0];
187
+
188
+ if (tracker) {
189
+ callback(tracker);
190
+ } else {
191
+ errorHandler(new Error('No such tracker found.'));
192
+ }
193
+ }
194
+
195
+ function trackSelfDescribingEvent(details: {
196
+ tracker: string | null;
197
+ eventData: SelfDescribing;
198
+ contexts: EventContext[];
199
+ }): Promise<void> {
200
+ forTracker(details.tracker, (tracker) => {
201
+ tracker.track(
202
+ buildSelfDescribingEvent({
203
+ event: details.eventData,
204
+ }),
205
+ details.contexts
206
+ );
207
+ });
208
+ return <Promise<void>>Promise.resolve();
209
+ }
210
+
211
+ function trackStructuredEvent(details: {
212
+ tracker: string | null;
213
+ eventData: StructuredProps;
214
+ contexts: EventContext[];
215
+ }): Promise<void> {
216
+ forTracker(details.tracker, (tracker) => {
217
+ tracker.track(buildStructEvent(details.eventData), details.contexts);
218
+ });
219
+ return <Promise<void>>Promise.resolve();
220
+ }
221
+
222
+ function trackScreenViewEvent(details: {
223
+ tracker: string | null;
224
+ eventData: ScreenViewProps;
225
+ contexts: EventContext[];
226
+ }): Promise<void> {
227
+ const data: ScreenViewProps = {
228
+ name: details.eventData.name,
229
+ id: details.eventData.id ?? uuid(),
230
+ };
231
+ if (details.eventData.type != null) {
232
+ data.type = details.eventData.type;
233
+ }
234
+ if (details.eventData.previousName != null) {
235
+ data.previousName = details.eventData.previousName;
236
+ }
237
+ if (details.eventData.previousId != null) {
238
+ data.previousId = details.eventData.previousId;
239
+ }
240
+ if (details.eventData.previousType != null) {
241
+ data.previousType = details.eventData.previousType;
242
+ }
243
+ if (details.eventData.transitionType != null) {
244
+ data.transitionType = details.eventData.transitionType;
245
+ }
246
+
247
+ return trackSelfDescribingEvent({
248
+ tracker: details.tracker,
249
+ eventData: {
250
+ schema: schemas.screenViewSchema,
251
+ data: data,
252
+ },
253
+ contexts: details.contexts,
254
+ });
255
+ }
256
+
257
+ function trackScrollChangedEvent(details: {
258
+ tracker: string | null;
259
+ eventData: ScrollChangedProps;
260
+ contexts: EventContext[];
261
+ }): Promise<void> {
262
+ const data: Record<string, number> = {};
263
+
264
+ if (details.eventData.yOffset != null) {
265
+ data.y_offset = details.eventData.yOffset;
266
+ }
267
+ if (details.eventData.xOffset != null) {
268
+ data.x_offset = details.eventData.xOffset;
269
+ }
270
+ if (details.eventData.viewHeight != null) {
271
+ data.view_height = details.eventData.viewHeight;
272
+ }
273
+ if (details.eventData.viewWidth != null) {
274
+ data.view_width = details.eventData.viewWidth;
275
+ }
276
+ if (details.eventData.contentHeight != null) {
277
+ data.content_height = details.eventData.contentHeight;
278
+ }
279
+ if (details.eventData.contentWidth != null) {
280
+ data.content_width = details.eventData.contentWidth;
281
+ }
282
+
283
+ return trackSelfDescribingEvent({
284
+ tracker: details.tracker,
285
+ eventData: {
286
+ schema: schemas.scrollChangedSchema,
287
+ data: data,
288
+ },
289
+ contexts: details.contexts,
290
+ });
291
+ }
292
+
293
+ function trackListItemViewEvent(details: {
294
+ tracker: string | null;
295
+ eventData: ListItemViewProps;
296
+ contexts: EventContext[];
297
+ }): Promise<void> {
298
+ const data: Record<string, number> = {
299
+ index: details.eventData.index,
300
+ };
301
+
302
+ if (details.eventData.itemsCount != null) {
303
+ data.items_count = details.eventData.itemsCount;
304
+ }
305
+
306
+ return trackSelfDescribingEvent({
307
+ tracker: details.tracker,
308
+ eventData: {
309
+ schema: schemas.listItemViewSchema,
310
+ data: data,
311
+ },
312
+ contexts: details.contexts,
313
+ });
314
+ }
315
+
316
+ function trackPageViewEvent(details: {
317
+ tracker: string | null;
318
+ eventData: PageViewProps;
319
+ contexts: EventContext[];
320
+ }): Promise<void> {
321
+ forTracker(details.tracker, (tracker) => {
322
+ tracker.track(buildPageView(details.eventData), details.contexts);
323
+ });
324
+ return <Promise<void>>Promise.resolve();
325
+ }
326
+
327
+ function trackTimingEvent(details: {
328
+ tracker: string | null;
329
+ eventData: TimingProps;
330
+ contexts: EventContext[];
331
+ }): Promise<void> {
332
+ return trackSelfDescribingEvent({
333
+ tracker: details.tracker,
334
+ eventData: {
335
+ schema: schemas.timingSchema,
336
+ data: details.eventData,
337
+ },
338
+ contexts: details.contexts,
339
+ });
340
+ }
341
+
342
+ function trackConsentGrantedEvent(details: {
343
+ tracker: string | null;
344
+ eventData: ConsentGrantedProps;
345
+ contexts: EventContext[];
346
+ }): Promise<void> {
347
+ forTracker(details.tracker, (tracker) => {
348
+ const built = buildConsentGranted({
349
+ id: details.eventData.documentId,
350
+ version: details.eventData.version,
351
+ name: details.eventData.name,
352
+ description: details.eventData.documentDescription,
353
+ expiry: details.eventData.expiry,
354
+ });
355
+ tracker.track(built.event, details.contexts.concat(built.context));
356
+ });
357
+ return <Promise<void>>Promise.resolve();
358
+ }
359
+
360
+ function trackConsentWithdrawnEvent(details: {
361
+ tracker: string | null;
362
+ eventData: ConsentWithdrawnProps;
363
+ contexts: EventContext[];
364
+ }): Promise<void> {
365
+ forTracker(details.tracker, (tracker) => {
366
+ const built = buildConsentWithdrawn({
367
+ all: details.eventData.all,
368
+ id: details.eventData.documentId,
369
+ version: details.eventData.version,
370
+ name: details.eventData.name,
371
+ description: details.eventData.documentDescription,
372
+ });
373
+ tracker.track(built.event, details.contexts.concat(built.context));
374
+ });
375
+ return <Promise<void>>Promise.resolve();
376
+ }
377
+
378
+ function trackEcommerceTransactionEvent(details: {
379
+ tracker: string | null;
380
+ eventData: EcommerceTransactionProps;
381
+ contexts: EventContext[];
382
+ }): Promise<void> {
383
+ forTracker(details.tracker, (tracker) => {
384
+ details.eventData.items.forEach((item) => {
385
+ tracker.track(
386
+ buildEcommerceTransactionItem({
387
+ ...item,
388
+ orderId: details.eventData.orderId,
389
+ }),
390
+ details.contexts
391
+ );
392
+ });
393
+ tracker.track(
394
+ buildEcommerceTransaction({
395
+ orderId: details.eventData.orderId,
396
+ total: details.eventData.totalValue,
397
+ affiliation: details.eventData.affiliation,
398
+ tax: details.eventData.taxValue,
399
+ shipping: details.eventData.shipping,
400
+ city: details.eventData.city,
401
+ state: details.eventData.state,
402
+ country: details.eventData.country,
403
+ currency: details.eventData.currency,
404
+ }),
405
+ details.contexts
406
+ );
407
+ });
408
+ return <Promise<void>>Promise.resolve();
409
+ }
410
+
411
+ function trackDeepLinkReceivedEvent(details: {
412
+ tracker: string | null;
413
+ eventData: DeepLinkReceivedProps;
414
+ contexts: EventContext[];
415
+ }): Promise<void> {
416
+ return trackSelfDescribingEvent({
417
+ tracker: details.tracker,
418
+ eventData: {
419
+ schema: schemas.deepLinkReceivedSchema,
420
+ data: details.eventData,
421
+ },
422
+ contexts: details.contexts,
423
+ });
424
+ }
425
+
426
+ function trackMessageNotificationEvent(details: {
427
+ tracker: string | null;
428
+ eventData: MessageNotificationProps;
429
+ contexts: EventContext[];
430
+ }): Promise<void> {
431
+ return trackSelfDescribingEvent({
432
+ tracker: details.tracker,
433
+ eventData: {
434
+ schema: schemas.messageNotificationSchema,
435
+ data: details.eventData,
436
+ },
437
+ contexts: details.contexts,
438
+ });
439
+ }
440
+
441
+ function removeGlobalContexts(): Promise<void> {
442
+ return <Promise<void>>Promise.reject(new Error('Not implemented'));
443
+ }
444
+
445
+ function addGlobalContexts(): Promise<void> {
446
+ return <Promise<void>>Promise.reject(new Error('Not implemented'));
447
+ }
448
+
449
+ function setUserId(details: {
450
+ tracker: string;
451
+ userId: string | null;
452
+ }): Promise<void> {
453
+ trackers[details.tracker]?.setUserId(details.userId ?? '');
454
+ return <Promise<void>>Promise.resolve();
455
+ }
456
+
457
+ function setNetworkUserId(details: {
458
+ tracker: string;
459
+ networkUserId: string | null;
460
+ }): Promise<void> {
461
+ trackers[details.tracker]?.setNetworkUserId(details.networkUserId ?? '');
462
+ return <Promise<void>>Promise.resolve();
463
+ }
464
+
465
+ function setDomainUserId(details: {
466
+ tracker: string;
467
+ domainUserId: string | null;
468
+ }): Promise<void> {
469
+ trackers[details.tracker]?.setDomainUserId(details.domainUserId ?? '');
470
+ return <Promise<void>>Promise.resolve();
471
+ }
472
+
473
+ function setIpAddress(details: {
474
+ tracker: string;
475
+ ipAddress: string | null;
476
+ }): Promise<void> {
477
+ trackers[details.tracker]?.setIpAddress(details.ipAddress ?? '');
478
+ return <Promise<void>>Promise.resolve();
479
+ }
480
+
481
+ function setUseragent(details: {
482
+ tracker: string;
483
+ useragent: string | null;
484
+ }): Promise<void> {
485
+ trackers[details.tracker]?.setUseragent(details.useragent ?? '');
486
+ return <Promise<void>>Promise.resolve();
487
+ }
488
+
489
+ function setTimezone(details: {
490
+ tracker: string;
491
+ timezone: string | null;
492
+ }): Promise<void> {
493
+ trackers[details.tracker]?.setTimezone(details.timezone ?? '');
494
+ return <Promise<void>>Promise.resolve();
495
+ }
496
+
497
+ function setLanguage(details: {
498
+ tracker: string;
499
+ language: string | null;
500
+ }): Promise<void> {
501
+ trackers[details.tracker]?.setLang(details.language ?? '');
502
+ return <Promise<void>>Promise.resolve();
503
+ }
504
+
505
+ function setScreenResolution(details: {
506
+ tracker: string;
507
+ screenResolution: ScreenSize | null;
508
+ }): Promise<void> {
509
+ if (details.screenResolution) {
510
+ trackers[details.tracker]?.setScreenResolution(
511
+ String(details.screenResolution[0]),
512
+ String(details.screenResolution[1])
513
+ );
514
+ } else {
515
+ trackers[details.tracker]?.addPayloadPair('res', '');
516
+ }
517
+ return <Promise<void>>Promise.resolve();
518
+ }
519
+
520
+ function setScreenViewport(details: {
521
+ tracker: string;
522
+ screenViewport: ScreenSize | null;
523
+ }): Promise<void> {
524
+ if (details.screenViewport) {
525
+ trackers[details.tracker]?.setViewport(
526
+ String(details.screenViewport[0]),
527
+ String(details.screenViewport[1])
528
+ );
529
+ } else {
530
+ trackers[details.tracker]?.addPayloadPair('vp', '');
531
+ }
532
+ return <Promise<void>>Promise.resolve();
533
+ }
534
+
535
+ function setColorDepth(details: {
536
+ tracker: string;
537
+ colorDepth: number | null;
538
+ }): Promise<void> {
539
+ trackers[details.tracker]?.setColorDepth(String(details.colorDepth ?? ''));
540
+ return <Promise<void>>Promise.resolve();
541
+ }
542
+
543
+ function getSessionUserId(): Promise<string> {
544
+ return <Promise<string>>Promise.reject(new Error('Not implemented'));
545
+ }
546
+
547
+ function getSessionId(): Promise<string> {
548
+ return <Promise<string>>Promise.reject(new Error('Not implemented'));
549
+ }
550
+
551
+ function getSessionIndex(): Promise<number> {
552
+ return <Promise<number>>Promise.reject(new Error('Not implemented'));
553
+ }
554
+
555
+ function getIsInBackground(): Promise<boolean> {
556
+ return <Promise<boolean>>Promise.reject(new Error('Not implemented'));
557
+ }
558
+
559
+ function getBackgroundIndex(): Promise<number> {
560
+ return <Promise<number>>Promise.reject(new Error('Not implemented'));
561
+ }
562
+
563
+ function getForegroundIndex(): Promise<number> {
564
+ return <Promise<number>>Promise.reject(new Error('Not implemented'));
565
+ }
566
+
567
+ const JSSnowplowTracker = Object.freeze({
568
+ createTracker,
569
+ removeTracker,
570
+ removeAllTrackers,
571
+ trackSelfDescribingEvent,
572
+ trackStructuredEvent,
573
+ trackScreenViewEvent,
574
+ trackScrollChangedEvent,
575
+ trackListItemViewEvent,
576
+ trackPageViewEvent,
577
+ trackTimingEvent,
578
+ trackConsentGrantedEvent,
579
+ trackConsentWithdrawnEvent,
580
+ trackEcommerceTransactionEvent,
581
+ trackDeepLinkReceivedEvent,
582
+ trackMessageNotificationEvent,
583
+ removeGlobalContexts,
584
+ addGlobalContexts,
585
+ setUserId,
586
+ setNetworkUserId,
587
+ setDomainUserId,
588
+ setIpAddress,
589
+ setUseragent,
590
+ setTimezone,
591
+ setLanguage,
592
+ setScreenResolution,
593
+ setScreenViewport,
594
+ setColorDepth,
595
+ getSessionUserId,
596
+ getSessionId,
597
+ getSessionIndex,
598
+ getIsInBackground,
599
+ getBackgroundIndex,
600
+ getForegroundIndex,
601
+ });
602
+
603
+ export { JSSnowplowTracker };
package/src/native.ts ADDED
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ import { NativeModules } from 'react-native';
4
+ import { JSSnowplowTracker } from './jsCore';
5
+ import type { Native } from './types';
6
+ import { errorHandler } from './utils';
7
+
8
+ const isAvailable = NativeModules.ReactNativeTracker != null;
9
+ if (!isAvailable) {
10
+ errorHandler(
11
+ new Error(
12
+ 'Unable to access the native iOS/Android Snowplow tracker, a tracker implementation with very limited functionality is used.'
13
+ )
14
+ );
15
+ }
16
+
17
+ const RNSnowplowTracker: Native = isAvailable
18
+ ? (NativeModules.ReactNativeTracker as Native)
19
+ : JSSnowplowTracker;
20
+
21
+ export { RNSnowplowTracker };