@grafana/faro-react-native 1.2.1 → 1.3.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 (217) hide show
  1. package/android/build.gradle +118 -36
  2. package/android/consumer-proguard-rules.pro +2 -0
  3. package/android/src/main/java/com/grafana/faro/reactnative/ANRTracker.kt +61 -9
  4. package/android/src/main/java/com/grafana/faro/reactnative/AnrThreadDumpParser.kt +70 -0
  5. package/android/src/main/java/com/grafana/faro/reactnative/ApplicationExitTraceReader.kt +142 -0
  6. package/android/src/main/java/com/grafana/faro/reactnative/FaroAnrCache.kt +163 -0
  7. package/android/src/main/java/com/grafana/faro/reactnative/FaroAnrReporter.kt +163 -0
  8. package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashReporter.kt +243 -50
  9. package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashTraceCache.kt +75 -0
  10. package/android/src/main/java/com/grafana/faro/reactnative/FaroNativeCrashTrace.kt +39 -0
  11. package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativeModule.kt +99 -8
  12. package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativePackage.kt +1 -0
  13. package/android/src/main/java/com/grafana/faro/reactnative/FaroUncaughtExceptionHandler.kt +62 -0
  14. package/android/src/main/java/com/grafana/faro/reactnative/TombstoneBacktraceFormatter.kt +117 -0
  15. package/android/src/main/java/com/grafana/faro/reactnative/TombstoneModels.kt +35 -0
  16. package/android/src/main/java/com/grafana/faro/reactnative/TombstoneWireParser.kt +235 -0
  17. package/android/src/main/proto/tombstone.proto +62 -0
  18. package/android/src/test/java/com/grafana/faro/reactnative/AnrStackFiltersTest.kt +28 -0
  19. package/android/src/test/java/com/grafana/faro/reactnative/AnrThreadDumpParserTest.kt +38 -0
  20. package/android/src/test/java/com/grafana/faro/reactnative/FaroAnrCacheTest.kt +81 -0
  21. package/android/src/test/java/com/grafana/faro/reactnative/TombstoneWireParserTest.kt +51 -0
  22. package/dist/cjs/config/getRNInstrumentations.js +3 -1
  23. package/dist/cjs/config/getRNInstrumentations.js.map +1 -1
  24. package/dist/cjs/config/makeRNConfig.js +48 -9
  25. package/dist/cjs/config/makeRNConfig.js.map +1 -1
  26. package/dist/cjs/config/types.js.map +1 -1
  27. package/dist/cjs/generated/faroRNPackageMeta.js +1 -1
  28. package/dist/cjs/generated/faroRNPackageMeta.js.map +1 -1
  29. package/dist/cjs/index.js +3 -2
  30. package/dist/cjs/index.js.map +1 -1
  31. package/dist/cjs/initialize.js +14 -8
  32. package/dist/cjs/initialize.js.map +1 -1
  33. package/dist/cjs/instrumentations/anr/anrStack.js +19 -0
  34. package/dist/cjs/instrumentations/anr/anrStack.js.map +1 -0
  35. package/dist/cjs/instrumentations/anr/instrumentation.js +374 -72
  36. package/dist/cjs/instrumentations/anr/instrumentation.js.map +1 -1
  37. package/dist/cjs/instrumentations/anr/types.js.map +1 -1
  38. package/dist/cjs/instrumentations/console/index.js +5 -1
  39. package/dist/cjs/instrumentations/console/index.js.map +1 -1
  40. package/dist/cjs/instrumentations/crashReporting/{instrumentation.js → BaseCrashReportingInstrumentation.js} +110 -103
  41. package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -0
  42. package/dist/cjs/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js +41 -0
  43. package/dist/cjs/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js.map +1 -0
  44. package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +87 -0
  45. package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -0
  46. package/dist/cjs/instrumentations/crashReporting/android/crashErrorMessage.js +123 -0
  47. package/dist/cjs/instrumentations/crashReporting/android/crashErrorMessage.js.map +1 -0
  48. package/dist/cjs/instrumentations/crashReporting/android/index.js +12 -0
  49. package/dist/cjs/instrumentations/crashReporting/android/index.js.map +1 -0
  50. package/dist/cjs/instrumentations/crashReporting/android/nativeTombstoneTrace.js +11 -0
  51. package/dist/cjs/instrumentations/crashReporting/android/nativeTombstoneTrace.js.map +1 -0
  52. package/dist/cjs/instrumentations/crashReporting/android/parseAndroidCrashTrace.js +181 -0
  53. package/dist/cjs/instrumentations/crashReporting/android/parseAndroidCrashTrace.js.map +1 -0
  54. package/dist/cjs/instrumentations/crashReporting/index.js +35 -2
  55. package/dist/cjs/instrumentations/crashReporting/index.js.map +1 -1
  56. package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +78 -0
  57. package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -0
  58. package/dist/cjs/instrumentations/crashReporting/ios/crashErrorMessage.js +103 -0
  59. package/dist/cjs/instrumentations/crashReporting/ios/crashErrorMessage.js.map +1 -0
  60. package/dist/cjs/instrumentations/crashReporting/ios/index.js +11 -0
  61. package/dist/cjs/instrumentations/crashReporting/ios/index.js.map +1 -0
  62. package/dist/cjs/instrumentations/crashReporting/ios/parseIosCrashTrace.js +48 -0
  63. package/dist/cjs/instrumentations/crashReporting/ios/parseIosCrashTrace.js.map +1 -0
  64. package/dist/cjs/instrumentations/crashReporting/types.js.map +1 -1
  65. package/dist/cjs/instrumentations/errors/index.js +2 -1
  66. package/dist/cjs/instrumentations/errors/index.js.map +1 -1
  67. package/dist/cjs/instrumentations/session/installationId.js +91 -0
  68. package/dist/cjs/instrumentations/session/installationId.js.map +1 -0
  69. package/dist/cjs/instrumentations/session/sessionAttributes.js +152 -89
  70. package/dist/cjs/instrumentations/session/sessionAttributes.js.map +1 -1
  71. package/dist/cjs/metas/appBuildIdentity.js +95 -0
  72. package/dist/cjs/metas/appBuildIdentity.js.map +1 -0
  73. package/dist/cjs/testUtils/mockDeviceInfo.js +5 -0
  74. package/dist/cjs/testUtils/mockDeviceInfo.js.map +1 -1
  75. package/dist/cjs/testUtils/setupTests.js +7 -0
  76. package/dist/cjs/testUtils/setupTests.js.map +1 -1
  77. package/dist/esm/config/getRNInstrumentations.js +3 -1
  78. package/dist/esm/config/getRNInstrumentations.js.map +1 -1
  79. package/dist/esm/config/makeRNConfig.js +49 -10
  80. package/dist/esm/config/makeRNConfig.js.map +1 -1
  81. package/dist/esm/config/types.js.map +1 -1
  82. package/dist/esm/generated/faroRNPackageMeta.js +1 -1
  83. package/dist/esm/generated/faroRNPackageMeta.js.map +1 -1
  84. package/dist/esm/index.js +1 -1
  85. package/dist/esm/index.js.map +1 -1
  86. package/dist/esm/initialize.js +11 -5
  87. package/dist/esm/initialize.js.map +1 -1
  88. package/dist/esm/instrumentations/anr/anrStack.js +16 -0
  89. package/dist/esm/instrumentations/anr/anrStack.js.map +1 -0
  90. package/dist/esm/instrumentations/anr/instrumentation.js +260 -67
  91. package/dist/esm/instrumentations/anr/instrumentation.js.map +1 -1
  92. package/dist/esm/instrumentations/anr/types.js.map +1 -1
  93. package/dist/esm/instrumentations/console/index.js +5 -1
  94. package/dist/esm/instrumentations/console/index.js.map +1 -1
  95. package/dist/esm/instrumentations/crashReporting/{instrumentation.js → BaseCrashReportingInstrumentation.js} +76 -94
  96. package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -0
  97. package/dist/esm/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js +18 -0
  98. package/dist/esm/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js.map +1 -0
  99. package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +56 -0
  100. package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -0
  101. package/dist/esm/instrumentations/crashReporting/android/crashErrorMessage.js +116 -0
  102. package/dist/esm/instrumentations/crashReporting/android/crashErrorMessage.js.map +1 -0
  103. package/dist/esm/instrumentations/crashReporting/android/index.js +4 -0
  104. package/dist/esm/instrumentations/crashReporting/android/index.js.map +1 -0
  105. package/dist/esm/instrumentations/crashReporting/android/nativeTombstoneTrace.js +8 -0
  106. package/dist/esm/instrumentations/crashReporting/android/nativeTombstoneTrace.js.map +1 -0
  107. package/dist/esm/instrumentations/crashReporting/android/parseAndroidCrashTrace.js +174 -0
  108. package/dist/esm/instrumentations/crashReporting/android/parseAndroidCrashTrace.js.map +1 -0
  109. package/dist/esm/instrumentations/crashReporting/index.js +35 -1
  110. package/dist/esm/instrumentations/crashReporting/index.js.map +1 -1
  111. package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +56 -0
  112. package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -0
  113. package/dist/esm/instrumentations/crashReporting/ios/crashErrorMessage.js +98 -0
  114. package/dist/esm/instrumentations/crashReporting/ios/crashErrorMessage.js.map +1 -0
  115. package/dist/esm/instrumentations/crashReporting/ios/index.js +4 -0
  116. package/dist/esm/instrumentations/crashReporting/ios/index.js.map +1 -0
  117. package/dist/esm/instrumentations/crashReporting/ios/parseIosCrashTrace.js +44 -0
  118. package/dist/esm/instrumentations/crashReporting/ios/parseIosCrashTrace.js.map +1 -0
  119. package/dist/esm/instrumentations/crashReporting/types.js.map +1 -1
  120. package/dist/esm/instrumentations/errors/index.js +2 -1
  121. package/dist/esm/instrumentations/errors/index.js.map +1 -1
  122. package/dist/esm/instrumentations/session/installationId.js +48 -0
  123. package/dist/esm/instrumentations/session/installationId.js.map +1 -0
  124. package/dist/esm/instrumentations/session/sessionAttributes.js +83 -38
  125. package/dist/esm/instrumentations/session/sessionAttributes.js.map +1 -1
  126. package/dist/esm/metas/appBuildIdentity.js +56 -0
  127. package/dist/esm/metas/appBuildIdentity.js.map +1 -0
  128. package/dist/esm/testUtils/mockDeviceInfo.js +5 -0
  129. package/dist/esm/testUtils/mockDeviceInfo.js.map +1 -1
  130. package/dist/esm/testUtils/setupTests.js +7 -0
  131. package/dist/esm/testUtils/setupTests.js.map +1 -1
  132. package/dist/types/config/makeRNConfig.d.ts +4 -3
  133. package/dist/types/config/types.d.ts +2 -1
  134. package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
  135. package/dist/types/index.d.ts +2 -2
  136. package/dist/types/initialize.d.ts +4 -2
  137. package/dist/types/instrumentations/anr/anrStack.d.ts +7 -0
  138. package/dist/types/instrumentations/anr/instrumentation.d.ts +23 -28
  139. package/dist/types/instrumentations/anr/types.d.ts +5 -1
  140. package/dist/types/instrumentations/appState/index.d.ts +1 -1
  141. package/dist/types/instrumentations/console/index.d.ts +1 -1
  142. package/dist/types/instrumentations/crashReporting/BaseCrashReportingInstrumentation.d.ts +56 -0
  143. package/dist/types/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.d.ts +12 -0
  144. package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +26 -0
  145. package/dist/types/instrumentations/crashReporting/android/crashErrorMessage.d.ts +23 -0
  146. package/dist/types/instrumentations/crashReporting/android/index.d.ts +4 -0
  147. package/dist/types/instrumentations/crashReporting/android/nativeTombstoneTrace.d.ts +2 -0
  148. package/dist/types/instrumentations/crashReporting/android/parseAndroidCrashTrace.d.ts +45 -0
  149. package/dist/types/instrumentations/crashReporting/index.d.ts +25 -2
  150. package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +28 -0
  151. package/dist/types/instrumentations/crashReporting/ios/crashErrorMessage.d.ts +14 -0
  152. package/dist/types/instrumentations/crashReporting/ios/index.d.ts +4 -0
  153. package/dist/types/instrumentations/crashReporting/ios/parseIosCrashTrace.d.ts +38 -0
  154. package/dist/types/instrumentations/crashReporting/types.d.ts +18 -51
  155. package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +1 -1
  156. package/dist/types/instrumentations/http/index.d.ts +1 -1
  157. package/dist/types/instrumentations/performance/index.d.ts +1 -1
  158. package/dist/types/instrumentations/session/index.d.ts +1 -1
  159. package/dist/types/instrumentations/session/installationId.d.ts +1 -0
  160. package/dist/types/instrumentations/session/sessionAttributes.d.ts +13 -4
  161. package/dist/types/instrumentations/startup/index.d.ts +1 -1
  162. package/dist/types/instrumentations/userActions/index.d.ts +1 -1
  163. package/dist/types/instrumentations/view/index.d.ts +1 -1
  164. package/dist/types/instrumentations/xhr/index.d.ts +1 -1
  165. package/dist/types/metas/appBuildIdentity.d.ts +16 -0
  166. package/dist/types/testUtils/mockFaroReactNativeTracing.d.ts +1 -1
  167. package/dist/types/transports/console/transport.d.ts +1 -1
  168. package/dist/types/transports/fetch/transport.d.ts +1 -1
  169. package/dist/types/transports/offline/transport.d.ts +1 -1
  170. package/package.json +4 -4
  171. package/src/config/getRNInstrumentations.ts +5 -1
  172. package/src/config/makeRNConfig.test.ts +59 -3
  173. package/src/config/makeRNConfig.ts +48 -9
  174. package/src/config/types.ts +2 -1
  175. package/src/generated/faroRNPackageMeta.ts +1 -1
  176. package/src/index.ts +2 -1
  177. package/src/initialize.test.ts +71 -15
  178. package/src/initialize.ts +11 -5
  179. package/src/instrumentations/anr/anrStack.test.ts +27 -0
  180. package/src/instrumentations/anr/anrStack.ts +19 -0
  181. package/src/instrumentations/anr/instrumentation.test.ts +45 -0
  182. package/src/instrumentations/anr/instrumentation.ts +301 -67
  183. package/src/instrumentations/anr/types.ts +7 -1
  184. package/src/instrumentations/console/index.ts +5 -1
  185. package/src/instrumentations/console/instrumentation.test.ts +5 -0
  186. package/src/instrumentations/crashReporting/{instrumentation.ts → BaseCrashReportingInstrumentation.ts} +119 -93
  187. package/src/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.ts +23 -0
  188. package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +62 -0
  189. package/src/instrumentations/crashReporting/android/crashErrorMessage.test.ts +182 -0
  190. package/src/instrumentations/crashReporting/android/crashErrorMessage.ts +135 -0
  191. package/src/instrumentations/crashReporting/android/index.ts +4 -0
  192. package/src/instrumentations/crashReporting/android/nativeTombstoneTrace.test.ts +19 -0
  193. package/src/instrumentations/crashReporting/android/nativeTombstoneTrace.ts +8 -0
  194. package/src/instrumentations/crashReporting/android/parseAndroidCrashTrace.test.ts +232 -0
  195. package/src/instrumentations/crashReporting/android/parseAndroidCrashTrace.ts +235 -0
  196. package/src/instrumentations/crashReporting/index.ts +43 -2
  197. package/src/instrumentations/crashReporting/instrumentation.test.ts +42 -0
  198. package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +62 -0
  199. package/src/instrumentations/crashReporting/ios/crashErrorMessage.test.ts +170 -0
  200. package/src/instrumentations/crashReporting/ios/crashErrorMessage.ts +111 -0
  201. package/src/instrumentations/crashReporting/ios/index.ts +4 -0
  202. package/src/instrumentations/crashReporting/ios/parseIosCrashTrace.test.ts +86 -0
  203. package/src/instrumentations/crashReporting/ios/parseIosCrashTrace.ts +83 -0
  204. package/src/instrumentations/crashReporting/types.ts +19 -58
  205. package/src/instrumentations/errors/index.ts +2 -1
  206. package/src/instrumentations/errors/instrumentation.test.ts +8 -2
  207. package/src/instrumentations/errors/stackTraceParser.test.ts +1 -1
  208. package/src/instrumentations/session/installationId.ts +43 -0
  209. package/src/instrumentations/session/sessionAttributes.test.ts +260 -30
  210. package/src/instrumentations/session/sessionAttributes.ts +112 -22
  211. package/src/metas/appBuildIdentity.test.ts +48 -0
  212. package/src/metas/appBuildIdentity.ts +50 -0
  213. package/src/testUtils/mockDeviceInfo.ts +5 -0
  214. package/src/testUtils/setupTests.ts +7 -0
  215. package/dist/cjs/instrumentations/crashReporting/instrumentation.js.map +0 -1
  216. package/dist/esm/instrumentations/crashReporting/instrumentation.js.map +0 -1
  217. package/dist/types/instrumentations/crashReporting/instrumentation.d.ts +0 -58
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -41,9 +52,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
41
52
  Object.defineProperty(exports, "__esModule", { value: true });
42
53
  exports.minimalSessionDeviceAttributes = minimalSessionDeviceAttributes;
43
54
  exports.getSessionAttributes = getSessionAttributes;
55
+ exports.loadMobileMetaForInit = loadMobileMetaForInit;
44
56
  exports.loadSessionDeviceAttributesForInit = loadSessionDeviceAttributesForInit;
45
57
  var react_native_1 = require("react-native");
46
58
  var react_native_device_info_1 = __importDefault(require("react-native-device-info"));
59
+ var installationId_1 = require("./installationId");
47
60
  /**
48
61
  * React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.
49
62
  */
@@ -64,28 +77,35 @@ function getReactNativeVersion() {
64
77
  return 'unknown';
65
78
  }
66
79
  }
67
- /**
68
- * Get device ID using react-native-device-info
69
- * Returns unique device identifier or 'unknown' on error
70
- */
71
- function getDeviceId() {
72
- return __awaiter(this, void 0, void 0, function () {
73
- var _error_1;
74
- return __generator(this, function (_a) {
75
- switch (_a.label) {
76
- case 0:
77
- _a.trys.push([0, 2, , 3]);
78
- return [4 /*yield*/, react_native_device_info_1.default.getUniqueId()];
79
- case 1:
80
- // getUniqueId returns a UUID that persists across app installations
81
- return [2 /*return*/, _a.sent()];
82
- case 2:
83
- _error_1 = _a.sent();
84
- return [2 /*return*/, 'unknown'];
85
- case 3: return [2 /*return*/];
86
- }
87
- });
88
- });
80
+ function getStructuredDeviceBrand(model, brand) {
81
+ if (react_native_1.Platform.OS !== 'ios') {
82
+ return brand;
83
+ }
84
+ return model.toLowerCase().includes('ipad') ? 'iPad' : 'iPhone';
85
+ }
86
+ function getStructuredDeviceManufacturer(manufacturer) {
87
+ return react_native_1.Platform.OS === 'ios' ? manufacturer.toLowerCase() : manufacturer;
88
+ }
89
+ function getStructuredDeviceModelIdentifier(model) {
90
+ // Android getDeviceId() returns a board code, so use Build.MODEL for the Faro
91
+ // model identifier.
92
+ if (react_native_1.Platform.OS === 'android') {
93
+ return model;
94
+ }
95
+ // React Native reports iPhone and iPadOS apps as Platform.OS === 'ios'.
96
+ // react-native-device-info exposes the Apple hardware identifier here.
97
+ if (react_native_1.Platform.OS === 'ios') {
98
+ return react_native_device_info_1.default.getDeviceId();
99
+ }
100
+ return undefined;
101
+ }
102
+ function getMobileDeviceType(isTablet) {
103
+ // iPadOS is still reported as Platform.OS === 'ios'; DeviceInfo.isTablet()
104
+ // distinguishes iPad/tablet form factor from phone form factor.
105
+ if (react_native_1.Platform.OS === 'ios' || react_native_1.Platform.OS === 'android') {
106
+ return isTablet ? 'tablet' : 'mobile';
107
+ }
108
+ return undefined;
89
109
  }
90
110
  /**
91
111
  * Get OS detail string matching Flutter SDK format
@@ -94,7 +114,7 @@ function getDeviceId() {
94
114
  */
95
115
  function getDeviceOsDetail() {
96
116
  return __awaiter(this, void 0, void 0, function () {
97
- var systemName, systemVersion, apiLevel, _error_2;
117
+ var systemName, systemVersion, apiLevel, _error_1;
98
118
  return __generator(this, function (_a) {
99
119
  switch (_a.label) {
100
120
  case 0:
@@ -109,13 +129,32 @@ function getDeviceOsDetail() {
109
129
  apiLevel = _a.sent();
110
130
  return [2 /*return*/, "".concat(systemName, " ").concat(systemVersion, " (SDK ").concat(apiLevel, ")")];
111
131
  case 3:
112
- _error_2 = _a.sent();
132
+ _error_1 = _a.sent();
113
133
  return [2 /*return*/, "".concat(systemName, " ").concat(systemVersion)];
114
134
  case 4: return [2 /*return*/, "".concat(systemName, " ").concat(systemVersion)];
115
135
  }
116
136
  });
117
137
  });
118
138
  }
139
+ function getDeviceOsBuildId() {
140
+ return __awaiter(this, void 0, void 0, function () {
141
+ var buildId, _error_2;
142
+ return __generator(this, function (_a) {
143
+ switch (_a.label) {
144
+ case 0:
145
+ _a.trys.push([0, 2, , 3]);
146
+ return [4 /*yield*/, react_native_device_info_1.default.getBuildId()];
147
+ case 1:
148
+ buildId = _a.sent();
149
+ return [2 /*return*/, buildId && buildId !== 'unknown' ? buildId : undefined];
150
+ case 2:
151
+ _error_2 = _a.sent();
152
+ return [2 /*return*/, undefined];
153
+ case 3: return [2 /*return*/];
154
+ }
155
+ });
156
+ });
157
+ }
119
158
  /**
120
159
  * Session attributes without device props when async collection or DeviceInfo is unavailable.
121
160
  * No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.
@@ -143,25 +182,38 @@ function minimalSessionDeviceAttributes() {
143
182
  */
144
183
  function getSessionAttributes() {
145
184
  return __awaiter(this, void 0, void 0, function () {
146
- var deviceId, deviceOsDetail, systemName, systemVersion, manufacturer, model, deviceName, brand, isEmulator, isTablet, totalMemory, usedMemory, reactNativeVersion, batteryLevel, isCharging, lowPowerMode, carrier, battery, _error_3, _a, _error_4, _b, _error_5, carrierName, _error_6, attributes, _error_7;
147
- return __generator(this, function (_c) {
148
- switch (_c.label) {
185
+ return __generator(this, function (_a) {
186
+ switch (_a.label) {
187
+ case 0: return [4 /*yield*/, collectMobileMeta()];
188
+ case 1: return [2 /*return*/, (_a.sent()).sessionAttributes];
189
+ }
190
+ });
191
+ });
192
+ }
193
+ function collectMobileMeta() {
194
+ return __awaiter(this, void 0, void 0, function () {
195
+ var _a, deviceOsDetail, deviceOsBuildId, installationId, systemName, systemVersion, manufacturer, model, modelIdentifier, deviceName, brand, isEmulator, isTablet, deviceType, totalMemory, usedMemory, reactNativeVersion, batteryLevel, isCharging, lowPowerMode, carrier, battery, _error_3, _b, _error_4, _c, _error_5, carrierName, _error_6, attributes, appMeta, structuredDeviceBrand, structuredDeviceManufacturer, osMeta, _error_7, installationId;
196
+ return __generator(this, function (_d) {
197
+ switch (_d.label) {
149
198
  case 0:
150
- _c.trys.push([0, 17, , 18]);
151
- return [4 /*yield*/, getDeviceId()];
199
+ _d.trys.push([0, 16, , 18]);
200
+ return [4 /*yield*/, Promise.all([
201
+ getDeviceOsDetail(),
202
+ getDeviceOsBuildId(),
203
+ (0, installationId_1.getInstallationId)(),
204
+ ])];
152
205
  case 1:
153
- deviceId = _c.sent();
154
- return [4 /*yield*/, getDeviceOsDetail()];
155
- case 2:
156
- deviceOsDetail = _c.sent();
206
+ _a = _d.sent(), deviceOsDetail = _a[0], deviceOsBuildId = _a[1], installationId = _a[2];
157
207
  systemName = react_native_device_info_1.default.getSystemName();
158
208
  systemVersion = react_native_device_info_1.default.getSystemVersion();
159
209
  manufacturer = react_native_device_info_1.default.getManufacturerSync();
160
210
  model = react_native_device_info_1.default.getModel();
211
+ modelIdentifier = getStructuredDeviceModelIdentifier(model);
161
212
  deviceName = react_native_device_info_1.default.getDeviceNameSync();
162
213
  brand = react_native_device_info_1.default.getBrand();
163
214
  isEmulator = react_native_device_info_1.default.isEmulatorSync();
164
215
  isTablet = react_native_device_info_1.default.isTablet();
216
+ deviceType = getMobileDeviceType(isTablet);
165
217
  totalMemory = react_native_device_info_1.default.getTotalMemorySync();
166
218
  usedMemory = react_native_device_info_1.default.getUsedMemorySync();
167
219
  reactNativeVersion = getReactNativeVersion();
@@ -169,82 +221,93 @@ function getSessionAttributes() {
169
221
  isCharging = void 0;
170
222
  lowPowerMode = void 0;
171
223
  carrier = void 0;
172
- _c.label = 3;
173
- case 3:
174
- _c.trys.push([3, 5, , 6]);
224
+ _d.label = 2;
225
+ case 2:
226
+ _d.trys.push([2, 4, , 5]);
175
227
  return [4 /*yield*/, react_native_device_info_1.default.getBatteryLevel()];
176
- case 4:
177
- battery = _c.sent();
228
+ case 3:
229
+ battery = _d.sent();
178
230
  if (battery >= 0) {
179
231
  batteryLevel = String(Math.round(battery * 100));
180
232
  }
181
- return [3 /*break*/, 6];
233
+ return [3 /*break*/, 5];
234
+ case 4:
235
+ _error_3 = _d.sent();
236
+ return [3 /*break*/, 5];
182
237
  case 5:
183
- _error_3 = _c.sent();
184
- return [3 /*break*/, 6];
185
- case 6:
186
- _c.trys.push([6, 8, , 9]);
187
- _a = String;
238
+ _d.trys.push([5, 7, , 8]);
239
+ _b = String;
188
240
  return [4 /*yield*/, react_native_device_info_1.default.isBatteryCharging()];
241
+ case 6:
242
+ isCharging = _b.apply(void 0, [_d.sent()]);
243
+ return [3 /*break*/, 8];
189
244
  case 7:
190
- isCharging = _a.apply(void 0, [_c.sent()]);
191
- return [3 /*break*/, 9];
245
+ _error_4 = _d.sent();
246
+ return [3 /*break*/, 8];
192
247
  case 8:
193
- _error_4 = _c.sent();
194
- return [3 /*break*/, 9];
195
- case 9:
196
- _c.trys.push([9, 12, , 13]);
197
- if (!('isPowerSaveMode' in react_native_device_info_1.default)) return [3 /*break*/, 11];
198
- _b = String;
248
+ _d.trys.push([8, 11, , 12]);
249
+ if (!('isPowerSaveMode' in react_native_device_info_1.default)) return [3 /*break*/, 10];
250
+ _c = String;
199
251
  return [4 /*yield*/, react_native_device_info_1.default.isPowerSaveMode()];
200
- case 10:
201
- lowPowerMode = _b.apply(void 0, [_c.sent()]);
202
- _c.label = 11;
203
- case 11: return [3 /*break*/, 13];
252
+ case 9:
253
+ lowPowerMode = _c.apply(void 0, [_d.sent()]);
254
+ _d.label = 10;
255
+ case 10: return [3 /*break*/, 12];
256
+ case 11:
257
+ _error_5 = _d.sent();
258
+ return [3 /*break*/, 12];
204
259
  case 12:
205
- _error_5 = _c.sent();
206
- return [3 /*break*/, 13];
207
- case 13:
208
- _c.trys.push([13, 15, , 16]);
260
+ _d.trys.push([12, 14, , 15]);
209
261
  return [4 /*yield*/, react_native_device_info_1.default.getCarrier()];
210
- case 14:
211
- carrierName = _c.sent();
262
+ case 13:
263
+ carrierName = _d.sent();
212
264
  if (carrierName && carrierName !== 'unknown') {
213
265
  carrier = carrierName;
214
266
  }
215
- return [3 /*break*/, 16];
267
+ return [3 /*break*/, 15];
268
+ case 14:
269
+ _error_6 = _d.sent();
270
+ return [3 /*break*/, 15];
216
271
  case 15:
217
- _error_6 = _c.sent();
218
- return [3 /*break*/, 16];
272
+ attributes = __assign(__assign(__assign({ react_native_version: reactNativeVersion, device_os: systemName, device_os_version: systemVersion, device_os_detail: deviceOsDetail, device_manufacturer: manufacturer.toLowerCase(), device_model: model, device_model_name: deviceName, device_brand: brand, device_is_physical: String(!isEmulator) }, (installationId ? { device_id: installationId } : {})), (deviceType ? { device_type: deviceType } : {})), { device_memory_total: String(totalMemory), device_memory_used: String(usedMemory), device_battery_level: batteryLevel, device_is_charging: isCharging, device_low_power_mode: lowPowerMode, device_carrier: carrier });
273
+ appMeta = installationId ? { installationId: installationId } : {};
274
+ structuredDeviceBrand = getStructuredDeviceBrand(model, brand);
275
+ structuredDeviceManufacturer = getStructuredDeviceManufacturer(manufacturer);
276
+ osMeta = __assign(__assign({}, (deviceOsBuildId ? { build_id: deviceOsBuildId } : {})), { detail: deviceOsDetail, name: systemName, version: systemVersion });
277
+ return [2 /*return*/, {
278
+ sessionAttributes: attributes,
279
+ meta: {
280
+ app: appMeta,
281
+ device: __assign(__assign(__assign({ brand: structuredDeviceBrand, is_physical: !isEmulator, manufacturer: structuredDeviceManufacturer }, (modelIdentifier ? { model_identifier: modelIdentifier } : {})), { model_name: model }), (deviceType ? { type: deviceType } : {})),
282
+ os: osMeta,
283
+ },
284
+ }];
219
285
  case 16:
220
- attributes = {
221
- react_native_version: reactNativeVersion,
222
- device_os: systemName,
223
- device_os_version: systemVersion,
224
- device_os_detail: deviceOsDetail,
225
- device_manufacturer: manufacturer.toLowerCase(),
226
- device_model: model,
227
- device_model_name: deviceName,
228
- device_brand: brand,
229
- device_is_physical: String(!isEmulator),
230
- device_id: deviceId,
231
- device_type: isTablet ? 'tablet' : 'mobile',
232
- device_memory_total: String(totalMemory),
233
- device_memory_used: String(usedMemory),
234
- device_battery_level: batteryLevel,
235
- device_is_charging: isCharging,
236
- device_low_power_mode: lowPowerMode,
237
- device_carrier: carrier,
238
- };
239
- return [2 /*return*/, attributes];
286
+ _error_7 = _d.sent();
287
+ return [4 /*yield*/, (0, installationId_1.getInstallationId)()];
240
288
  case 17:
241
- _error_7 = _c.sent();
242
- return [2 /*return*/, minimalSessionDeviceAttributes()];
289
+ installationId = _d.sent();
290
+ return [2 /*return*/, {
291
+ sessionAttributes: minimalSessionDeviceAttributes(),
292
+ meta: {
293
+ app: installationId ? { installationId: installationId } : {},
294
+ },
295
+ }];
243
296
  case 18: return [2 /*return*/];
244
297
  }
245
298
  });
246
299
  });
247
300
  }
301
+ /**
302
+ * Get structured mobile meta plus flat session attributes for async `initializeFaro`.
303
+ */
304
+ function loadMobileMetaForInit() {
305
+ return __awaiter(this, void 0, void 0, function () {
306
+ return __generator(this, function (_a) {
307
+ return [2 /*return*/, collectMobileMeta()];
308
+ });
309
+ });
310
+ }
248
311
  /**
249
312
  * Await full async session device attributes (battery, carrier, etc.), then fall back to
250
313
  * {@link minimalSessionDeviceAttributes} if anything throws. Used by async `initializeFaro`.
@@ -256,8 +319,8 @@ function loadSessionDeviceAttributesForInit() {
256
319
  switch (_b.label) {
257
320
  case 0:
258
321
  _b.trys.push([0, 2, , 3]);
259
- return [4 /*yield*/, getSessionAttributes()];
260
- case 1: return [2 /*return*/, _b.sent()];
322
+ return [4 /*yield*/, loadMobileMetaForInit()];
323
+ case 1: return [2 /*return*/, (_b.sent()).sessionAttributes];
261
324
  case 2:
262
325
  _a = _b.sent();
263
326
  return [2 /*return*/, minimalSessionDeviceAttributes()];
@@ -1 +1 @@
1
- {"version":3,"file":"sessionAttributes.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/sessionAttributes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\nimport DeviceInfo from 'react-native-device-info';\n\n/**\n * Session attributes for React Native\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes match Flutter SDK format, with additional mobile-specific\n * monitoring fields (memory, device type, battery, etc.)\n *\n * SDK name, core version, and npm adapter are on Faro meta `sdk` (`getSdkMeta` in `metas/sdk.ts`).\n *\n * `react_native_version` is the host app's React Native **framework** version from `Platform`, not the Faro package.\n */\nexport interface SessionAttributes {\n /** Host app's React Native framework version (e.g. \"0.75.1\") from `Platform.constants`. */\n react_native_version: string;\n\n /** Operating system (\"iOS\" or \"Android\") */\n device_os?: string;\n\n /** OS version (e.g., \"17.0\" for iOS, \"15\" for Android) */\n device_os_version?: string;\n\n /** Detailed OS info (e.g., \"iOS 17.0\" or \"Android 15 (SDK 35)\") */\n device_os_detail?: string;\n\n /** Device manufacturer (e.g., \"apple\", \"samsung\") */\n device_manufacturer?: string;\n\n /** Raw model identifier (e.g., \"iPhone16,1\", \"SM-A155F\") */\n device_model?: string;\n\n /** Human-readable model name (e.g., \"iPhone 15 Pro\") */\n device_model_name?: string;\n\n /** Device brand (e.g., \"iPhone\", \"samsung\") */\n device_brand?: string;\n\n /** Whether device is physical or emulator (\"true\" or \"false\") */\n device_is_physical?: string;\n\n /** Unique device ID (UUID) */\n device_id?: string;\n\n /** Device type (\"mobile\" or \"tablet\") */\n device_type?: string;\n\n /** Total device memory in bytes */\n device_memory_total?: string;\n\n /** Currently used memory in bytes */\n device_memory_used?: string;\n\n /** Battery level percentage (e.g., \"85\") - empty if unavailable */\n device_battery_level?: string;\n\n /** Whether device is charging (\"true\" or \"false\") - empty if unavailable */\n device_is_charging?: string;\n\n /** Whether low power mode is enabled (\"true\" or \"false\") - empty if unavailable */\n device_low_power_mode?: string;\n\n /** Mobile carrier name (e.g., \"Verizon\") - empty if unavailable */\n device_carrier?: string;\n}\n\n/**\n * React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.\n */\nfunction getReactNativeVersion(): string {\n try {\n const version = Platform.constants.reactNativeVersion;\n if (version && typeof version === 'object') {\n const { major, minor, patch, prerelease } = version as {\n major: number;\n minor: number;\n patch: number;\n prerelease?: number;\n };\n let versionString = `${major}.${minor}.${patch}`;\n if (prerelease) {\n versionString += `-rc.${prerelease}`;\n }\n return versionString;\n }\n return 'unknown';\n } catch (_error) {\n return 'unknown';\n }\n}\n\n/**\n * Get device ID using react-native-device-info\n * Returns unique device identifier or 'unknown' on error\n */\nasync function getDeviceId(): Promise<string> {\n try {\n // getUniqueId returns a UUID that persists across app installations\n return await DeviceInfo.getUniqueId();\n } catch (_error) {\n return 'unknown';\n }\n}\n\n/**\n * Get OS detail string matching Flutter SDK format\n * iOS: \"iOS 17.0\"\n * Android: \"Android 15 (SDK 35)\"\n */\nasync function getDeviceOsDetail(): Promise<string> {\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n\n if (Platform.OS === 'android') {\n try {\n const apiLevel = await DeviceInfo.getApiLevel();\n return `${systemName} ${systemVersion} (SDK ${apiLevel})`;\n } catch (_error) {\n return `${systemName} ${systemVersion}`;\n }\n }\n\n return `${systemName} ${systemVersion}`;\n}\n\n/**\n * Session attributes without device props when async collection or DeviceInfo is unavailable.\n * No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.\n */\nexport function minimalSessionDeviceAttributes(): SessionAttributes {\n return {\n react_native_version: getReactNativeVersion(),\n };\n}\n\n/**\n * Get all session attributes\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes matching Flutter SDK:\n * - react_native_version (RN framework in the host app)\n * - device_os, device_os_version, device_os_detail\n * - device_manufacturer, device_model, device_model_name\n * - device_brand, device_is_physical, device_id\n *\n * Additional monitoring attributes:\n * - device_type (mobile/tablet)\n * - device_memory_total, device_memory_used\n * - device_battery_level, device_is_charging, device_low_power_mode\n * - device_carrier\n */\nexport async function getSessionAttributes(): Promise<SessionAttributes> {\n try {\n // Get device ID asynchronously\n const deviceId = await getDeviceId();\n const deviceOsDetail = await getDeviceOsDetail();\n\n // Get synchronous device info\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n const manufacturer = DeviceInfo.getManufacturerSync();\n const model = DeviceInfo.getModel();\n const deviceName = DeviceInfo.getDeviceNameSync();\n const brand = DeviceInfo.getBrand();\n const isEmulator = DeviceInfo.isEmulatorSync();\n const isTablet = DeviceInfo.isTablet();\n\n // Memory info\n const totalMemory = DeviceInfo.getTotalMemorySync();\n const usedMemory = DeviceInfo.getUsedMemorySync();\n const reactNativeVersion = getReactNativeVersion();\n\n // Try to get async device info (battery, carrier)\n let batteryLevel: string | undefined;\n let isCharging: string | undefined;\n let lowPowerMode: string | undefined;\n let carrier: string | undefined;\n\n try {\n const battery = await DeviceInfo.getBatteryLevel();\n if (battery >= 0) {\n batteryLevel = String(Math.round(battery * 100));\n }\n } catch (_error) {\n // Battery info not available\n }\n\n try {\n isCharging = String(await DeviceInfo.isBatteryCharging());\n } catch (_error) {\n // Charging status not available\n }\n\n try {\n if ('isPowerSaveMode' in DeviceInfo) {\n lowPowerMode = String(\n await (DeviceInfo as typeof DeviceInfo & { isPowerSaveMode: () => Promise<boolean> }).isPowerSaveMode()\n );\n }\n } catch (_error) {\n // Low power mode not available\n }\n\n try {\n const carrierName = await DeviceInfo.getCarrier();\n if (carrierName && carrierName !== 'unknown') {\n carrier = carrierName;\n }\n } catch (_error) {\n // Carrier not available\n }\n\n const attributes: SessionAttributes = {\n react_native_version: reactNativeVersion,\n device_os: systemName,\n device_os_version: systemVersion,\n device_os_detail: deviceOsDetail,\n device_manufacturer: manufacturer.toLowerCase(),\n device_model: model,\n device_model_name: deviceName,\n device_brand: brand,\n device_is_physical: String(!isEmulator),\n device_id: deviceId,\n device_type: isTablet ? 'tablet' : 'mobile',\n device_memory_total: String(totalMemory),\n device_memory_used: String(usedMemory),\n device_battery_level: batteryLevel,\n device_is_charging: isCharging,\n device_low_power_mode: lowPowerMode,\n device_carrier: carrier,\n };\n\n return attributes;\n } catch (_error) {\n return minimalSessionDeviceAttributes();\n }\n}\n\n/**\n * Await full async session device attributes (battery, carrier, etc.), then fall back to\n * {@link minimalSessionDeviceAttributes} if anything throws. Used by async `initializeFaro`.\n */\nexport async function loadSessionDeviceAttributesForInit(): Promise<SessionAttributes> {\n try {\n return await getSessionAttributes();\n } catch {\n return minimalSessionDeviceAttributes();\n }\n}\n"]}
1
+ {"version":3,"file":"sessionAttributes.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/sessionAttributes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\nimport DeviceInfo from 'react-native-device-info';\n\nimport type { Meta } from '@grafana/faro-core';\n\nimport { getInstallationId } from './installationId';\n\n/**\n * Session attributes for React Native\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes match Flutter SDK format, with additional mobile-specific\n * monitoring fields (memory, device type, battery, etc.)\n *\n * SDK name, core version, and npm adapter are on Faro meta `sdk` (`getSdkMeta` in `metas/sdk.ts`).\n *\n * `react_native_version` is the host app's React Native **framework** version from `Platform`, not the Faro package.\n */\nexport interface SessionAttributes {\n /** Host app's React Native framework version (e.g. \"0.75.1\") from `Platform.constants`. */\n react_native_version: string;\n\n /** Operating system (\"iOS\" or \"Android\") */\n device_os?: string;\n\n /** OS version (e.g., \"17.0\" for iOS, \"15\" for Android) */\n device_os_version?: string;\n\n /** Detailed OS info (e.g., \"iOS 17.0\" or \"Android 15 (SDK 35)\") */\n device_os_detail?: string;\n\n /** Device manufacturer (e.g., \"apple\", \"samsung\", \"Google\") */\n device_manufacturer?: string;\n\n /** Device model in flat session attributes (e.g., \"iPhone 15 Pro\", \"SM-A155F\") */\n device_model?: string;\n\n /** Human-readable model name (e.g., \"iPhone 15 Pro\") */\n device_model_name?: string;\n\n /** Device brand in flat session attributes (e.g., \"Apple\", \"samsung\") */\n device_brand?: string;\n\n /** Whether device is physical or emulator (\"true\" or \"false\") */\n device_is_physical?: string;\n\n /** Temporary flat attribute mirroring `app.installationId` during migration. */\n device_id?: string;\n\n /** Device type (\"mobile\" or \"tablet\") */\n device_type?: string;\n\n /** Total device memory in bytes */\n device_memory_total?: string;\n\n /** Currently used memory in bytes */\n device_memory_used?: string;\n\n /** Battery level percentage (e.g., \"85\") - empty if unavailable */\n device_battery_level?: string;\n\n /** Whether device is charging (\"true\" or \"false\") - empty if unavailable */\n device_is_charging?: string;\n\n /** Whether low power mode is enabled (\"true\" or \"false\") - empty if unavailable */\n device_low_power_mode?: string;\n\n /** Mobile carrier name (e.g., \"Verizon\") - empty if unavailable */\n device_carrier?: string;\n}\n\nexport interface PreloadedMobileMeta {\n sessionAttributes: SessionAttributes;\n meta: Pick<Meta, 'app' | 'device' | 'os'>;\n}\n\n/**\n * React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.\n */\nfunction getReactNativeVersion(): string {\n try {\n const version = Platform.constants.reactNativeVersion;\n if (version && typeof version === 'object') {\n const { major, minor, patch, prerelease } = version as {\n major: number;\n minor: number;\n patch: number;\n prerelease?: number;\n };\n let versionString = `${major}.${minor}.${patch}`;\n if (prerelease) {\n versionString += `-rc.${prerelease}`;\n }\n return versionString;\n }\n return 'unknown';\n } catch (_error) {\n return 'unknown';\n }\n}\n\nfunction getStructuredDeviceBrand(model: string, brand: string): string {\n if (Platform.OS !== 'ios') {\n return brand;\n }\n\n return model.toLowerCase().includes('ipad') ? 'iPad' : 'iPhone';\n}\n\nfunction getStructuredDeviceManufacturer(manufacturer: string): string {\n return Platform.OS === 'ios' ? manufacturer.toLowerCase() : manufacturer;\n}\n\nfunction getStructuredDeviceModelIdentifier(model: string): string | undefined {\n // Android getDeviceId() returns a board code, so use Build.MODEL for the Faro\n // model identifier.\n if (Platform.OS === 'android') {\n return model;\n }\n\n // React Native reports iPhone and iPadOS apps as Platform.OS === 'ios'.\n // react-native-device-info exposes the Apple hardware identifier here.\n if (Platform.OS === 'ios') {\n return DeviceInfo.getDeviceId();\n }\n\n return undefined;\n}\n\nfunction getMobileDeviceType(isTablet: boolean): 'mobile' | 'tablet' | undefined {\n // iPadOS is still reported as Platform.OS === 'ios'; DeviceInfo.isTablet()\n // distinguishes iPad/tablet form factor from phone form factor.\n if (Platform.OS === 'ios' || Platform.OS === 'android') {\n return isTablet ? 'tablet' : 'mobile';\n }\n\n return undefined;\n}\n\n/**\n * Get OS detail string matching Flutter SDK format\n * iOS: \"iOS 17.0\"\n * Android: \"Android 15 (SDK 35)\"\n */\nasync function getDeviceOsDetail(): Promise<string> {\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n\n if (Platform.OS === 'android') {\n try {\n const apiLevel = await DeviceInfo.getApiLevel();\n return `${systemName} ${systemVersion} (SDK ${apiLevel})`;\n } catch (_error) {\n return `${systemName} ${systemVersion}`;\n }\n }\n\n return `${systemName} ${systemVersion}`;\n}\n\nasync function getDeviceOsBuildId(): Promise<string | undefined> {\n try {\n // RN device-info exposes a useful OS build id on both Android and iOS.\n // Keep it omitted when unavailable instead of sending \"unknown\".\n const buildId = await DeviceInfo.getBuildId();\n return buildId && buildId !== 'unknown' ? buildId : undefined;\n } catch (_error) {\n return undefined;\n }\n}\n\n/**\n * Session attributes without device props when async collection or DeviceInfo is unavailable.\n * No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.\n */\nexport function minimalSessionDeviceAttributes(): SessionAttributes {\n return {\n react_native_version: getReactNativeVersion(),\n };\n}\n\n/**\n * Get all session attributes\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes matching Flutter SDK:\n * - react_native_version (RN framework in the host app)\n * - device_os, device_os_version, device_os_detail\n * - device_manufacturer, device_model, device_model_name\n * - device_brand, device_is_physical, device_id\n *\n * Additional monitoring attributes:\n * - device_type (mobile/tablet)\n * - device_memory_total, device_memory_used\n * - device_battery_level, device_is_charging, device_low_power_mode\n * - device_carrier\n */\nexport async function getSessionAttributes(): Promise<SessionAttributes> {\n return (await collectMobileMeta()).sessionAttributes;\n}\n\nasync function collectMobileMeta(): Promise<PreloadedMobileMeta> {\n try {\n const [deviceOsDetail, deviceOsBuildId, installationId] = await Promise.all([\n getDeviceOsDetail(),\n getDeviceOsBuildId(),\n getInstallationId(),\n ]);\n\n // Get synchronous device info\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n const manufacturer = DeviceInfo.getManufacturerSync();\n const model = DeviceInfo.getModel();\n const modelIdentifier = getStructuredDeviceModelIdentifier(model);\n const deviceName = DeviceInfo.getDeviceNameSync();\n const brand = DeviceInfo.getBrand();\n const isEmulator = DeviceInfo.isEmulatorSync();\n const isTablet = DeviceInfo.isTablet();\n const deviceType = getMobileDeviceType(isTablet);\n\n // Memory info\n const totalMemory = DeviceInfo.getTotalMemorySync();\n const usedMemory = DeviceInfo.getUsedMemorySync();\n const reactNativeVersion = getReactNativeVersion();\n\n // Try to get async device info (battery, carrier)\n let batteryLevel: string | undefined;\n let isCharging: string | undefined;\n let lowPowerMode: string | undefined;\n let carrier: string | undefined;\n\n try {\n const battery = await DeviceInfo.getBatteryLevel();\n if (battery >= 0) {\n batteryLevel = String(Math.round(battery * 100));\n }\n } catch (_error) {\n // Battery info not available\n }\n\n try {\n isCharging = String(await DeviceInfo.isBatteryCharging());\n } catch (_error) {\n // Charging status not available\n }\n\n try {\n if ('isPowerSaveMode' in DeviceInfo) {\n lowPowerMode = String(\n await (DeviceInfo as typeof DeviceInfo & { isPowerSaveMode: () => Promise<boolean> }).isPowerSaveMode()\n );\n }\n } catch (_error) {\n // Low power mode not available\n }\n\n try {\n const carrierName = await DeviceInfo.getCarrier();\n if (carrierName && carrierName !== 'unknown') {\n carrier = carrierName;\n }\n } catch (_error) {\n // Carrier not available\n }\n\n const attributes: SessionAttributes = {\n react_native_version: reactNativeVersion,\n device_os: systemName,\n device_os_version: systemVersion,\n device_os_detail: deviceOsDetail,\n device_manufacturer: manufacturer.toLowerCase(),\n device_model: model,\n device_model_name: deviceName,\n device_brand: brand,\n device_is_physical: String(!isEmulator),\n ...(installationId ? { device_id: installationId } : {}),\n ...(deviceType ? { device_type: deviceType } : {}),\n device_memory_total: String(totalMemory),\n device_memory_used: String(usedMemory),\n device_battery_level: batteryLevel,\n device_is_charging: isCharging,\n device_low_power_mode: lowPowerMode,\n device_carrier: carrier,\n };\n const appMeta = installationId ? { installationId } : {};\n const structuredDeviceBrand = getStructuredDeviceBrand(model, brand);\n const structuredDeviceManufacturer = getStructuredDeviceManufacturer(manufacturer);\n const osMeta = {\n ...(deviceOsBuildId ? { build_id: deviceOsBuildId } : {}),\n detail: deviceOsDetail,\n name: systemName,\n version: systemVersion,\n };\n\n return {\n sessionAttributes: attributes,\n meta: {\n app: appMeta,\n device: {\n brand: structuredDeviceBrand,\n is_physical: !isEmulator,\n manufacturer: structuredDeviceManufacturer,\n ...(modelIdentifier ? { model_identifier: modelIdentifier } : {}),\n model_name: model,\n ...(deviceType ? { type: deviceType } : {}),\n },\n os: osMeta,\n },\n };\n } catch (_error) {\n const installationId = await getInstallationId();\n\n return {\n sessionAttributes: minimalSessionDeviceAttributes(),\n meta: {\n app: installationId ? { installationId } : {},\n },\n };\n }\n}\n\n/**\n * Get structured mobile meta plus flat session attributes for async `initializeFaro`.\n */\nexport async function loadMobileMetaForInit(): Promise<PreloadedMobileMeta> {\n return collectMobileMeta();\n}\n\n/**\n * Await full async session device attributes (battery, carrier, etc.), then fall back to\n * {@link minimalSessionDeviceAttributes} if anything throws. Used by async `initializeFaro`.\n */\nexport async function loadSessionDeviceAttributesForInit(): Promise<SessionAttributes> {\n try {\n return (await loadMobileMetaForInit()).sessionAttributes;\n } catch {\n return minimalSessionDeviceAttributes();\n }\n}\n"]}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.getMetroInjectedBundleId = getMetroInjectedBundleId;
43
+ exports.formatSymbolsBundleId = formatSymbolsBundleId;
44
+ exports.loadAppSymbolsBundleIdForInit = loadAppSymbolsBundleIdForInit;
45
+ var react_native_device_info_1 = __importDefault(require("react-native-device-info"));
46
+ var faro_core_1 = require("@grafana/faro-core");
47
+ var BUNDLE_ID_SEPARATOR = '@';
48
+ /** Metro / webpack preamble bundle id for JS source maps (`__faroBundleId_<appName>`). */
49
+ function getMetroInjectedBundleId(appName) {
50
+ if (!appName) {
51
+ return undefined;
52
+ }
53
+ var key = "__faroBundleId_".concat(appName);
54
+ var fromGlobal = faro_core_1.globalObject[key];
55
+ if (typeof fromGlobal === 'string' && fromGlobal !== '') {
56
+ return fromGlobal;
57
+ }
58
+ return undefined;
59
+ }
60
+ /**
61
+ * Encodes the Android/iOS build identity used as `meta.app.bundleId` for
62
+ * server-side symbol retrace. Must match the symbols upload bundle id
63
+ * (`{applicationId}@{versionCode}@{versionName}`).
64
+ */
65
+ function formatSymbolsBundleId(applicationId, versionCode, versionName) {
66
+ return "".concat(applicationId).concat(BUNDLE_ID_SEPARATOR).concat(versionCode).concat(BUNDLE_ID_SEPARATOR).concat(versionName);
67
+ }
68
+ /**
69
+ * Reads the installed build's identity from `react-native-device-info` and
70
+ * returns the encoded bundle id when all parts are available.
71
+ *
72
+ * Values must match what the symbol uploader (Gradle plugin / faro-cli) sends
73
+ * for the same build so the collector can locate the mapping for retrace.
74
+ */
75
+ function loadAppSymbolsBundleIdForInit() {
76
+ return __awaiter(this, void 0, void 0, function () {
77
+ var applicationId, versionName, versionCodeRaw;
78
+ return __generator(this, function (_a) {
79
+ try {
80
+ applicationId = react_native_device_info_1.default.getBundleId();
81
+ versionName = react_native_device_info_1.default.getVersion();
82
+ versionCodeRaw = react_native_device_info_1.default.getBuildNumber();
83
+ if (!applicationId || versionCodeRaw === '' || versionCodeRaw == null || !versionName) {
84
+ return [2 /*return*/, undefined];
85
+ }
86
+ return [2 /*return*/, formatSymbolsBundleId(applicationId, String(versionCodeRaw), versionName)];
87
+ }
88
+ catch (_b) {
89
+ return [2 /*return*/, undefined];
90
+ }
91
+ return [2 /*return*/];
92
+ });
93
+ });
94
+ }
95
+ //# sourceMappingURL=appBuildIdentity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appBuildIdentity.js","sourceRoot":"","sources":["../../../src/metas/appBuildIdentity.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,4DAUC;AAOD,sDAEC;AASD,sEAcC;AAjDD,sFAAkD;AAElD,gDAAkD;AAElD,IAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,0FAA0F;AAC1F,SAAgB,wBAAwB,CAAC,OAA2B;IAClE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAM,GAAG,GAAG,yBAAkB,OAAO,CAAE,CAAC;IACxC,IAAM,UAAU,GAAI,wBAAwC,CAAC,GAAG,CAAC,CAAC;IAClE,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACxD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,SAAgB,qBAAqB,CAAC,aAAqB,EAAE,WAAmB,EAAE,WAAmB;IACnG,OAAO,UAAG,aAAa,SAAG,mBAAmB,SAAG,WAAW,SAAG,mBAAmB,SAAG,WAAW,CAAE,CAAC;AACpG,CAAC;AAED;;;;;;GAMG;AACH,SAAsB,6BAA6B;;;;YACjD,IAAI,CAAC;gBACG,aAAa,GAAG,kCAAU,CAAC,WAAW,EAAE,CAAC;gBACzC,WAAW,GAAG,kCAAU,CAAC,UAAU,EAAE,CAAC;gBACtC,cAAc,GAAG,kCAAU,CAAC,cAAc,EAAE,CAAC;gBAEnD,IAAI,CAAC,aAAa,IAAI,cAAc,KAAK,EAAE,IAAI,cAAc,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACtF,sBAAO,SAAS,EAAC;gBACnB,CAAC;gBAED,sBAAO,qBAAqB,CAAC,aAAa,EAAE,MAAM,CAAC,cAAc,CAAC,EAAE,WAAW,CAAC,EAAC;YACnF,CAAC;YAAC,WAAM,CAAC;gBACP,sBAAO,SAAS,EAAC;YACnB,CAAC;;;;CACF","sourcesContent":["import DeviceInfo from 'react-native-device-info';\n\nimport { globalObject } from '@grafana/faro-core';\n\nconst BUNDLE_ID_SEPARATOR = '@';\n\n/** Metro / webpack preamble bundle id for JS source maps (`__faroBundleId_<appName>`). */\nexport function getMetroInjectedBundleId(appName: string | undefined): string | undefined {\n if (!appName) {\n return undefined;\n }\n const key = `__faroBundleId_${appName}`;\n const fromGlobal = (globalObject as Record<string, unknown>)[key];\n if (typeof fromGlobal === 'string' && fromGlobal !== '') {\n return fromGlobal;\n }\n return undefined;\n}\n\n/**\n * Encodes the Android/iOS build identity used as `meta.app.bundleId` for\n * server-side symbol retrace. Must match the symbols upload bundle id\n * (`{applicationId}@{versionCode}@{versionName}`).\n */\nexport function formatSymbolsBundleId(applicationId: string, versionCode: string, versionName: string): string {\n return `${applicationId}${BUNDLE_ID_SEPARATOR}${versionCode}${BUNDLE_ID_SEPARATOR}${versionName}`;\n}\n\n/**\n * Reads the installed build's identity from `react-native-device-info` and\n * returns the encoded bundle id when all parts are available.\n *\n * Values must match what the symbol uploader (Gradle plugin / faro-cli) sends\n * for the same build so the collector can locate the mapping for retrace.\n */\nexport async function loadAppSymbolsBundleIdForInit(): Promise<string | undefined> {\n try {\n const applicationId = DeviceInfo.getBundleId();\n const versionName = DeviceInfo.getVersion();\n const versionCodeRaw = DeviceInfo.getBuildNumber();\n\n if (!applicationId || versionCodeRaw === '' || versionCodeRaw == null || !versionName) {\n return undefined;\n }\n\n return formatSymbolsBundleId(applicationId, String(versionCodeRaw), versionName);\n } catch {\n return undefined;\n }\n}\n"]}
@@ -9,10 +9,15 @@ function mockDeviceInfo() {
9
9
  default: {
10
10
  getBrand: jest.fn(function () { return 'Apple'; }),
11
11
  getDeviceId: jest.fn(function () { return 'iPhone14,2'; }),
12
+ getDeviceNameSync: jest.fn(function () { return "Test's iPhone"; }),
13
+ getUniqueId: jest.fn(function () { return Promise.resolve('test-device-id'); }),
12
14
  getModel: jest.fn(function () { return 'iPhone 13 Pro'; }),
15
+ getManufacturerSync: jest.fn(function () { return 'Apple'; }),
13
16
  getSystemName: jest.fn(function () { return 'iOS'; }),
14
17
  getSystemVersion: jest.fn(function () { return '16.0'; }),
15
18
  getVersion: jest.fn(function () { return '1.0.0'; }),
19
+ getApiLevel: jest.fn(function () { return Promise.resolve(35); }),
20
+ getBuildId: jest.fn(function () { return Promise.resolve('22B83'); }),
16
21
  isTablet: jest.fn(function () { return false; }),
17
22
  isEmulatorSync: jest.fn(function () { return false; }),
18
23
  getTotalMemorySync: jest.fn(function () { return 6442450944; }), // 6GB in bytes
@@ -1 +1 @@
1
- {"version":3,"file":"mockDeviceInfo.js","sourceRoot":"","sources":["../../../src/testUtils/mockDeviceInfo.ts"],"names":[],"mappings":";;AAGA,wCAmBC;AAtBD;;GAEG;AACH,SAAgB,cAAc;IAC5B,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,cAAM,OAAA,CAAC;QAC3C,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAChC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,YAAY,EAAZ,CAAY,CAAC;YACxC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,eAAe,EAAf,CAAe,CAAC;YACxC,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YACnC,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,MAAM,EAAN,CAAM,CAAC;YACvC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAClC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YAC9B,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YACpC,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,UAAU,EAAV,CAAU,CAAC,EAAE,eAAe;YAC9D,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,UAAU,EAAV,CAAU,CAAC,EAAE,eAAe;YAC7D,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAArB,CAAqB,CAAC;YACrD,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAA3B,CAA2B,CAAC;YACtD,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAtB,CAAsB,CAAC;YACtD,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAtB,CAAsB,CAAC;SACzD;KACF,CAAC,EAjB0C,CAiB1C,CAAC,CAAC;AACN,CAAC","sourcesContent":["/**\n * Mock react-native-device-info for testing\n */\nexport function mockDeviceInfo(): void {\n jest.mock('react-native-device-info', () => ({\n default: {\n getBrand: jest.fn(() => 'Apple'),\n getDeviceId: jest.fn(() => 'iPhone14,2'),\n getModel: jest.fn(() => 'iPhone 13 Pro'),\n getSystemName: jest.fn(() => 'iOS'),\n getSystemVersion: jest.fn(() => '16.0'),\n getVersion: jest.fn(() => '1.0.0'),\n isTablet: jest.fn(() => false),\n isEmulatorSync: jest.fn(() => false),\n getTotalMemorySync: jest.fn(() => 6442450944), // 6GB in bytes\n getUsedMemorySync: jest.fn(() => 2147483648), // 2GB in bytes\n getBatteryLevel: jest.fn(() => Promise.resolve(0.75)),\n getCarrier: jest.fn(() => Promise.resolve('T-Mobile')),\n isPowerSaveMode: jest.fn(() => Promise.resolve(false)),\n isBatteryCharging: jest.fn(() => Promise.resolve(false)),\n },\n }));\n}\n"]}
1
+ {"version":3,"file":"mockDeviceInfo.js","sourceRoot":"","sources":["../../../src/testUtils/mockDeviceInfo.ts"],"names":[],"mappings":";;AAGA,wCAwBC;AA3BD;;GAEG;AACH,SAAgB,cAAc;IAC5B,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,cAAM,OAAA,CAAC;QAC3C,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAChC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,YAAY,EAAZ,CAAY,CAAC;YACxC,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,eAAe,EAAf,CAAe,CAAC;YACjD,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAjC,CAAiC,CAAC;YAC7D,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,eAAe,EAAf,CAAe,CAAC;YACxC,mBAAmB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAC3C,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YACnC,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,MAAM,EAAN,CAAM,CAAC;YACvC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAClC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAnB,CAAmB,CAAC;YAC/C,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAxB,CAAwB,CAAC;YACnD,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YAC9B,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YACpC,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,UAAU,EAAV,CAAU,CAAC,EAAE,eAAe;YAC9D,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,UAAU,EAAV,CAAU,CAAC,EAAE,eAAe;YAC7D,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAArB,CAAqB,CAAC;YACrD,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAA3B,CAA2B,CAAC;YACtD,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAtB,CAAsB,CAAC;YACtD,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAtB,CAAsB,CAAC;SACzD;KACF,CAAC,EAtB0C,CAsB1C,CAAC,CAAC;AACN,CAAC","sourcesContent":["/**\n * Mock react-native-device-info for testing\n */\nexport function mockDeviceInfo(): void {\n jest.mock('react-native-device-info', () => ({\n default: {\n getBrand: jest.fn(() => 'Apple'),\n getDeviceId: jest.fn(() => 'iPhone14,2'),\n getDeviceNameSync: jest.fn(() => \"Test's iPhone\"),\n getUniqueId: jest.fn(() => Promise.resolve('test-device-id')),\n getModel: jest.fn(() => 'iPhone 13 Pro'),\n getManufacturerSync: jest.fn(() => 'Apple'),\n getSystemName: jest.fn(() => 'iOS'),\n getSystemVersion: jest.fn(() => '16.0'),\n getVersion: jest.fn(() => '1.0.0'),\n getApiLevel: jest.fn(() => Promise.resolve(35)),\n getBuildId: jest.fn(() => Promise.resolve('22B83')),\n isTablet: jest.fn(() => false),\n isEmulatorSync: jest.fn(() => false),\n getTotalMemorySync: jest.fn(() => 6442450944), // 6GB in bytes\n getUsedMemorySync: jest.fn(() => 2147483648), // 2GB in bytes\n getBatteryLevel: jest.fn(() => Promise.resolve(0.75)),\n getCarrier: jest.fn(() => Promise.resolve('T-Mobile')),\n isPowerSaveMode: jest.fn(() => Promise.resolve(false)),\n isBatteryCharging: jest.fn(() => Promise.resolve(false)),\n },\n }));\n}\n"]}
@@ -19,10 +19,17 @@ jest.mock('react-native-device-info', function () {
19
19
  var mockDeviceInfo = {
20
20
  getBrand: jest.fn(function () { return 'Apple'; }),
21
21
  getDeviceId: jest.fn(function () { return 'iPhone14,2'; }),
22
+ getDeviceNameSync: jest.fn(function () { return "Test's iPhone"; }),
23
+ getUniqueId: jest.fn(function () { return Promise.resolve('test-device-id'); }),
22
24
  getModel: jest.fn(function () { return 'iPhone 13 Pro'; }),
25
+ getManufacturerSync: jest.fn(function () { return 'Apple'; }),
23
26
  getSystemName: jest.fn(function () { return 'iOS'; }),
24
27
  getSystemVersion: jest.fn(function () { return '16.0'; }),
25
28
  getVersion: jest.fn(function () { return '1.0.0'; }),
29
+ getBundleId: jest.fn(function () { return 'com.example.myapp'; }),
30
+ getBuildNumber: jest.fn(function () { return '42'; }),
31
+ getApiLevel: jest.fn(function () { return Promise.resolve(35); }),
32
+ getBuildId: jest.fn(function () { return Promise.resolve('22B83'); }),
26
33
  isTablet: jest.fn(function () { return false; }),
27
34
  isEmulatorSync: jest.fn(function () { return false; }),
28
35
  getTotalMemorySync: jest.fn(function () { return 6442450944; }), // 6GB in bytes