@grafana/faro-react-native 1.3.0 → 1.4.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 (266) hide show
  1. package/README.md +176 -30
  2. package/android/build.gradle +20 -15
  3. package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashIds.kt +44 -0
  4. package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashReporter.kt +134 -38
  5. package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashSessionStore.kt +433 -0
  6. package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashTraceCache.kt +11 -2
  7. package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativeModule.kt +128 -17
  8. package/android/src/main/java/com/grafana/faro/reactnative/FaroSessionProcess.kt +88 -0
  9. package/android/src/main/java/com/grafana/faro/reactnative/FrameMonitor.kt +34 -42
  10. package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashReporterBelowApi30Test.kt +21 -0
  11. package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashReporterTest.kt +59 -0
  12. package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashSessionStoreTest.kt +268 -0
  13. package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashTraceCacheTest.kt +52 -0
  14. package/android/src/test/java/com/grafana/faro/reactnative/FaroSessionProcessTest.kt +127 -0
  15. package/dist/cjs/config/getRNInstrumentations.js +6 -8
  16. package/dist/cjs/config/getRNInstrumentations.js.map +1 -1
  17. package/dist/cjs/config/sampling.js.map +1 -1
  18. package/dist/cjs/config/types.js.map +1 -1
  19. package/dist/cjs/dataCollection/DataCollectionPolicy.js +1 -2
  20. package/dist/cjs/dataCollection/DataCollectionPolicy.js.map +1 -1
  21. package/dist/cjs/generated/faroRNPackageMeta.js +1 -1
  22. package/dist/cjs/generated/faroRNPackageMeta.js.map +1 -1
  23. package/dist/cjs/index.js +8 -3
  24. package/dist/cjs/index.js.map +1 -1
  25. package/dist/cjs/instrumentations/anr/instrumentation.js +10 -1
  26. package/dist/cjs/instrumentations/anr/instrumentation.js.map +1 -1
  27. package/dist/cjs/instrumentations/appState/index.js +8 -2
  28. package/dist/cjs/instrumentations/appState/index.js.map +1 -1
  29. package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +19 -6
  30. package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
  31. package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +331 -0
  32. package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
  33. package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
  34. package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
  35. package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
  36. package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
  37. package/dist/cjs/instrumentations/crashReporting/types.js.map +1 -1
  38. package/dist/cjs/instrumentations/errors/index.js +8 -3
  39. package/dist/cjs/instrumentations/errors/index.js.map +1 -1
  40. package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js +20 -31
  41. package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
  42. package/dist/cjs/instrumentations/frameMonitoring/types.js.map +1 -1
  43. package/dist/cjs/instrumentations/performance/index.js +2 -6
  44. package/dist/cjs/instrumentations/performance/index.js.map +1 -1
  45. package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js +48 -0
  46. package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
  47. package/dist/cjs/instrumentations/session/directSessionActivity.js +37 -0
  48. package/dist/cjs/instrumentations/session/directSessionActivity.js.map +1 -0
  49. package/dist/cjs/instrumentations/session/index.js +214 -45
  50. package/dist/cjs/instrumentations/session/index.js.map +1 -1
  51. package/dist/cjs/instrumentations/session/sessionActivity.js +43 -0
  52. package/dist/cjs/instrumentations/session/sessionActivity.js.map +1 -0
  53. package/dist/cjs/instrumentations/session/sessionAttributes.js +8 -8
  54. package/dist/cjs/instrumentations/session/sessionAttributes.js.map +1 -1
  55. package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +199 -24
  56. package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
  57. package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -13
  58. package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
  59. package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js +72 -0
  60. package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
  61. package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js +1 -1
  62. package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
  63. package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js +124 -96
  64. package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
  65. package/dist/cjs/instrumentations/session/sessionManager/types.js.map +1 -1
  66. package/dist/cjs/instrumentations/session/sessionProcess.js +96 -0
  67. package/dist/cjs/instrumentations/session/sessionProcess.js.map +1 -0
  68. package/dist/cjs/instrumentations/startup/index.js +2 -6
  69. package/dist/cjs/instrumentations/startup/index.js.map +1 -1
  70. package/dist/cjs/navigation/utils.js +3 -1
  71. package/dist/cjs/navigation/utils.js.map +1 -1
  72. package/dist/cjs/transports/fetch/index.js.map +1 -1
  73. package/dist/cjs/transports/fetch/transport.js +56 -25
  74. package/dist/cjs/transports/fetch/transport.js.map +1 -1
  75. package/dist/cjs/transports/fetch/types.js.map +1 -1
  76. package/dist/cjs/transports/offline/ConnectivityService.js +1 -1
  77. package/dist/cjs/transports/offline/ConnectivityService.js.map +1 -1
  78. package/dist/cjs/transports/offline/OfflineCache.js +2 -2
  79. package/dist/cjs/transports/offline/OfflineCache.js.map +1 -1
  80. package/dist/cjs/transports/offline/transport.js +3 -4
  81. package/dist/cjs/transports/offline/transport.js.map +1 -1
  82. package/dist/cjs/userPersistence/UserPersistence.js +1 -2
  83. package/dist/cjs/userPersistence/UserPersistence.js.map +1 -1
  84. package/dist/esm/config/getRNInstrumentations.js +6 -8
  85. package/dist/esm/config/getRNInstrumentations.js.map +1 -1
  86. package/dist/esm/config/sampling.js.map +1 -1
  87. package/dist/esm/config/types.js.map +1 -1
  88. package/dist/esm/dataCollection/DataCollectionPolicy.js +1 -2
  89. package/dist/esm/dataCollection/DataCollectionPolicy.js.map +1 -1
  90. package/dist/esm/generated/faroRNPackageMeta.js +1 -1
  91. package/dist/esm/generated/faroRNPackageMeta.js.map +1 -1
  92. package/dist/esm/index.js +4 -2
  93. package/dist/esm/index.js.map +1 -1
  94. package/dist/esm/instrumentations/anr/instrumentation.js +6 -1
  95. package/dist/esm/instrumentations/anr/instrumentation.js.map +1 -1
  96. package/dist/esm/instrumentations/appState/index.js +8 -2
  97. package/dist/esm/instrumentations/appState/index.js.map +1 -1
  98. package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +15 -4
  99. package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
  100. package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +230 -0
  101. package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
  102. package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
  103. package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
  104. package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
  105. package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
  106. package/dist/esm/instrumentations/crashReporting/types.js.map +1 -1
  107. package/dist/esm/instrumentations/errors/index.js +8 -3
  108. package/dist/esm/instrumentations/errors/index.js.map +1 -1
  109. package/dist/esm/instrumentations/frameMonitoring/instrumentation.js +17 -32
  110. package/dist/esm/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
  111. package/dist/esm/instrumentations/frameMonitoring/types.js.map +1 -1
  112. package/dist/esm/instrumentations/performance/index.js +2 -6
  113. package/dist/esm/instrumentations/performance/index.js.map +1 -1
  114. package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js +34 -0
  115. package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
  116. package/dist/esm/instrumentations/session/directSessionActivity.js +32 -0
  117. package/dist/esm/instrumentations/session/directSessionActivity.js.map +1 -0
  118. package/dist/esm/instrumentations/session/index.js +207 -46
  119. package/dist/esm/instrumentations/session/index.js.map +1 -1
  120. package/dist/esm/instrumentations/session/sessionActivity.js +38 -0
  121. package/dist/esm/instrumentations/session/sessionActivity.js.map +1 -0
  122. package/dist/esm/instrumentations/session/sessionAttributes.js +7 -7
  123. package/dist/esm/instrumentations/session/sessionAttributes.js.map +1 -1
  124. package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +190 -27
  125. package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
  126. package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -14
  127. package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
  128. package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js +56 -0
  129. package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
  130. package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js +1 -1
  131. package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
  132. package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js +120 -44
  133. package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
  134. package/dist/esm/instrumentations/session/sessionManager/types.js.map +1 -1
  135. package/dist/esm/instrumentations/session/sessionProcess.js +89 -0
  136. package/dist/esm/instrumentations/session/sessionProcess.js.map +1 -0
  137. package/dist/esm/instrumentations/startup/index.js +2 -6
  138. package/dist/esm/instrumentations/startup/index.js.map +1 -1
  139. package/dist/esm/navigation/utils.js +2 -1
  140. package/dist/esm/navigation/utils.js.map +1 -1
  141. package/dist/esm/transports/fetch/index.js.map +1 -1
  142. package/dist/esm/transports/fetch/transport.js +38 -14
  143. package/dist/esm/transports/fetch/transport.js.map +1 -1
  144. package/dist/esm/transports/fetch/types.js.map +1 -1
  145. package/dist/esm/transports/offline/ConnectivityService.js +1 -1
  146. package/dist/esm/transports/offline/ConnectivityService.js.map +1 -1
  147. package/dist/esm/transports/offline/OfflineCache.js +2 -2
  148. package/dist/esm/transports/offline/OfflineCache.js.map +1 -1
  149. package/dist/esm/transports/offline/transport.js +3 -4
  150. package/dist/esm/transports/offline/transport.js.map +1 -1
  151. package/dist/esm/userPersistence/UserPersistence.js +1 -2
  152. package/dist/esm/userPersistence/UserPersistence.js.map +1 -1
  153. package/dist/types/config/getRNInstrumentations.d.ts +1 -2
  154. package/dist/types/config/sampling.d.ts +0 -3
  155. package/dist/types/config/types.d.ts +5 -3
  156. package/dist/types/dataCollection/DataCollectionPolicy.d.ts +1 -2
  157. package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
  158. package/dist/types/index.d.ts +4 -1
  159. package/dist/types/instrumentations/anr/instrumentation.d.ts +1 -1
  160. package/dist/types/instrumentations/appState/index.d.ts +1 -1
  161. package/dist/types/instrumentations/console/index.d.ts +1 -1
  162. package/dist/types/instrumentations/crashReporting/BaseCrashReportingInstrumentation.d.ts +14 -4
  163. package/dist/types/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.d.ts +1 -1
  164. package/dist/types/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.d.ts +27 -0
  165. package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +3 -3
  166. package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +3 -3
  167. package/dist/types/instrumentations/crashReporting/types.d.ts +6 -0
  168. package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +3 -3
  169. package/dist/types/instrumentations/frameMonitoring/types.d.ts +4 -6
  170. package/dist/types/instrumentations/http/index.d.ts +1 -1
  171. package/dist/types/instrumentations/performance/index.d.ts +1 -3
  172. package/dist/types/instrumentations/session/FaroSessionActivityBoundary.d.ts +8 -0
  173. package/dist/types/instrumentations/session/directSessionActivity.d.ts +13 -0
  174. package/dist/types/instrumentations/session/index.d.ts +21 -2
  175. package/dist/types/instrumentations/session/sessionActivity.d.ts +9 -0
  176. package/dist/types/instrumentations/session/sessionAttributes.d.ts +6 -3
  177. package/dist/types/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.d.ts +16 -3
  178. package/dist/types/instrumentations/session/sessionManager/VolatileSessionManager.d.ts +9 -3
  179. package/dist/types/instrumentations/session/sessionManager/persistentSessionRecord.d.ts +4 -0
  180. package/dist/types/instrumentations/session/sessionManager/sessionManagerUtils.d.ts +19 -7
  181. package/dist/types/instrumentations/session/sessionManager/types.d.ts +6 -0
  182. package/dist/types/instrumentations/session/sessionProcess.d.ts +17 -0
  183. package/dist/types/instrumentations/startup/index.d.ts +3 -7
  184. package/dist/types/instrumentations/userActions/index.d.ts +1 -1
  185. package/dist/types/instrumentations/view/index.d.ts +1 -1
  186. package/dist/types/instrumentations/xhr/index.d.ts +1 -1
  187. package/dist/types/navigation/utils.d.ts +1 -0
  188. package/dist/types/testUtils/mockFaroReactNativeTracing.d.ts +1 -1
  189. package/dist/types/transports/console/transport.d.ts +1 -1
  190. package/dist/types/transports/fetch/index.d.ts +1 -1
  191. package/dist/types/transports/fetch/transport.d.ts +9 -2
  192. package/dist/types/transports/fetch/types.d.ts +5 -0
  193. package/dist/types/transports/offline/ConnectivityService.d.ts +1 -1
  194. package/dist/types/transports/offline/OfflineCache.d.ts +2 -2
  195. package/dist/types/transports/offline/transport.d.ts +4 -5
  196. package/dist/types/userPersistence/UserPersistence.d.ts +1 -2
  197. package/ios/FaroCrashReporter.swift +214 -21
  198. package/ios/FaroReactNative.swift +24 -0
  199. package/ios/FaroReactNativeModule.h +2 -1
  200. package/ios/FaroReactNativeModule.mm +121 -6
  201. package/ios/RefreshRateVitals.swift +34 -38
  202. package/package.json +8 -6
  203. package/src/config/getRNInstrumentations.ts +6 -8
  204. package/src/config/makeRNConfig.test.ts +6 -0
  205. package/src/config/sampling.ts +0 -3
  206. package/src/config/types.ts +5 -3
  207. package/src/dataCollection/DataCollectionPolicy.ts +1 -2
  208. package/src/generated/faroRNPackageMeta.ts +1 -1
  209. package/src/index.ts +8 -2
  210. package/src/instrumentations/anr/instrumentation.ts +8 -1
  211. package/src/instrumentations/appState/index.ts +10 -2
  212. package/src/instrumentations/crashReporting/BaseCrashReportingInstrumentation.ts +28 -8
  213. package/src/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.ts +277 -0
  214. package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +2 -2
  215. package/src/instrumentations/crashReporting/instrumentation.test.ts +433 -5
  216. package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +2 -2
  217. package/src/instrumentations/crashReporting/types.ts +7 -0
  218. package/src/instrumentations/errors/index.ts +12 -4
  219. package/src/instrumentations/errors/instrumentation.test.ts +35 -0
  220. package/src/instrumentations/frameMonitoring/instrumentation.test.ts +155 -0
  221. package/src/instrumentations/frameMonitoring/instrumentation.ts +19 -38
  222. package/src/instrumentations/frameMonitoring/types.ts +4 -6
  223. package/src/instrumentations/performance/index.ts +2 -6
  224. package/src/instrumentations/session/FaroSessionActivityBoundary.test.ts +60 -0
  225. package/src/instrumentations/session/FaroSessionActivityBoundary.tsx +41 -0
  226. package/src/instrumentations/session/beforeSendHook.test.ts +246 -0
  227. package/src/instrumentations/session/directSessionActivity.test.ts +158 -0
  228. package/src/instrumentations/session/directSessionActivity.ts +36 -0
  229. package/src/instrumentations/session/index.ts +269 -46
  230. package/src/instrumentations/session/persistentColdStart.test.ts +196 -0
  231. package/src/instrumentations/session/sessionActivity.test.ts +68 -0
  232. package/src/instrumentations/session/sessionActivity.ts +58 -0
  233. package/src/instrumentations/session/sessionAttributes.test.ts +37 -2
  234. package/src/instrumentations/session/sessionAttributes.ts +12 -6
  235. package/src/instrumentations/session/sessionCleanup.test.ts +410 -0
  236. package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.test.ts +552 -0
  237. package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.ts +249 -33
  238. package/src/instrumentations/session/sessionManager/VolatileSessionManager.ts +38 -18
  239. package/src/instrumentations/session/sessionManager/persistentSessionRecord.test.ts +103 -0
  240. package/src/instrumentations/session/sessionManager/persistentSessionRecord.ts +78 -0
  241. package/src/instrumentations/session/sessionManager/sampling.test.ts +1 -1
  242. package/src/instrumentations/session/sessionManager/sessionConstants.ts +1 -1
  243. package/src/instrumentations/session/sessionManager/sessionManagerUtils.test.ts +256 -18
  244. package/src/instrumentations/session/sessionManager/sessionManagerUtils.ts +180 -39
  245. package/src/instrumentations/session/sessionManager/types.ts +8 -0
  246. package/src/instrumentations/session/sessionManagerInstance.test.ts +65 -0
  247. package/src/instrumentations/session/sessionProcess.test.ts +136 -0
  248. package/src/instrumentations/session/sessionProcess.ts +114 -0
  249. package/src/instrumentations/session/startNewSession.test.ts +337 -0
  250. package/src/instrumentations/startup/index.ts +2 -6
  251. package/src/navigation/utils.ts +3 -1
  252. package/src/transports/fetch/index.ts +6 -1
  253. package/src/transports/fetch/transport.test.ts +86 -2
  254. package/src/transports/fetch/transport.ts +38 -16
  255. package/src/transports/fetch/types.ts +7 -0
  256. package/src/transports/offline/ConnectivityService.ts +1 -1
  257. package/src/transports/offline/OfflineCache.ts +2 -2
  258. package/src/transports/offline/transport.ts +3 -4
  259. package/src/userPersistence/UserPersistence.ts +1 -2
  260. package/dist/cjs/utils/throttle.js +0 -42
  261. package/dist/cjs/utils/throttle.js.map +0 -1
  262. package/dist/esm/utils/throttle.js +0 -34
  263. package/dist/esm/utils/throttle.js.map +0 -1
  264. package/dist/types/utils/throttle.d.ts +0 -9
  265. package/src/utils/throttle.test.ts +0 -141
  266. package/src/utils/throttle.ts +0 -34
@@ -27,11 +27,78 @@ var __assign = (this && this.__assign) || function () {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.SessionInstrumentation = void 0;
30
+ exports.startNewSession = startNewSession;
30
31
  var faro_core_1 = require("@grafana/faro-core");
32
+ var directSessionActivity_1 = require("./directSessionActivity");
33
+ var sessionActivity_1 = require("./sessionActivity");
31
34
  var sessionAttributes_1 = require("./sessionAttributes");
32
35
  var sessionManager_1 = require("./sessionManager");
33
36
  var sessionConstants_1 = require("./sessionManager/sessionConstants");
34
37
  var sessionManagerUtils_1 = require("./sessionManager/sessionManagerUtils");
38
+ var SESSION_INSTRUMENTATION_NAME = '@grafana/faro-react-native:instrumentation-session';
39
+ // Track the current session hook per transport so superseded hooks yield to a
40
+ // replacement. The shared fallback preserves sampling decisions captured on
41
+ // queued items after the owning instrumentation has detached.
42
+ var activeSessionBeforeSendHooks = new WeakMap();
43
+ var sessionSamplingFallbackHooks = new WeakMap();
44
+ function applySessionSampling(item, fallbackSamplingDecision) {
45
+ var _a, _b, _c, _d;
46
+ var attributes = (_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.attributes;
47
+ var samplingAttribute = (_b = attributes === null || attributes === void 0 ? void 0 : attributes['isSampled']) !== null && _b !== void 0 ? _b : fallbackSamplingDecision === null || fallbackSamplingDecision === void 0 ? void 0 : fallbackSamplingDecision.toString();
48
+ if (samplingAttribute === 'false') {
49
+ return null;
50
+ }
51
+ if (samplingAttribute !== 'true') {
52
+ return item;
53
+ }
54
+ var sampledItem = __assign(__assign({}, item), { meta: __assign(__assign({}, item.meta), { session: item.meta.session
55
+ ? __assign(__assign({}, item.meta.session), { attributes: item.meta.session.attributes ? __assign({}, item.meta.session.attributes) : undefined }) : undefined }) });
56
+ var sampledAttributes = (_c = sampledItem.meta.session) === null || _c === void 0 ? void 0 : _c.attributes;
57
+ sampledAttributes === null || sampledAttributes === void 0 ? true : delete sampledAttributes['isSampled'];
58
+ if (Object.keys(sampledAttributes !== null && sampledAttributes !== void 0 ? sampledAttributes : {}).length === 0) {
59
+ (_d = sampledItem.meta.session) === null || _d === void 0 ? true : delete _d.attributes;
60
+ }
61
+ return sampledItem;
62
+ }
63
+ function ensureSessionSamplingFallback(transports) {
64
+ if (sessionSamplingFallbackHooks.has(transports)) {
65
+ return;
66
+ }
67
+ var fallbackHook = function (item) {
68
+ return activeSessionBeforeSendHooks.has(transports) ? item : applySessionSampling(item);
69
+ };
70
+ transports.addBeforeSendHooks(fallbackHook);
71
+ sessionSamplingFallbackHooks.set(transports, fallbackHook);
72
+ }
73
+ function removeInternalSamplingAttribute(session) {
74
+ var _a;
75
+ if (((_a = session === null || session === void 0 ? void 0 : session.attributes) === null || _a === void 0 ? void 0 : _a['isSampled']) == null) {
76
+ return session;
77
+ }
78
+ var attributes = __assign({}, session.attributes);
79
+ delete attributes['isSampled'];
80
+ return __assign(__assign({}, session), { attributes: Object.keys(attributes).length === 0 ? undefined : attributes });
81
+ }
82
+ /**
83
+ * Starts a new linked session at an application-defined boundary.
84
+ *
85
+ * Call this after changing or clearing the current user for logout, account
86
+ * changes, or another boundary that must not share a session. Calls made
87
+ * before Faro initializes, after teardown, or while session tracking is
88
+ * disabled have no effect.
89
+ */
90
+ function startNewSession() {
91
+ var _a;
92
+ var instrumentation = (_a = faro_core_1.faro === null || faro_core_1.faro === void 0 ? void 0 : faro_core_1.faro.instrumentations) === null || _a === void 0 ? void 0 : _a.instrumentations.find(function (_a) {
93
+ var name = _a.name;
94
+ return name === SESSION_INSTRUMENTATION_NAME;
95
+ });
96
+ if (instrumentation != null &&
97
+ 'startNewSession' in instrumentation &&
98
+ typeof instrumentation.startNewSession === 'function') {
99
+ instrumentation.startNewSession();
100
+ }
101
+ }
35
102
  /**
36
103
  * Session instrumentation for React Native
37
104
  * Manages persistent or volatile sessions with expiration and inactivity tracking
@@ -40,8 +107,19 @@ var SessionInstrumentation = /** @class */ (function (_super) {
40
107
  __extends(SessionInstrumentation, _super);
41
108
  function SessionInstrumentation() {
42
109
  var _this = _super !== null && _super.apply(this, arguments) || this;
43
- _this.name = '@grafana/faro-react-native:instrumentation-session';
110
+ _this.name = SESSION_INSTRUMENTATION_NAME;
44
111
  _this.version = faro_core_1.VERSION;
112
+ _this.isResettingSession = false;
113
+ _this.sendSessionStartEvent = function (meta) {
114
+ var _a;
115
+ var session = meta.session;
116
+ if (session && session.id !== ((_a = _this.notifiedSession) === null || _a === void 0 ? void 0 : _a.id)) {
117
+ _this.notifiedSession = session;
118
+ // no need to add attributes and session id, they are included as part of meta
119
+ // automatically
120
+ _this.api.pushEvent(faro_core_1.EVENT_SESSION_START, {}, undefined, { skipDedupe: true });
121
+ }
122
+ };
45
123
  return _this;
46
124
  }
47
125
  SessionInstrumentation.prototype.getDefaultSessionDeviceAttributes = function () {
@@ -51,24 +129,20 @@ var SessionInstrumentation = /** @class */ (function (_super) {
51
129
  }
52
130
  return (0, sessionAttributes_1.minimalSessionDeviceAttributes)();
53
131
  };
54
- SessionInstrumentation.prototype.sendSessionStartEvent = function (meta) {
55
- var _a;
56
- var session = meta.session;
57
- if (session && session.id !== ((_a = this.notifiedSession) === null || _a === void 0 ? void 0 : _a.id)) {
58
- this.notifiedSession = session;
59
- // no need to add attributes and session id, they are included as part of meta
60
- // automatically
61
- this.api.pushEvent(faro_core_1.EVENT_SESSION_START, {}, undefined, { skipDedupe: true });
62
- }
132
+ SessionInstrumentation.prototype.registerSessionMetaListener = function () {
133
+ this.metas.addListener(this.sendSessionStartEvent);
134
+ this.sessionMetaListenerMetas = this.metas;
63
135
  };
64
136
  SessionInstrumentation.prototype.createInitialSession = function (SessionManagerClass, sessionsConfig) {
65
- var _a, _b, _c, _d, _e, _f, _g;
137
+ var _a, _b, _c, _d, _e, _f;
66
138
  var storedUserSession = SessionManagerClass.fetchUserSession();
67
139
  var sessionsConfigTyped = sessionsConfig;
68
140
  var maxPersistenceMs = (_a = sessionsConfigTyped.maxSessionPersistenceTime) !== null && _a !== void 0 ? _a : sessionConstants_1.MAX_SESSION_PERSISTENCE_TIME;
69
141
  if (sessionsConfig.persistent && storedUserSession) {
70
142
  var now = (0, faro_core_1.dateNow)();
71
- var shouldClearPersistentSession = storedUserSession.lastActivity < now - maxPersistenceMs;
143
+ var shouldClearPersistentSession = storedUserSession.started > now ||
144
+ storedUserSession.lastActivity > now ||
145
+ storedUserSession.lastActivity <= now - maxPersistenceMs;
72
146
  if (shouldClearPersistentSession) {
73
147
  SessionManagerClass.removeUserSession();
74
148
  storedUserSession = null;
@@ -77,7 +151,7 @@ var SessionInstrumentation = /** @class */ (function (_super) {
77
151
  var defaultAttributes = this.getDefaultSessionDeviceAttributes();
78
152
  var emitSessionStartOnInit;
79
153
  var initialSession;
80
- if ((0, sessionManagerUtils_1.isUserSessionValid)(storedUserSession)) {
154
+ if (!sessionsConfig.persistent && (0, sessionManagerUtils_1.isUserSessionValid)(storedUserSession)) {
81
155
  var sessionId = storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionId;
82
156
  initialSession = (0, sessionManagerUtils_1.createUserSessionObject)({
83
157
  sessionId: sessionId,
@@ -94,71 +168,166 @@ var SessionInstrumentation = /** @class */ (function (_super) {
94
168
  emitSessionStartOnInit = false;
95
169
  }
96
170
  else {
97
- var sessionId = (_e = (_d = sessionsConfig.session) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : (0, faro_core_1.genShortID)();
98
171
  initialSession = (0, sessionManagerUtils_1.createUserSessionObject)({
99
- sessionId: sessionId,
172
+ sessionId: (_d = sessionsConfig.session) === null || _d === void 0 ? void 0 : _d.id,
100
173
  isSampled: (0, sessionManager_1.isSampled)(),
101
174
  });
102
- var overrides = (_f = sessionsConfig.session) === null || _f === void 0 ? void 0 : _f.overrides;
103
- initialSession.sessionMeta = __assign({ id: sessionId, attributes: __assign(__assign({ isSampled: initialSession.isSampled.toString() }, (_g = sessionsConfig.session) === null || _g === void 0 ? void 0 : _g.attributes), defaultAttributes) }, (overrides ? { overrides: overrides } : {}));
175
+ var sessionId = initialSession.sessionId;
176
+ var previousSessionId = (storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionId) === sessionId ? undefined : storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionId;
177
+ var overrides = (_e = sessionsConfig.session) === null || _e === void 0 ? void 0 : _e.overrides;
178
+ initialSession.sessionMeta = __assign({ id: sessionId, attributes: __assign(__assign(__assign(__assign({}, (_f = sessionsConfig.session) === null || _f === void 0 ? void 0 : _f.attributes), defaultAttributes), { isSampled: initialSession.isSampled.toString() }), (previousSessionId == null ? {} : { previousSession: previousSessionId })) }, (overrides ? { overrides: overrides } : {}));
104
179
  emitSessionStartOnInit = true;
105
180
  }
106
181
  return { initialSession: initialSession, emitSessionStartOnInit: emitSessionStartOnInit };
107
182
  };
108
183
  SessionInstrumentation.prototype.registerBeforeSendHook = function (SessionManagerClass) {
109
- var _a;
110
- var updateSession = new SessionManagerClass().updateSession;
111
- (_a = this.transports) === null || _a === void 0 ? void 0 : _a.addBeforeSendHooks(function (item) {
112
- var _a, _b, _c;
113
- updateSession();
114
- var attributes = (_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.attributes;
115
- // Only filter out items when session is explicitly NOT sampled (isSampled='false')
116
- // If isSampled='true', remove the attribute before sending (it's internal)
117
- // If no isSampled attribute, pass through the item unchanged
118
- if ((attributes === null || attributes === void 0 ? void 0 : attributes['isSampled']) === 'false') {
119
- // Session is not sampled - drop this item
120
- return null;
184
+ var _this = this;
185
+ var registeredTransports = this.transports;
186
+ ensureSessionSamplingFallback(registeredTransports);
187
+ var beforeSendHook = function (item) {
188
+ var _a;
189
+ var activeBeforeSendHook = activeSessionBeforeSendHooks.get(registeredTransports);
190
+ if (activeBeforeSendHook != null && activeBeforeSendHook !== beforeSendHook) {
191
+ return item;
121
192
  }
122
- if ((attributes === null || attributes === void 0 ? void 0 : attributes['isSampled']) === 'true') {
123
- // Session is sampled - remove internal isSampled attribute before sending
124
- var newItem = JSON.parse(JSON.stringify(item));
125
- var newAttributes = (_b = newItem.meta.session) === null || _b === void 0 ? void 0 : _b.attributes;
126
- newAttributes === null || newAttributes === void 0 ? true : delete newAttributes['isSampled'];
127
- if (Object.keys(newAttributes !== null && newAttributes !== void 0 ? newAttributes : {}).length === 0) {
128
- (_c = newItem.meta.session) === null || _c === void 0 ? true : delete _c.attributes;
193
+ var nextItem = item;
194
+ var fallbackSamplingDecision;
195
+ var sessionManager = _this.beforeSendHook === beforeSendHook ? _this.sessionManagerInstance : undefined;
196
+ if (sessionManager != null) {
197
+ var storedSession = SessionManagerClass.fetchUserSession();
198
+ var recoveredCrash = (0, sessionActivity_1.isRecoveredCrashItem)(item, storedSession === null || storedSession === void 0 ? void 0 : storedSession.sessionId);
199
+ // Ending an active action can send telemetry synchronously. Keep that
200
+ // telemetry on the current session until the explicit reset completes.
201
+ var checkedSession = recoveredCrash
202
+ ? null
203
+ : _this.isResettingSession
204
+ ? storedSession
205
+ : sessionManager.checkSession((0, sessionActivity_1.classifySessionActivity)(item), storedSession);
206
+ if ((checkedSession === null || checkedSession === void 0 ? void 0 : checkedSession.sessionMeta) != null && ((_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.id) !== checkedSession.sessionId) {
207
+ nextItem = __assign(__assign({}, item), { meta: __assign(__assign({}, item.meta), { session: checkedSession.sessionMeta }) });
129
208
  }
130
- return newItem;
209
+ // New crash records carry the crash-time decision. Older records may not,
210
+ // so retain the previous behavior and use the live session's stable
211
+ // decision rather than implicitly sampling every recovered crash.
212
+ fallbackSamplingDecision = recoveredCrash ? storedSession === null || storedSession === void 0 ? void 0 : storedSession.isSampled : checkedSession === null || checkedSession === void 0 ? void 0 : checkedSession.isSampled;
131
213
  }
132
- // No isSampled attribute or other value - pass through unchanged
133
- return item;
134
- });
214
+ return applySessionSampling(nextItem, fallbackSamplingDecision);
215
+ };
216
+ this.beforeSendHook = beforeSendHook;
217
+ this.beforeSendHookApi = this.api;
218
+ this.beforeSendHookTransports = registeredTransports;
219
+ registeredTransports.addBeforeSendHooks(beforeSendHook);
220
+ activeSessionBeforeSendHooks.set(registeredTransports, beforeSendHook);
135
221
  };
136
222
  SessionInstrumentation.prototype.initialize = function () {
223
+ var _this = this;
224
+ // BaseInstrumentation instances can be registered more than once. Detach
225
+ // every resource from the previous Faro instance before binding the next.
226
+ this.unpatch();
137
227
  var sessionTrackingConfig = this.config.sessionTracking;
228
+ // A new initialization owns direct-activity routing, including when
229
+ // session tracking is disabled.
230
+ (0, directSessionActivity_1.clearDirectSessionActivityHandler)();
138
231
  if (!(sessionTrackingConfig === null || sessionTrackingConfig === void 0 ? void 0 : sessionTrackingConfig.enabled)) {
139
- this.metas.addListener(this.sendSessionStartEvent.bind(this));
232
+ this.registerSessionMetaListener();
140
233
  return;
141
234
  }
142
235
  var SessionManagerClass = (0, sessionManager_1.getSessionManagerByConfig)(sessionTrackingConfig);
236
+ // Constructing a manager registers an AppState subscription and a metas
237
+ // listener, so exactly one instance is created and reused. It is also the
238
+ // instance `unpatch()` cleans up.
239
+ this.sessionManagerInstance = new SessionManagerClass(this.metas);
143
240
  this.registerBeforeSendHook(SessionManagerClass);
144
241
  var _a = this.createInitialSession(SessionManagerClass, sessionTrackingConfig), initialSession = _a.initialSession, emitSessionStartOnInit = _a.emitSessionStartOnInit;
145
242
  SessionManagerClass.storeUserSession(initialSession);
146
243
  var initialSessionMeta = initialSession.sessionMeta;
147
244
  this.notifiedSession = initialSessionMeta;
148
245
  this.api.setSession(initialSessionMeta);
149
- this.sessionManagerInstance = new SessionManagerClass();
150
246
  if (emitSessionStartOnInit) {
151
247
  this.api.pushEvent(faro_core_1.EVENT_SESSION_START, {}, undefined, { skipDedupe: true });
152
248
  }
153
- this.metas.addListener(this.sendSessionStartEvent.bind(this));
249
+ this.unregisterDirectSessionActivity = (0, directSessionActivity_1.registerDirectSessionActivityHandler)(function () {
250
+ var _a;
251
+ (_a = _this.sessionManagerInstance) === null || _a === void 0 ? void 0 : _a.checkSession(sessionActivity_1.SessionActivityKind.Meaningful);
252
+ });
253
+ this.registerSessionMetaListener();
254
+ };
255
+ /** Starts a new linked session immediately. */
256
+ SessionInstrumentation.prototype.startNewSession = function () {
257
+ var _a, _b;
258
+ if (this.sessionManagerInstance == null || this.isResettingSession) {
259
+ return;
260
+ }
261
+ this.isResettingSession = true;
262
+ try {
263
+ try {
264
+ var activeAction = (_b = (_a = this.api).getActiveUserAction) === null || _b === void 0 ? void 0 : _b.call(_a);
265
+ activeAction === null || activeAction === void 0 ? void 0 : activeAction.end();
266
+ }
267
+ catch (error) {
268
+ this.logWarn('Failed to end the active user action before resetting the session:', error);
269
+ }
270
+ this.sessionManagerInstance.resetSession();
271
+ }
272
+ finally {
273
+ this.isResettingSession = false;
274
+ }
154
275
  };
155
276
  /**
156
277
  * Clean up session manager listeners
157
278
  */
158
279
  SessionInstrumentation.prototype.unpatch = function () {
159
- if (this.sessionManagerInstance && 'unpatch' in this.sessionManagerInstance) {
160
- this.sessionManagerInstance.unpatch();
280
+ var _a, _b;
281
+ (_a = this.unregisterDirectSessionActivity) === null || _a === void 0 ? void 0 : _a.call(this);
282
+ this.unregisterDirectSessionActivity = undefined;
283
+ var beforeSendHook = this.beforeSendHook;
284
+ var beforeSendHookApi = this.beforeSendHookApi;
285
+ var beforeSendHookTransports = this.beforeSendHookTransports;
286
+ var ownedActiveHook = beforeSendHook != null &&
287
+ beforeSendHookTransports != null &&
288
+ activeSessionBeforeSendHooks.get(beforeSendHookTransports) === beforeSendHook;
289
+ // Stop the manager's metas synchronization before removing the internal
290
+ // sampling marker. Keep the session hook active during that update so any
291
+ // surviving metas listener that emits telemetry is still attributed and
292
+ // filtered with the current session.
293
+ (_b = this.sessionManagerInstance) === null || _b === void 0 ? void 0 : _b.unpatch();
294
+ try {
295
+ if (ownedActiveHook && beforeSendHookApi) {
296
+ var session = beforeSendHookApi.getSession();
297
+ var sessionWithoutSamplingAttribute = removeInternalSamplingAttribute(session);
298
+ if (sessionWithoutSamplingAttribute !== session) {
299
+ this.isResettingSession = true;
300
+ try {
301
+ beforeSendHookApi.setSession(sessionWithoutSamplingAttribute);
302
+ }
303
+ finally {
304
+ this.isResettingSession = false;
305
+ }
306
+ }
307
+ }
161
308
  }
309
+ finally {
310
+ this.beforeSendHook = undefined;
311
+ this.beforeSendHookApi = undefined;
312
+ this.beforeSendHookTransports = undefined;
313
+ if (beforeSendHook && beforeSendHookTransports) {
314
+ if (ownedActiveHook) {
315
+ activeSessionBeforeSendHooks.delete(beforeSendHookTransports);
316
+ }
317
+ beforeSendHookTransports.removeBeforeSendHooks(beforeSendHook);
318
+ }
319
+ this.sessionManagerInstance = undefined;
320
+ var sessionMetaListenerMetas = this.sessionMetaListenerMetas;
321
+ this.sessionMetaListenerMetas = undefined;
322
+ if (sessionMetaListenerMetas) {
323
+ sessionMetaListenerMetas.removeListener(this.sendSessionStartEvent);
324
+ }
325
+ this.notifiedSession = undefined;
326
+ this.isResettingSession = false;
327
+ }
328
+ };
329
+ SessionInstrumentation.prototype.destroy = function () {
330
+ this.unpatch();
162
331
  };
163
332
  return SessionInstrumentation;
164
333
  }(faro_core_1.BaseInstrumentation));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseInstrumentation, dateNow, EVENT_SESSION_START, genShortID, VERSION } from '@grafana/faro-core';\nimport type { Config, Meta, MetaSession, TransportItem } from '@grafana/faro-core';\n\nimport type { ReactNativeFullConfig, ReactNativeSessionTrackingConfig } from '../../config/types';\n\nimport { minimalSessionDeviceAttributes, type SessionAttributes } from './sessionAttributes';\nimport { type FaroUserSession, getSessionManagerByConfig, isSampled } from './sessionManager';\nimport { MAX_SESSION_PERSISTENCE_TIME } from './sessionManager/sessionConstants';\nimport { createUserSessionObject, isUserSessionValid } from './sessionManager/sessionManagerUtils';\nimport type { SessionManager } from './sessionManager/types';\n\n/**\n * Session instrumentation for React Native\n * Manages persistent or volatile sessions with expiration and inactivity tracking\n */\nexport class SessionInstrumentation extends BaseInstrumentation {\n readonly name = '@grafana/faro-react-native:instrumentation-session';\n readonly version = VERSION;\n\n // previously notified session, to ensure we don't send session start\n // event twice for the same session\n private notifiedSession: MetaSession | undefined;\n private sessionManagerInstance: InstanceType<SessionManager> | undefined;\n\n private getDefaultSessionDeviceAttributes(): SessionAttributes {\n const cfg = this.config as ReactNativeFullConfig;\n if (cfg.preloadedSessionDeviceAttributes != null) {\n return cfg.preloadedSessionDeviceAttributes;\n }\n return minimalSessionDeviceAttributes();\n }\n\n private sendSessionStartEvent(meta: Meta): void {\n const session = meta.session;\n\n if (session && session.id !== this.notifiedSession?.id) {\n this.notifiedSession = session;\n // no need to add attributes and session id, they are included as part of meta\n // automatically\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n }\n\n private createInitialSession(\n SessionManagerClass: SessionManager,\n sessionsConfig: Required<Config>['sessionTracking']\n ): {\n initialSession: FaroUserSession;\n emitSessionStartOnInit: boolean;\n } {\n let storedUserSession = SessionManagerClass.fetchUserSession();\n\n const sessionsConfigTyped = sessionsConfig as ReactNativeSessionTrackingConfig;\n const maxPersistenceMs = sessionsConfigTyped.maxSessionPersistenceTime ?? MAX_SESSION_PERSISTENCE_TIME;\n\n if (sessionsConfig.persistent && storedUserSession) {\n const now = dateNow();\n const shouldClearPersistentSession = storedUserSession.lastActivity < now - maxPersistenceMs;\n\n if (shouldClearPersistentSession) {\n SessionManagerClass.removeUserSession();\n storedUserSession = null;\n }\n }\n\n const defaultAttributes = this.getDefaultSessionDeviceAttributes();\n\n let emitSessionStartOnInit: boolean;\n let initialSession: FaroUserSession;\n\n if (isUserSessionValid(storedUserSession)) {\n const sessionId = storedUserSession?.sessionId;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: storedUserSession?.isSampled || false,\n started: storedUserSession?.started,\n });\n\n const storedUserSessionMeta = storedUserSession?.sessionMeta;\n\n // For resumed sessions we want to merge the previous overrides with the configured ones.\n // If the same key is present in both, the new one will override the old one.\n const overrides = { ...sessionsConfig.session?.overrides, ...storedUserSessionMeta?.overrides };\n\n initialSession.sessionMeta = {\n ...sessionsConfig.session,\n id: sessionId,\n attributes: {\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Merge with stored attributes\n ...storedUserSessionMeta?.attributes,\n // Default attributes take precedence (matching Flutter SDK behavior)\n ...defaultAttributes,\n // For valid resumed sessions we do not want to recalculate the sampling decision on each init phase.\n isSampled: initialSession.isSampled.toString(),\n },\n overrides,\n };\n\n emitSessionStartOnInit = false;\n } else {\n const sessionId = sessionsConfig.session?.id ?? genShortID();\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: isSampled(),\n });\n\n const overrides = sessionsConfig.session?.overrides;\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n isSampled: initialSession.isSampled.toString(),\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Default attributes take precedence (matching Flutter SDK behavior)\n ...defaultAttributes,\n },\n // new session we don't care about previous overrides\n ...(overrides ? { overrides } : {}),\n };\n\n emitSessionStartOnInit = true;\n }\n\n return { initialSession, emitSessionStartOnInit };\n }\n\n private registerBeforeSendHook(SessionManagerClass: SessionManager) {\n const { updateSession } = new SessionManagerClass();\n\n this.transports?.addBeforeSendHooks((item: TransportItem) => {\n updateSession();\n\n const attributes = item.meta.session?.attributes;\n\n // Only filter out items when session is explicitly NOT sampled (isSampled='false')\n // If isSampled='true', remove the attribute before sending (it's internal)\n // If no isSampled attribute, pass through the item unchanged\n if (attributes?.['isSampled'] === 'false') {\n // Session is not sampled - drop this item\n return null;\n }\n\n if (attributes?.['isSampled'] === 'true') {\n // Session is sampled - remove internal isSampled attribute before sending\n let newItem: TransportItem = JSON.parse(JSON.stringify(item));\n\n const newAttributes = newItem.meta.session?.attributes;\n delete newAttributes?.['isSampled'];\n\n if (Object.keys(newAttributes ?? {}).length === 0) {\n delete newItem.meta.session?.attributes;\n }\n\n return newItem;\n }\n\n // No isSampled attribute or other value - pass through unchanged\n return item;\n });\n }\n\n initialize(): void {\n const sessionTrackingConfig = this.config.sessionTracking;\n\n if (!sessionTrackingConfig?.enabled) {\n this.metas.addListener(this.sendSessionStartEvent.bind(this));\n return;\n }\n\n const SessionManagerClass = getSessionManagerByConfig(sessionTrackingConfig);\n\n this.registerBeforeSendHook(SessionManagerClass);\n\n const { initialSession, emitSessionStartOnInit } = this.createInitialSession(\n SessionManagerClass,\n sessionTrackingConfig\n );\n SessionManagerClass.storeUserSession(initialSession);\n\n const initialSessionMeta = initialSession.sessionMeta;\n this.notifiedSession = initialSessionMeta;\n this.api.setSession(initialSessionMeta);\n\n this.sessionManagerInstance = new SessionManagerClass();\n\n if (emitSessionStartOnInit) {\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n\n this.metas.addListener(this.sendSessionStartEvent.bind(this));\n }\n\n /**\n * Clean up session manager listeners\n */\n unpatch(): void {\n if (this.sessionManagerInstance && 'unpatch' in this.sessionManagerInstance) {\n this.sessionManagerInstance.unpatch();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseInstrumentation, dateNow, EVENT_SESSION_START, faro, VERSION } from '@grafana/faro-core';\nimport type {\n API,\n BeforeSendHook,\n Config,\n Meta,\n Metas,\n MetaSession,\n TransportItem,\n Transports,\n UserActionInternalInterface,\n} from '@grafana/faro-core';\n\nimport type { ReactNativeFullConfig, ReactNativeSessionTrackingConfig } from '../../config/types';\n\nimport { clearDirectSessionActivityHandler, registerDirectSessionActivityHandler } from './directSessionActivity';\nimport { classifySessionActivity, isRecoveredCrashItem, SessionActivityKind } from './sessionActivity';\nimport { minimalSessionDeviceAttributes, type SessionAttributes } from './sessionAttributes';\nimport { type FaroUserSession, getSessionManagerByConfig, isSampled } from './sessionManager';\nimport { MAX_SESSION_PERSISTENCE_TIME } from './sessionManager/sessionConstants';\nimport { createUserSessionObject, isUserSessionValid } from './sessionManager/sessionManagerUtils';\nimport type { SessionManager, SessionManagerInstance } from './sessionManager/types';\n\nconst SESSION_INSTRUMENTATION_NAME = '@grafana/faro-react-native:instrumentation-session';\n\n// Track the current session hook per transport so superseded hooks yield to a\n// replacement. The shared fallback preserves sampling decisions captured on\n// queued items after the owning instrumentation has detached.\nconst activeSessionBeforeSendHooks = new WeakMap<Transports, BeforeSendHook>();\nconst sessionSamplingFallbackHooks = new WeakMap<Transports, BeforeSendHook>();\n\nfunction applySessionSampling(item: TransportItem, fallbackSamplingDecision?: boolean): TransportItem | null {\n const attributes = item.meta.session?.attributes;\n const samplingAttribute = attributes?.['isSampled'] ?? fallbackSamplingDecision?.toString();\n\n if (samplingAttribute === 'false') {\n return null;\n }\n\n if (samplingAttribute !== 'true') {\n return item;\n }\n\n const sampledItem: TransportItem = {\n ...item,\n meta: {\n ...item.meta,\n session: item.meta.session\n ? {\n ...item.meta.session,\n attributes: item.meta.session.attributes ? { ...item.meta.session.attributes } : undefined,\n }\n : undefined,\n },\n };\n\n const sampledAttributes = sampledItem.meta.session?.attributes;\n delete sampledAttributes?.['isSampled'];\n\n if (Object.keys(sampledAttributes ?? {}).length === 0) {\n delete sampledItem.meta.session?.attributes;\n }\n\n return sampledItem;\n}\n\nfunction ensureSessionSamplingFallback(transports: Transports): void {\n if (sessionSamplingFallbackHooks.has(transports)) {\n return;\n }\n\n const fallbackHook: BeforeSendHook = (item) =>\n activeSessionBeforeSendHooks.has(transports) ? item : applySessionSampling(item);\n\n transports.addBeforeSendHooks(fallbackHook);\n sessionSamplingFallbackHooks.set(transports, fallbackHook);\n}\n\nfunction removeInternalSamplingAttribute(session: MetaSession | undefined): MetaSession | undefined {\n if (session?.attributes?.['isSampled'] == null) {\n return session;\n }\n\n const attributes = { ...session.attributes };\n delete attributes['isSampled'];\n\n return {\n ...session,\n attributes: Object.keys(attributes).length === 0 ? undefined : attributes,\n };\n}\n\n/**\n * Starts a new linked session at an application-defined boundary.\n *\n * Call this after changing or clearing the current user for logout, account\n * changes, or another boundary that must not share a session. Calls made\n * before Faro initializes, after teardown, or while session tracking is\n * disabled have no effect.\n */\nexport function startNewSession(): void {\n const instrumentation = faro?.instrumentations?.instrumentations.find(\n ({ name }) => name === SESSION_INSTRUMENTATION_NAME\n );\n\n if (\n instrumentation != null &&\n 'startNewSession' in instrumentation &&\n typeof instrumentation.startNewSession === 'function'\n ) {\n instrumentation.startNewSession();\n }\n}\n\n/**\n * Session instrumentation for React Native\n * Manages persistent or volatile sessions with expiration and inactivity tracking\n */\nexport class SessionInstrumentation extends BaseInstrumentation {\n readonly name = SESSION_INSTRUMENTATION_NAME;\n readonly version = VERSION;\n\n // previously notified session, to ensure we don't send session start\n // event twice for the same session\n private notifiedSession: MetaSession | undefined;\n private sessionManagerInstance: SessionManagerInstance | undefined;\n private isResettingSession = false;\n private unregisterDirectSessionActivity: (() => void) | undefined;\n private sessionMetaListenerMetas: Metas | undefined;\n private beforeSendHookApi: API | undefined;\n private beforeSendHook: BeforeSendHook | undefined;\n private beforeSendHookTransports: Transports | undefined;\n\n private getDefaultSessionDeviceAttributes(): SessionAttributes {\n const cfg = this.config as ReactNativeFullConfig;\n if (cfg.preloadedSessionDeviceAttributes != null) {\n return cfg.preloadedSessionDeviceAttributes;\n }\n return minimalSessionDeviceAttributes();\n }\n\n private readonly sendSessionStartEvent = (meta: Meta): void => {\n const session = meta.session;\n\n if (session && session.id !== this.notifiedSession?.id) {\n this.notifiedSession = session;\n // no need to add attributes and session id, they are included as part of meta\n // automatically\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n };\n\n private registerSessionMetaListener(): void {\n this.metas.addListener(this.sendSessionStartEvent);\n this.sessionMetaListenerMetas = this.metas;\n }\n\n private createInitialSession(\n SessionManagerClass: SessionManager,\n sessionsConfig: Required<Config>['sessionTracking']\n ): {\n initialSession: FaroUserSession;\n emitSessionStartOnInit: boolean;\n } {\n let storedUserSession = SessionManagerClass.fetchUserSession();\n\n const sessionsConfigTyped = sessionsConfig as ReactNativeSessionTrackingConfig;\n const maxPersistenceMs = sessionsConfigTyped.maxSessionPersistenceTime ?? MAX_SESSION_PERSISTENCE_TIME;\n\n if (sessionsConfig.persistent && storedUserSession) {\n const now = dateNow();\n const shouldClearPersistentSession =\n storedUserSession.started > now ||\n storedUserSession.lastActivity > now ||\n storedUserSession.lastActivity <= now - maxPersistenceMs;\n\n if (shouldClearPersistentSession) {\n SessionManagerClass.removeUserSession();\n storedUserSession = null;\n }\n }\n\n const defaultAttributes = this.getDefaultSessionDeviceAttributes();\n\n let emitSessionStartOnInit: boolean;\n let initialSession: FaroUserSession;\n\n if (!sessionsConfig.persistent && isUserSessionValid(storedUserSession)) {\n const sessionId = storedUserSession?.sessionId;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: storedUserSession?.isSampled || false,\n started: storedUserSession?.started,\n });\n\n const storedUserSessionMeta = storedUserSession?.sessionMeta;\n\n // For resumed sessions we want to merge the previous overrides with the configured ones.\n // If the same key is present in both, the new one will override the old one.\n const overrides = { ...sessionsConfig.session?.overrides, ...storedUserSessionMeta?.overrides };\n\n initialSession.sessionMeta = {\n ...sessionsConfig.session,\n id: sessionId,\n attributes: {\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Merge with stored attributes\n ...storedUserSessionMeta?.attributes,\n // Default attributes take precedence\n ...defaultAttributes,\n // For valid resumed sessions we do not want to recalculate the sampling decision on each init phase.\n isSampled: initialSession.isSampled.toString(),\n },\n overrides,\n };\n\n emitSessionStartOnInit = false;\n } else {\n initialSession = createUserSessionObject({\n sessionId: sessionsConfig.session?.id,\n isSampled: isSampled(),\n });\n\n const sessionId = initialSession.sessionId;\n const previousSessionId = storedUserSession?.sessionId === sessionId ? undefined : storedUserSession?.sessionId;\n const overrides = sessionsConfig.session?.overrides;\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Default attributes take precedence\n ...defaultAttributes,\n isSampled: initialSession.isSampled.toString(),\n ...(previousSessionId == null ? {} : { previousSession: previousSessionId }),\n },\n // new session we don't care about previous overrides\n ...(overrides ? { overrides } : {}),\n };\n\n emitSessionStartOnInit = true;\n }\n\n return { initialSession, emitSessionStartOnInit };\n }\n\n private registerBeforeSendHook(SessionManagerClass: SessionManager): void {\n const registeredTransports = this.transports;\n ensureSessionSamplingFallback(registeredTransports);\n\n const beforeSendHook: BeforeSendHook = (item: TransportItem) => {\n const activeBeforeSendHook = activeSessionBeforeSendHooks.get(registeredTransports);\n if (activeBeforeSendHook != null && activeBeforeSendHook !== beforeSendHook) {\n return item;\n }\n\n let nextItem = item;\n let fallbackSamplingDecision: boolean | undefined;\n const sessionManager = this.beforeSendHook === beforeSendHook ? this.sessionManagerInstance : undefined;\n\n if (sessionManager != null) {\n const storedSession = SessionManagerClass.fetchUserSession();\n const recoveredCrash = isRecoveredCrashItem(item, storedSession?.sessionId);\n // Ending an active action can send telemetry synchronously. Keep that\n // telemetry on the current session until the explicit reset completes.\n const checkedSession = recoveredCrash\n ? null\n : this.isResettingSession\n ? storedSession\n : sessionManager.checkSession(classifySessionActivity(item), storedSession);\n\n if (checkedSession?.sessionMeta != null && item.meta.session?.id !== checkedSession.sessionId) {\n nextItem = {\n ...item,\n meta: {\n ...item.meta,\n session: checkedSession.sessionMeta,\n },\n };\n }\n\n // New crash records carry the crash-time decision. Older records may not,\n // so retain the previous behavior and use the live session's stable\n // decision rather than implicitly sampling every recovered crash.\n fallbackSamplingDecision = recoveredCrash ? storedSession?.isSampled : checkedSession?.isSampled;\n }\n\n return applySessionSampling(nextItem, fallbackSamplingDecision);\n };\n\n this.beforeSendHook = beforeSendHook;\n this.beforeSendHookApi = this.api;\n this.beforeSendHookTransports = registeredTransports;\n registeredTransports.addBeforeSendHooks(beforeSendHook);\n activeSessionBeforeSendHooks.set(registeredTransports, beforeSendHook);\n }\n\n initialize(): void {\n // BaseInstrumentation instances can be registered more than once. Detach\n // every resource from the previous Faro instance before binding the next.\n this.unpatch();\n\n const sessionTrackingConfig = this.config.sessionTracking;\n\n // A new initialization owns direct-activity routing, including when\n // session tracking is disabled.\n clearDirectSessionActivityHandler();\n\n if (!sessionTrackingConfig?.enabled) {\n this.registerSessionMetaListener();\n return;\n }\n\n const SessionManagerClass = getSessionManagerByConfig(sessionTrackingConfig);\n\n // Constructing a manager registers an AppState subscription and a metas\n // listener, so exactly one instance is created and reused. It is also the\n // instance `unpatch()` cleans up.\n this.sessionManagerInstance = new SessionManagerClass(this.metas);\n\n this.registerBeforeSendHook(SessionManagerClass);\n\n const { initialSession, emitSessionStartOnInit } = this.createInitialSession(\n SessionManagerClass,\n sessionTrackingConfig\n );\n SessionManagerClass.storeUserSession(initialSession);\n\n const initialSessionMeta = initialSession.sessionMeta;\n this.notifiedSession = initialSessionMeta;\n this.api.setSession(initialSessionMeta);\n\n if (emitSessionStartOnInit) {\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n\n this.unregisterDirectSessionActivity = registerDirectSessionActivityHandler(() => {\n this.sessionManagerInstance?.checkSession(SessionActivityKind.Meaningful);\n });\n\n this.registerSessionMetaListener();\n }\n\n /** Starts a new linked session immediately. */\n startNewSession(): void {\n if (this.sessionManagerInstance == null || this.isResettingSession) {\n return;\n }\n\n this.isResettingSession = true;\n try {\n try {\n const activeAction = this.api.getActiveUserAction?.() as UserActionInternalInterface | undefined;\n activeAction?.end();\n } catch (error) {\n this.logWarn('Failed to end the active user action before resetting the session:', error);\n }\n\n this.sessionManagerInstance.resetSession();\n } finally {\n this.isResettingSession = false;\n }\n }\n\n /**\n * Clean up session manager listeners\n */\n unpatch(): void {\n this.unregisterDirectSessionActivity?.();\n this.unregisterDirectSessionActivity = undefined;\n\n const beforeSendHook = this.beforeSendHook;\n const beforeSendHookApi = this.beforeSendHookApi;\n const beforeSendHookTransports = this.beforeSendHookTransports;\n const ownedActiveHook =\n beforeSendHook != null &&\n beforeSendHookTransports != null &&\n activeSessionBeforeSendHooks.get(beforeSendHookTransports) === beforeSendHook;\n\n // Stop the manager's metas synchronization before removing the internal\n // sampling marker. Keep the session hook active during that update so any\n // surviving metas listener that emits telemetry is still attributed and\n // filtered with the current session.\n this.sessionManagerInstance?.unpatch();\n\n try {\n if (ownedActiveHook && beforeSendHookApi) {\n const session = beforeSendHookApi.getSession();\n const sessionWithoutSamplingAttribute = removeInternalSamplingAttribute(session);\n if (sessionWithoutSamplingAttribute !== session) {\n this.isResettingSession = true;\n try {\n beforeSendHookApi.setSession(sessionWithoutSamplingAttribute);\n } finally {\n this.isResettingSession = false;\n }\n }\n }\n } finally {\n this.beforeSendHook = undefined;\n this.beforeSendHookApi = undefined;\n this.beforeSendHookTransports = undefined;\n if (beforeSendHook && beforeSendHookTransports) {\n if (ownedActiveHook) {\n activeSessionBeforeSendHooks.delete(beforeSendHookTransports);\n }\n beforeSendHookTransports.removeBeforeSendHooks(beforeSendHook);\n }\n\n this.sessionManagerInstance = undefined;\n\n const sessionMetaListenerMetas = this.sessionMetaListenerMetas;\n this.sessionMetaListenerMetas = undefined;\n if (sessionMetaListenerMetas) {\n sessionMetaListenerMetas.removeListener(this.sendSessionStartEvent);\n }\n\n this.notifiedSession = undefined;\n this.isResettingSession = false;\n }\n }\n\n destroy(): void {\n this.unpatch();\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionActivityKind = void 0;
4
+ exports.classifySessionActivity = classifySessionActivity;
5
+ exports.isRecoveredCrashItem = isRecoveredCrashItem;
6
+ var faro_core_1 = require("@grafana/faro-core");
7
+ var utils_1 = require("../../navigation/utils");
8
+ var appState_1 = require("../appState");
9
+ var SessionActivityKind;
10
+ (function (SessionActivityKind) {
11
+ SessionActivityKind["Meaningful"] = "meaningful";
12
+ SessionActivityKind["Passive"] = "passive";
13
+ })(SessionActivityKind || (exports.SessionActivityKind = SessionActivityKind = {}));
14
+ /** Classifies how a transport item affects the session inactivity window. */
15
+ function classifySessionActivity(item) {
16
+ var _a, _b;
17
+ var payload = item.payload;
18
+ if (payload.action != null) {
19
+ return SessionActivityKind.Meaningful;
20
+ }
21
+ if (item.type !== faro_core_1.TransportItemType.EVENT) {
22
+ return SessionActivityKind.Passive;
23
+ }
24
+ if (payload.name === faro_core_1.EVENT_VIEW_CHANGED || payload.name === utils_1.EVENT_NAVIGATION) {
25
+ return SessionActivityKind.Meaningful;
26
+ }
27
+ if (payload.name === appState_1.EVENT_APP_STATE_CHANGED &&
28
+ ((_a = payload.attributes) === null || _a === void 0 ? void 0 : _a['fromState']) === 'background' &&
29
+ ((_b = payload.attributes) === null || _b === void 0 ? void 0 : _b['toState']) === 'active') {
30
+ return SessionActivityKind.Meaningful;
31
+ }
32
+ return SessionActivityKind.Passive;
33
+ }
34
+ /** Recovered crashes keep the session captured by the previous process. */
35
+ function isRecoveredCrashItem(item, currentSessionId) {
36
+ var _a;
37
+ if (item.type !== faro_core_1.TransportItemType.EXCEPTION || ((_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.id) == null) {
38
+ return false;
39
+ }
40
+ var payload = item.payload;
41
+ return payload.type === 'crash' && payload.fatal === true && item.meta.session.id !== currentSessionId;
42
+ }
43
+ //# sourceMappingURL=sessionActivity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionActivity.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/sessionActivity.ts"],"names":[],"mappings":";;;AAkBA,0DAwBC;AAQD,oDAOC;AAzDD,gDAA2E;AAG3E,gDAA0D;AAC1D,wCAAsD;AAEtD,IAAY,mBAGX;AAHD,WAAY,mBAAmB;IAC7B,gDAAyB,CAAA;IACzB,0CAAmB,CAAA;AACrB,CAAC,EAHW,mBAAmB,mCAAnB,mBAAmB,QAG9B;AAQD,6EAA6E;AAC7E,SAAgB,uBAAuB,CAAC,IAAmB;;IACzD,IAAM,OAAO,GAAG,IAAI,CAAC,OAA+B,CAAC;IAErD,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QAC3B,OAAO,mBAAmB,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,6BAAiB,CAAC,KAAK,EAAE,CAAC;QAC1C,OAAO,mBAAmB,CAAC,OAAO,CAAC;IACrC,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,KAAK,8BAAkB,IAAI,OAAO,CAAC,IAAI,KAAK,wBAAgB,EAAE,CAAC;QAC7E,OAAO,mBAAmB,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,IACE,OAAO,CAAC,IAAI,KAAK,kCAAuB;QACxC,CAAA,MAAA,OAAO,CAAC,UAAU,0CAAG,WAAW,CAAC,MAAK,YAAY;QAClD,CAAA,MAAA,OAAO,CAAC,UAAU,0CAAG,SAAS,CAAC,MAAK,QAAQ,EAC5C,CAAC;QACD,OAAO,mBAAmB,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,OAAO,mBAAmB,CAAC,OAAO,CAAC;AACrC,CAAC;AAOD,2EAA2E;AAC3E,SAAgB,oBAAoB,CAAC,IAAmB,EAAE,gBAAoC;;IAC5F,IAAI,IAAI,CAAC,IAAI,KAAK,6BAAiB,CAAC,SAAS,IAAI,CAAA,MAAA,IAAI,CAAC,IAAI,CAAC,OAAO,0CAAE,EAAE,KAAI,IAAI,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAM,OAAO,GAAG,IAAI,CAAC,OAAuB,CAAC;IAC7C,OAAO,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,gBAAgB,CAAC;AACzG,CAAC","sourcesContent":["import { EVENT_VIEW_CHANGED, TransportItemType } from '@grafana/faro-core';\nimport type { EventAttributes, TransportItem } from '@grafana/faro-core';\n\nimport { EVENT_NAVIGATION } from '../../navigation/utils';\nimport { EVENT_APP_STATE_CHANGED } from '../appState';\n\nexport enum SessionActivityKind {\n Meaningful = 'meaningful',\n Passive = 'passive',\n}\n\ntype ActivityEventPayload = {\n action?: unknown;\n attributes?: EventAttributes;\n name?: string;\n};\n\n/** Classifies how a transport item affects the session inactivity window. */\nexport function classifySessionActivity(item: TransportItem): SessionActivityKind {\n const payload = item.payload as ActivityEventPayload;\n\n if (payload.action != null) {\n return SessionActivityKind.Meaningful;\n }\n\n if (item.type !== TransportItemType.EVENT) {\n return SessionActivityKind.Passive;\n }\n\n if (payload.name === EVENT_VIEW_CHANGED || payload.name === EVENT_NAVIGATION) {\n return SessionActivityKind.Meaningful;\n }\n\n if (\n payload.name === EVENT_APP_STATE_CHANGED &&\n payload.attributes?.['fromState'] === 'background' &&\n payload.attributes?.['toState'] === 'active'\n ) {\n return SessionActivityKind.Meaningful;\n }\n\n return SessionActivityKind.Passive;\n}\n\ntype CrashPayload = {\n fatal?: unknown;\n type?: unknown;\n};\n\n/** Recovered crashes keep the session captured by the previous process. */\nexport function isRecoveredCrashItem(item: TransportItem, currentSessionId: string | undefined): boolean {\n if (item.type !== TransportItemType.EXCEPTION || item.meta.session?.id == null) {\n return false;\n }\n\n const payload = item.payload as CrashPayload;\n return payload.type === 'crash' && payload.fatal === true && item.meta.session.id !== currentSessionId;\n}\n"]}
@@ -57,6 +57,7 @@ exports.loadSessionDeviceAttributesForInit = loadSessionDeviceAttributesForInit;
57
57
  var react_native_1 = require("react-native");
58
58
  var react_native_device_info_1 = __importDefault(require("react-native-device-info"));
59
59
  var installationId_1 = require("./installationId");
60
+ var sessionProcess_1 = require("./sessionProcess");
60
61
  /**
61
62
  * React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.
62
63
  */
@@ -108,7 +109,7 @@ function getMobileDeviceType(isTablet) {
108
109
  return undefined;
109
110
  }
110
111
  /**
111
- * Get OS detail string matching Flutter SDK format
112
+ * Get OS detail string for session attributes.
112
113
  * iOS: "iOS 17.0"
113
114
  * Android: "Android 15 (SDK 35)"
114
115
  */
@@ -160,16 +161,16 @@ function getDeviceOsBuildId() {
160
161
  * No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.
161
162
  */
162
163
  function minimalSessionDeviceAttributes() {
163
- return {
164
- react_native_version: getReactNativeVersion(),
165
- };
164
+ var processInfo = (0, sessionProcess_1.getSessionProcessInfo)();
165
+ return __assign({ react_native_version: getReactNativeVersion() }, (processInfo == null ? {} : { process_name: processInfo.identifier }));
166
166
  }
167
167
  /**
168
168
  * Get all session attributes
169
169
  * These attributes are automatically included with every telemetry event
170
170
  *
171
- * Core attributes matching Flutter SDK:
171
+ * Core session attributes:
172
172
  * - react_native_version (RN framework in the host app)
173
+ * - process_name (Android process name or iOS bundle identifier)
173
174
  * - device_os, device_os_version, device_os_detail
174
175
  * - device_manufacturer, device_model, device_model_name
175
176
  * - device_brand, device_is_physical, device_id
@@ -192,7 +193,7 @@ function getSessionAttributes() {
192
193
  }
193
194
  function collectMobileMeta() {
194
195
  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
+ var _a, deviceOsDetail, deviceOsBuildId, installationId, systemName, systemVersion, manufacturer, model, modelIdentifier, deviceName, brand, isEmulator, isTablet, deviceType, totalMemory, usedMemory, 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
197
  return __generator(this, function (_d) {
197
198
  switch (_d.label) {
198
199
  case 0:
@@ -216,7 +217,6 @@ function collectMobileMeta() {
216
217
  deviceType = getMobileDeviceType(isTablet);
217
218
  totalMemory = react_native_device_info_1.default.getTotalMemorySync();
218
219
  usedMemory = react_native_device_info_1.default.getUsedMemorySync();
219
- reactNativeVersion = getReactNativeVersion();
220
220
  batteryLevel = void 0;
221
221
  isCharging = void 0;
222
222
  lowPowerMode = void 0;
@@ -269,7 +269,7 @@ function collectMobileMeta() {
269
269
  _error_6 = _d.sent();
270
270
  return [3 /*break*/, 15];
271
271
  case 15:
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 });
272
+ attributes = __assign(__assign(__assign(__assign(__assign({}, minimalSessionDeviceAttributes()), { 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
273
  appMeta = installationId ? { installationId: installationId } : {};
274
274
  structuredDeviceBrand = getStructuredDeviceBrand(model, brand);
275
275
  structuredDeviceManufacturer = getStructuredDeviceManufacturer(manufacturer);