@grafana/faro-react-native 1.3.1 → 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 (256) hide show
  1. package/README.md +176 -30
  2. package/android/build.gradle +17 -12
  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/crashReporting/BaseCrashReportingInstrumentation.d.ts +14 -4
  160. package/dist/types/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.d.ts +27 -0
  161. package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +2 -2
  162. package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +2 -2
  163. package/dist/types/instrumentations/crashReporting/types.d.ts +6 -0
  164. package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +2 -2
  165. package/dist/types/instrumentations/frameMonitoring/types.d.ts +4 -6
  166. package/dist/types/instrumentations/performance/index.d.ts +0 -2
  167. package/dist/types/instrumentations/session/FaroSessionActivityBoundary.d.ts +8 -0
  168. package/dist/types/instrumentations/session/directSessionActivity.d.ts +13 -0
  169. package/dist/types/instrumentations/session/index.d.ts +20 -1
  170. package/dist/types/instrumentations/session/sessionActivity.d.ts +9 -0
  171. package/dist/types/instrumentations/session/sessionAttributes.d.ts +6 -3
  172. package/dist/types/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.d.ts +16 -3
  173. package/dist/types/instrumentations/session/sessionManager/VolatileSessionManager.d.ts +9 -3
  174. package/dist/types/instrumentations/session/sessionManager/persistentSessionRecord.d.ts +4 -0
  175. package/dist/types/instrumentations/session/sessionManager/sessionManagerUtils.d.ts +19 -7
  176. package/dist/types/instrumentations/session/sessionManager/types.d.ts +6 -0
  177. package/dist/types/instrumentations/session/sessionProcess.d.ts +17 -0
  178. package/dist/types/instrumentations/startup/index.d.ts +2 -6
  179. package/dist/types/navigation/utils.d.ts +1 -0
  180. package/dist/types/transports/fetch/index.d.ts +1 -1
  181. package/dist/types/transports/fetch/transport.d.ts +8 -1
  182. package/dist/types/transports/fetch/types.d.ts +5 -0
  183. package/dist/types/transports/offline/ConnectivityService.d.ts +1 -1
  184. package/dist/types/transports/offline/OfflineCache.d.ts +2 -2
  185. package/dist/types/transports/offline/transport.d.ts +3 -4
  186. package/dist/types/userPersistence/UserPersistence.d.ts +1 -2
  187. package/ios/FaroCrashReporter.swift +214 -21
  188. package/ios/FaroReactNative.swift +24 -0
  189. package/ios/FaroReactNativeModule.h +2 -1
  190. package/ios/FaroReactNativeModule.mm +121 -6
  191. package/ios/RefreshRateVitals.swift +34 -38
  192. package/package.json +7 -5
  193. package/src/config/getRNInstrumentations.ts +6 -8
  194. package/src/config/makeRNConfig.test.ts +6 -0
  195. package/src/config/sampling.ts +0 -3
  196. package/src/config/types.ts +5 -3
  197. package/src/dataCollection/DataCollectionPolicy.ts +1 -2
  198. package/src/generated/faroRNPackageMeta.ts +1 -1
  199. package/src/index.ts +8 -2
  200. package/src/instrumentations/anr/instrumentation.ts +8 -1
  201. package/src/instrumentations/appState/index.ts +10 -2
  202. package/src/instrumentations/crashReporting/BaseCrashReportingInstrumentation.ts +28 -8
  203. package/src/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.ts +277 -0
  204. package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +2 -2
  205. package/src/instrumentations/crashReporting/instrumentation.test.ts +433 -5
  206. package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +2 -2
  207. package/src/instrumentations/crashReporting/types.ts +7 -0
  208. package/src/instrumentations/errors/index.ts +12 -4
  209. package/src/instrumentations/errors/instrumentation.test.ts +35 -0
  210. package/src/instrumentations/frameMonitoring/instrumentation.test.ts +155 -0
  211. package/src/instrumentations/frameMonitoring/instrumentation.ts +19 -38
  212. package/src/instrumentations/frameMonitoring/types.ts +4 -6
  213. package/src/instrumentations/performance/index.ts +2 -6
  214. package/src/instrumentations/session/FaroSessionActivityBoundary.test.ts +60 -0
  215. package/src/instrumentations/session/FaroSessionActivityBoundary.tsx +41 -0
  216. package/src/instrumentations/session/beforeSendHook.test.ts +246 -0
  217. package/src/instrumentations/session/directSessionActivity.test.ts +158 -0
  218. package/src/instrumentations/session/directSessionActivity.ts +36 -0
  219. package/src/instrumentations/session/index.ts +269 -46
  220. package/src/instrumentations/session/persistentColdStart.test.ts +196 -0
  221. package/src/instrumentations/session/sessionActivity.test.ts +68 -0
  222. package/src/instrumentations/session/sessionActivity.ts +58 -0
  223. package/src/instrumentations/session/sessionAttributes.test.ts +37 -2
  224. package/src/instrumentations/session/sessionAttributes.ts +12 -6
  225. package/src/instrumentations/session/sessionCleanup.test.ts +410 -0
  226. package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.test.ts +552 -0
  227. package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.ts +249 -33
  228. package/src/instrumentations/session/sessionManager/VolatileSessionManager.ts +38 -18
  229. package/src/instrumentations/session/sessionManager/persistentSessionRecord.test.ts +103 -0
  230. package/src/instrumentations/session/sessionManager/persistentSessionRecord.ts +78 -0
  231. package/src/instrumentations/session/sessionManager/sampling.test.ts +1 -1
  232. package/src/instrumentations/session/sessionManager/sessionConstants.ts +1 -1
  233. package/src/instrumentations/session/sessionManager/sessionManagerUtils.test.ts +256 -18
  234. package/src/instrumentations/session/sessionManager/sessionManagerUtils.ts +180 -39
  235. package/src/instrumentations/session/sessionManager/types.ts +8 -0
  236. package/src/instrumentations/session/sessionManagerInstance.test.ts +65 -0
  237. package/src/instrumentations/session/sessionProcess.test.ts +136 -0
  238. package/src/instrumentations/session/sessionProcess.ts +114 -0
  239. package/src/instrumentations/session/startNewSession.test.ts +337 -0
  240. package/src/instrumentations/startup/index.ts +2 -6
  241. package/src/navigation/utils.ts +3 -1
  242. package/src/transports/fetch/index.ts +6 -1
  243. package/src/transports/fetch/transport.test.ts +86 -2
  244. package/src/transports/fetch/transport.ts +38 -16
  245. package/src/transports/fetch/types.ts +7 -0
  246. package/src/transports/offline/ConnectivityService.ts +1 -1
  247. package/src/transports/offline/OfflineCache.ts +2 -2
  248. package/src/transports/offline/transport.ts +3 -4
  249. package/src/userPersistence/UserPersistence.ts +1 -2
  250. package/dist/cjs/utils/throttle.js +0 -42
  251. package/dist/cjs/utils/throttle.js.map +0 -1
  252. package/dist/esm/utils/throttle.js +0 -34
  253. package/dist/esm/utils/throttle.js.map +0 -1
  254. package/dist/types/utils/throttle.d.ts +0 -9
  255. package/src/utils/throttle.test.ts +0 -141
  256. package/src/utils/throttle.ts +0 -34
@@ -1 +1 @@
1
- {"version":3,"file":"sessionAttributes.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/sessionAttributes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+KA,wEAIC;AAkBD,oDAEC;AA8HD,sDAEC;AAMD,gFAMC;AAnVD,6CAAwC;AACxC,sFAAkD;AAIlD,mDAAqD;AAuErD;;GAEG;AACH,SAAS,qBAAqB;IAC5B,IAAI,CAAC;QACH,IAAM,OAAO,GAAG,uBAAQ,CAAC,SAAS,CAAC,kBAAkB,CAAC;QACtD,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACrC,IAAA,KAAsC,OAK3C,EALO,KAAK,WAAA,EAAE,KAAK,WAAA,EAAE,KAAK,WAAA,EAAE,UAAU,gBAKtC,CAAC;YACF,IAAI,aAAa,GAAG,UAAG,KAAK,cAAI,KAAK,cAAI,KAAK,CAAE,CAAC;YACjD,IAAI,UAAU,EAAE,CAAC;gBACf,aAAa,IAAI,cAAO,UAAU,CAAE,CAAC;YACvC,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAa,EAAE,KAAa;IAC5D,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClE,CAAC;AAED,SAAS,+BAA+B,CAAC,YAAoB;IAC3D,OAAO,uBAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;AAC3E,CAAC;AAED,SAAS,kCAAkC,CAAC,KAAa;IACvD,8EAA8E;IAC9E,oBAAoB;IACpB,IAAI,uBAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wEAAwE;IACxE,uEAAuE;IACvE,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,kCAAU,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAiB;IAC5C,2EAA2E;IAC3E,gEAAgE;IAChE,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,uBAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QACvD,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,SAAe,iBAAiB;;;;;;oBACxB,UAAU,GAAG,kCAAU,CAAC,aAAa,EAAE,CAAC;oBACxC,aAAa,GAAG,kCAAU,CAAC,gBAAgB,EAAE,CAAC;yBAEhD,CAAA,uBAAQ,CAAC,EAAE,KAAK,SAAS,CAAA,EAAzB,wBAAyB;;;;oBAER,qBAAM,kCAAU,CAAC,WAAW,EAAE,EAAA;;oBAAzC,QAAQ,GAAG,SAA8B;oBAC/C,sBAAO,UAAG,UAAU,cAAI,aAAa,mBAAS,QAAQ,MAAG,EAAC;;;oBAE1D,sBAAO,UAAG,UAAU,cAAI,aAAa,CAAE,EAAC;wBAI5C,sBAAO,UAAG,UAAU,cAAI,aAAa,CAAE,EAAC;;;;CACzC;AAED,SAAe,kBAAkB;;;;;;;oBAIb,qBAAM,kCAAU,CAAC,UAAU,EAAE,EAAA;;oBAAvC,OAAO,GAAG,SAA6B;oBAC7C,sBAAO,OAAO,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAC;;;oBAE9D,sBAAO,SAAS,EAAC;;;;;CAEpB;AAED;;;GAGG;AACH,SAAgB,8BAA8B;IAC5C,OAAO;QACL,oBAAoB,EAAE,qBAAqB,EAAE;KAC9C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAsB,oBAAoB;;;;wBAChC,qBAAM,iBAAiB,EAAE,EAAA;wBAAjC,sBAAO,CAAC,SAAyB,CAAC,CAAC,iBAAiB,EAAC;;;;CACtD;AAED,SAAe,iBAAiB;;;;;;;oBAE8B,qBAAM,OAAO,CAAC,GAAG,CAAC;4BAC1E,iBAAiB,EAAE;4BACnB,kBAAkB,EAAE;4BACpB,IAAA,kCAAiB,GAAE;yBACpB,CAAC,EAAA;;oBAJI,KAAoD,SAIxD,EAJK,cAAc,QAAA,EAAE,eAAe,QAAA,EAAE,cAAc,QAAA;oBAOhD,UAAU,GAAG,kCAAU,CAAC,aAAa,EAAE,CAAC;oBACxC,aAAa,GAAG,kCAAU,CAAC,gBAAgB,EAAE,CAAC;oBAC9C,YAAY,GAAG,kCAAU,CAAC,mBAAmB,EAAE,CAAC;oBAChD,KAAK,GAAG,kCAAU,CAAC,QAAQ,EAAE,CAAC;oBAC9B,eAAe,GAAG,kCAAkC,CAAC,KAAK,CAAC,CAAC;oBAC5D,UAAU,GAAG,kCAAU,CAAC,iBAAiB,EAAE,CAAC;oBAC5C,KAAK,GAAG,kCAAU,CAAC,QAAQ,EAAE,CAAC;oBAC9B,UAAU,GAAG,kCAAU,CAAC,cAAc,EAAE,CAAC;oBACzC,QAAQ,GAAG,kCAAU,CAAC,QAAQ,EAAE,CAAC;oBACjC,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;oBAG3C,WAAW,GAAG,kCAAU,CAAC,kBAAkB,EAAE,CAAC;oBAC9C,UAAU,GAAG,kCAAU,CAAC,iBAAiB,EAAE,CAAC;oBAC5C,kBAAkB,GAAG,qBAAqB,EAAE,CAAC;oBAG/C,YAAY,SAAoB,CAAC;oBACjC,UAAU,SAAoB,CAAC;oBAC/B,YAAY,SAAoB,CAAC;oBACjC,OAAO,SAAoB,CAAC;;;;oBAGd,qBAAM,kCAAU,CAAC,eAAe,EAAE,EAAA;;oBAA5C,OAAO,GAAG,SAAkC;oBAClD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;wBACjB,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC;oBACnD,CAAC;;;;;;;oBAMY,KAAA,MAAM,CAAA;oBAAC,qBAAM,kCAAU,CAAC,iBAAiB,EAAE,EAAA;;oBAAxD,UAAU,GAAG,kBAAO,SAAoC,EAAC,CAAC;;;;;;;yBAMtD,CAAA,iBAAiB,IAAI,kCAAU,CAAA,EAA/B,yBAA+B;oBAClB,KAAA,MAAM,CAAA;oBACnB,qBAAO,kCAA8E,CAAC,eAAe,EAAE,EAAA;;oBADzG,YAAY,GAAG,kBACb,SAAuG,EACxG,CAAC;;;;;;;;oBAOgB,qBAAM,kCAAU,CAAC,UAAU,EAAE,EAAA;;oBAA3C,WAAW,GAAG,SAA6B;oBACjD,IAAI,WAAW,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;wBAC7C,OAAO,GAAG,WAAW,CAAC;oBACxB,CAAC;;;;;;oBAKG,UAAU,gCACd,oBAAoB,EAAE,kBAAkB,EACxC,SAAS,EAAE,UAAU,EACrB,iBAAiB,EAAE,aAAa,EAChC,gBAAgB,EAAE,cAAc,EAChC,mBAAmB,EAAE,YAAY,CAAC,WAAW,EAAE,EAC/C,YAAY,EAAE,KAAK,EACnB,iBAAiB,EAAE,UAAU,EAC7B,YAAY,EAAE,KAAK,EACnB,kBAAkB,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,IACpC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACrD,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAClD,mBAAmB,EAAE,MAAM,CAAC,WAAW,CAAC,EACxC,kBAAkB,EAAE,MAAM,CAAC,UAAU,CAAC,EACtC,oBAAoB,EAAE,YAAY,EAClC,kBAAkB,EAAE,UAAU,EAC9B,qBAAqB,EAAE,YAAY,EACnC,cAAc,EAAE,OAAO,GACxB,CAAC;oBACI,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,gBAAA,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACnD,qBAAqB,GAAG,wBAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;oBAC/D,4BAA4B,GAAG,+BAA+B,CAAC,YAAY,CAAC,CAAC;oBAC7E,MAAM,yBACP,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACzD,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,aAAa,GACvB,CAAC;oBAEF,sBAAO;4BACL,iBAAiB,EAAE,UAAU;4BAC7B,IAAI,EAAE;gCACJ,GAAG,EAAE,OAAO;gCACZ,MAAM,+BACJ,KAAK,EAAE,qBAAqB,EAC5B,WAAW,EAAE,CAAC,UAAU,EACxB,YAAY,EAAE,4BAA4B,IACvC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACjE,UAAU,EAAE,KAAK,KACd,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC5C;gCACD,EAAE,EAAE,MAAM;6BACX;yBACF,EAAC;;;oBAEqB,qBAAM,IAAA,kCAAiB,GAAE,EAAA;;oBAA1C,cAAc,GAAG,SAAyB;oBAEhD,sBAAO;4BACL,iBAAiB,EAAE,8BAA8B,EAAE;4BACnD,IAAI,EAAE;gCACJ,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,gBAAA,EAAE,CAAC,CAAC,CAAC,EAAE;6BAC9C;yBACF,EAAC;;;;;CAEL;AAED;;GAEG;AACH,SAAsB,qBAAqB;;;YACzC,sBAAO,iBAAiB,EAAE,EAAC;;;CAC5B;AAED;;;GAGG;AACH,SAAsB,kCAAkC;;;;;;;oBAE5C,qBAAM,qBAAqB,EAAE,EAAA;wBAArC,sBAAO,CAAC,SAA6B,CAAC,CAAC,iBAAiB,EAAC;;;oBAEzD,sBAAO,8BAA8B,EAAE,EAAC;;;;;CAE3C","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"]}
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';\nimport { getSessionProcessInfo } from './sessionProcess';\n\n/**\n * Session attributes for React Native\n * These attributes are automatically included with every telemetry event\n *\n * Core mobile session attributes, with additional monitoring fields\n * (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 /** Stable Android process name or Apple bundle identifier for this runtime. */\n process_name?: 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 for session attributes.\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 const processInfo = getSessionProcessInfo();\n return {\n react_native_version: getReactNativeVersion(),\n ...(processInfo == null ? {} : { process_name: processInfo.identifier }),\n };\n}\n\n/**\n * Get all session attributes\n * These attributes are automatically included with every telemetry event\n *\n * Core session attributes:\n * - react_native_version (RN framework in the host app)\n * - process_name (Android process name or iOS bundle identifier)\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\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 ...minimalSessionDeviceAttributes(),\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"]}
@@ -1,48 +1,174 @@
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
  Object.defineProperty(exports, "__esModule", { value: true });
3
14
  exports.MmkvPersistentSessionsManager = void 0;
4
15
  exports.resetMmkvSingletonForTests = resetMmkvSingletonForTests;
5
16
  var react_native_1 = require("react-native");
6
17
  var faro_core_1 = require("@grafana/faro-core");
7
- var throttle_1 = require("../../../utils/throttle");
18
+ var sessionActivity_1 = require("../sessionActivity");
19
+ var sessionProcess_1 = require("../sessionProcess");
20
+ var persistentSessionRecord_1 = require("./persistentSessionRecord");
8
21
  var sessionConstants_1 = require("./sessionConstants");
9
22
  var sessionManagerUtils_1 = require("./sessionManagerUtils");
23
+ function errorMessage(error) {
24
+ return error instanceof Error ? error.message : String(error);
25
+ }
26
+ function loadMmkvModule() {
27
+ try {
28
+ return require('react-native-mmkv');
29
+ }
30
+ catch (error) {
31
+ throw new Error("react-native-mmkv could not be loaded. Install it and rebuild the native project. ".concat(errorMessage(error)));
32
+ }
33
+ }
34
+ function mmkvConfiguration(mmkv, storageId, isIosExtension) {
35
+ var _a;
36
+ if (!isIosExtension) {
37
+ return { id: storageId };
38
+ }
39
+ if (typeof mmkv.createMMKV === 'function') {
40
+ return { id: storageId, mode: 'multi-process' };
41
+ }
42
+ var legacyMultiProcessMode = (_a = mmkv.Mode) === null || _a === void 0 ? void 0 : _a.MULTI_PROCESS;
43
+ if (typeof legacyMultiProcessMode !== 'number') {
44
+ throw new Error('Persisting sessions in an iOS extension requires react-native-mmkv v3 or newer.');
45
+ }
46
+ return { id: storageId, mode: legacyMultiProcessMode };
47
+ }
10
48
  function createMmkvInstance() {
49
+ // Load MMKV before taking native ownership so a missing dependency cannot
50
+ // leave the process-wide claim occupied.
51
+ var mmkv = loadMmkvModule();
52
+ var processInfo = (0, sessionProcess_1.getSessionProcessInfo)();
53
+ var storageId = (0, sessionProcess_1.claimSessionPersistenceStorageId)();
54
+ if (storageId == null || processInfo == null) {
55
+ throw new Error('Native session-storage coordination is unavailable or already owned by another runtime. Rebuild the native app after upgrading Faro, or use sessionTracking.persistent=false in runtimes that cannot own storage.');
56
+ }
11
57
  try {
12
- var MMKV = require('react-native-mmkv').MMKV;
13
- return new MMKV({ id: 'grafana-faro-react-native-session' });
58
+ var configuration = mmkvConfiguration(mmkv, storageId, react_native_1.Platform.OS === 'ios' && !processInfo.isMain);
59
+ // react-native-mmkv v4 was rewritten to Nitro and removed the `new MMKV()`
60
+ // class constructor in favor of a `createMMKV()` factory (see the v4 upgrade
61
+ // guide). Support both so v2/v3 (class) and v4+ (factory) work.
62
+ if (typeof mmkv.createMMKV === 'function') {
63
+ return mmkv.createMMKV(configuration);
64
+ }
65
+ if (typeof mmkv.MMKV !== 'function') {
66
+ throw new Error('The installed react-native-mmkv package does not expose a supported storage API.');
67
+ }
68
+ return new mmkv.MMKV(configuration);
14
69
  }
15
- catch (_a) {
16
- throw new Error('sessionTracking.persistent is true but react-native-mmkv could not be loaded. Install it: yarn add react-native-mmkv, then rebuild native projects.');
70
+ catch (error) {
71
+ (0, sessionProcess_1.releaseSessionPersistenceOwnership)();
72
+ throw new Error("Session persistence could not be initialized. ".concat(errorMessage(error)));
17
73
  }
18
74
  }
75
+ // undefined means MMKV has not been resolved; null means it is unavailable.
19
76
  var mmkvSingleton;
20
- function getMmkv() {
21
- if (mmkvSingleton == null) {
77
+ // undefined means storage has not been read, null means no persisted state is
78
+ // available, and a session is the live value for this JavaScript runtime.
79
+ var runtimeSession;
80
+ function tryGetMmkv() {
81
+ var _a, _b;
82
+ if (mmkvSingleton !== undefined) {
83
+ return mmkvSingleton;
84
+ }
85
+ try {
22
86
  mmkvSingleton = createMmkvInstance();
23
87
  }
88
+ catch (error) {
89
+ mmkvSingleton = null;
90
+ (_b = (_a = faro_core_1.faro.unpatchedConsole) === null || _a === void 0 ? void 0 : _a.warn) === null || _b === void 0 ? void 0 : _b.call(_a, 'Session persistence is unavailable; using an in-memory session:', error);
91
+ }
24
92
  return mmkvSingleton;
25
93
  }
94
+ function removeMmkvValue(mmkv, key) {
95
+ var compatibleMmkv = mmkv;
96
+ if (typeof compatibleMmkv.remove === 'function') {
97
+ compatibleMmkv.remove(key);
98
+ return;
99
+ }
100
+ if (typeof compatibleMmkv.delete === 'function') {
101
+ compatibleMmkv.delete(key);
102
+ return;
103
+ }
104
+ throw new Error('The installed react-native-mmkv version cannot remove stored values.');
105
+ }
26
106
  /** @internal */
27
107
  function resetMmkvSingletonForTests() {
28
108
  mmkvSingleton = undefined;
109
+ runtimeSession = undefined;
29
110
  }
30
111
  /**
31
112
  * Persistent session storage backed by MMKV (synchronous reads/writes).
32
113
  * Used when `sessionTracking.persistent` is true.
33
114
  */
34
115
  var MmkvPersistentSessionsManager = /** @class */ (function () {
35
- function MmkvPersistentSessionsManager() {
116
+ function MmkvPersistentSessionsManager(metas) {
117
+ if (metas === void 0) { metas = faro_core_1.faro.metas; }
36
118
  var _this = this;
37
119
  this.appStateSubscription = null;
38
- this.metaUnsubscribe = null;
39
- this.updateSession = (0, throttle_1.throttle)(function () { return _this.updateUserSession(); }, sessionConstants_1.STORAGE_UPDATE_DELAY);
120
+ this.activityWriteTimer = null;
121
+ this.hasPendingActivityWrite = false;
122
+ this.lastActivityWrite = 0;
123
+ this.wasBackgrounded = react_native_1.AppState.currentState === 'background';
124
+ this.metaUpdateHandler = null;
125
+ this.flushActivityWrite = function () {
126
+ if (_this.activityWriteTimer != null) {
127
+ clearTimeout(_this.activityWriteTimer);
128
+ _this.activityWriteTimer = null;
129
+ }
130
+ if (!_this.hasPendingActivityWrite) {
131
+ return;
132
+ }
133
+ var session = MmkvPersistentSessionsManager.fetchUserSession();
134
+ _this.hasPendingActivityWrite = false;
135
+ if (session == null) {
136
+ return;
137
+ }
138
+ MmkvPersistentSessionsManager.persistSession(session);
139
+ _this.lastActivityWrite = (0, faro_core_1.dateNow)();
140
+ };
141
+ this.recordUserSessionActivity = function (session) {
142
+ // Keep expiry checks exact in memory while limiting native storage writes.
143
+ MmkvPersistentSessionsManager.setRuntimeSession(session);
144
+ _this.hasPendingActivityWrite = true;
145
+ var elapsed = (0, faro_core_1.dateNow)() - _this.lastActivityWrite;
146
+ if (_this.lastActivityWrite === 0 || elapsed < 0 || elapsed >= sessionConstants_1.STORAGE_UPDATE_DELAY) {
147
+ _this.flushActivityWrite();
148
+ return;
149
+ }
150
+ if (_this.activityWriteTimer == null) {
151
+ _this.activityWriteTimer = setTimeout(_this.flushActivityWrite, sessionConstants_1.STORAGE_UPDATE_DELAY - elapsed);
152
+ }
153
+ };
40
154
  this.handleAppStateChange = function (nextAppState) {
41
- if (nextAppState === 'active') {
42
- _this.updateSession();
155
+ if (nextAppState === 'background') {
156
+ _this.wasBackgrounded = true;
157
+ _this.flushActivityWrite();
158
+ return;
159
+ }
160
+ if (nextAppState === 'active' && _this.wasBackgrounded) {
161
+ _this.wasBackgrounded = false;
162
+ _this.checkSession(sessionActivity_1.SessionActivityKind.Meaningful);
43
163
  }
44
164
  };
165
+ this.metas = metas;
45
166
  this.updateUserSession = (0, sessionManagerUtils_1.getUserSessionUpdater)({
167
+ fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,
168
+ recordUserSessionActivity: this.recordUserSessionActivity,
169
+ storeUserSession: MmkvPersistentSessionsManager.storeUserSession,
170
+ });
171
+ this.resetUserSession = (0, sessionManagerUtils_1.getUserSessionResetter)({
46
172
  fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,
47
173
  storeUserSession: MmkvPersistentSessionsManager.storeUserSession,
48
174
  });
@@ -50,17 +176,36 @@ var MmkvPersistentSessionsManager = /** @class */ (function () {
50
176
  }
51
177
  MmkvPersistentSessionsManager.removeUserSession = function () {
52
178
  var _a, _b;
179
+ runtimeSession = null;
180
+ var mmkv = tryGetMmkv();
181
+ if (mmkv == null) {
182
+ return;
183
+ }
53
184
  try {
54
- getMmkv().remove(sessionConstants_1.STORAGE_KEY);
185
+ removeMmkvValue(mmkv, sessionConstants_1.STORAGE_KEY);
55
186
  }
56
187
  catch (error) {
57
188
  (_b = (_a = faro_core_1.faro.unpatchedConsole) === null || _a === void 0 ? void 0 : _a.warn) === null || _b === void 0 ? void 0 : _b.call(_a, 'Failed to remove session from MMKV:', error);
58
189
  }
59
190
  };
60
191
  MmkvPersistentSessionsManager.storeUserSession = function (session) {
192
+ MmkvPersistentSessionsManager.setRuntimeSession(session);
193
+ MmkvPersistentSessionsManager.persistSession(session);
194
+ };
195
+ MmkvPersistentSessionsManager.setRuntimeSession = function (session) {
196
+ runtimeSession =
197
+ session.sessionMeta == null
198
+ ? session
199
+ : __assign(__assign({}, session), { sessionMeta: (0, sessionManagerUtils_1.toStorableSessionMeta)(session.sessionMeta) });
200
+ };
201
+ MmkvPersistentSessionsManager.persistSession = function (session) {
61
202
  var _a, _b;
203
+ var mmkv = tryGetMmkv();
204
+ if (mmkv == null) {
205
+ return;
206
+ }
62
207
  try {
63
- getMmkv().set(sessionConstants_1.STORAGE_KEY, (0, faro_core_1.stringifyExternalJson)(session));
208
+ mmkv.set(sessionConstants_1.STORAGE_KEY, (0, persistentSessionRecord_1.serializePersistentSession)(session));
64
209
  }
65
210
  catch (error) {
66
211
  (_b = (_a = faro_core_1.faro.unpatchedConsole) === null || _a === void 0 ? void 0 : _a.warn) === null || _b === void 0 ? void 0 : _b.call(_a, 'Failed to store session in MMKV:', error);
@@ -68,34 +213,64 @@ var MmkvPersistentSessionsManager = /** @class */ (function () {
68
213
  };
69
214
  MmkvPersistentSessionsManager.fetchUserSession = function () {
70
215
  var _a, _b;
216
+ if (runtimeSession !== undefined) {
217
+ return runtimeSession;
218
+ }
219
+ var mmkv = tryGetMmkv();
220
+ if (mmkv == null) {
221
+ runtimeSession = null;
222
+ return null;
223
+ }
71
224
  try {
72
- var storedSession = getMmkv().getString(sessionConstants_1.STORAGE_KEY);
73
- if (storedSession) {
74
- return JSON.parse(storedSession);
225
+ var storedSession = mmkv.getString(sessionConstants_1.STORAGE_KEY);
226
+ if (storedSession == null) {
227
+ runtimeSession = null;
228
+ return null;
75
229
  }
76
- return null;
230
+ runtimeSession = (0, persistentSessionRecord_1.parsePersistentSession)(storedSession);
231
+ if (runtimeSession == null) {
232
+ removeMmkvValue(mmkv, sessionConstants_1.STORAGE_KEY);
233
+ }
234
+ return runtimeSession;
77
235
  }
78
236
  catch (error) {
237
+ runtimeSession = null;
79
238
  (_b = (_a = faro_core_1.faro.unpatchedConsole) === null || _a === void 0 ? void 0 : _a.warn) === null || _b === void 0 ? void 0 : _b.call(_a, 'Failed to fetch session from MMKV:', error);
80
239
  return null;
81
240
  }
82
241
  };
242
+ MmkvPersistentSessionsManager.prototype.checkSession = function (activity, currentSession) {
243
+ return this.updateUserSession(activity, currentSession);
244
+ };
245
+ MmkvPersistentSessionsManager.prototype.resetSession = function () {
246
+ if (this.activityWriteTimer != null) {
247
+ clearTimeout(this.activityWriteTimer);
248
+ this.activityWriteTimer = null;
249
+ }
250
+ this.hasPendingActivityWrite = false;
251
+ var session = this.resetUserSession();
252
+ this.lastActivityWrite = (0, faro_core_1.dateNow)();
253
+ return session;
254
+ };
83
255
  MmkvPersistentSessionsManager.prototype.init = function () {
84
256
  this.appStateSubscription = react_native_1.AppState.addEventListener('change', this.handleAppStateChange);
85
- var unsubscribe = faro_core_1.faro.metas.addListener((0, sessionManagerUtils_1.getSessionMetaUpdateHandler)({
257
+ var metaUpdateHandler = (0, sessionManagerUtils_1.getSessionMetaUpdateHandler)({
86
258
  fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,
87
259
  storeUserSession: MmkvPersistentSessionsManager.storeUserSession,
88
- }));
89
- this.metaUnsubscribe = typeof unsubscribe === 'function' ? unsubscribe : null;
260
+ });
261
+ this.metas.addListener(metaUpdateHandler);
262
+ this.metaUpdateHandler = metaUpdateHandler;
90
263
  };
91
264
  MmkvPersistentSessionsManager.prototype.unpatch = function () {
265
+ this.flushActivityWrite();
92
266
  if (this.appStateSubscription) {
93
267
  this.appStateSubscription.remove();
94
268
  this.appStateSubscription = null;
95
269
  }
96
- if (this.metaUnsubscribe) {
97
- this.metaUnsubscribe();
98
- this.metaUnsubscribe = null;
270
+ var metaUpdateHandler = this.metaUpdateHandler;
271
+ this.metaUpdateHandler = null;
272
+ if (metaUpdateHandler) {
273
+ this.metas.removeListener(metaUpdateHandler);
99
274
  }
100
275
  };
101
276
  return MmkvPersistentSessionsManager;
@@ -1 +1 @@
1
- {"version":3,"file":"MmkvPersistentSessionsManager.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppState, type AppStateStatus } from 'react-native';\nimport type { MMKV } from 'react-native-mmkv';\n\nimport { faro, stringifyExternalJson } from '@grafana/faro-core';\n\nimport { throttle } from '../../../utils/throttle';\n\nimport { STORAGE_KEY, STORAGE_UPDATE_DELAY } from './sessionConstants';\nimport { getSessionMetaUpdateHandler, getUserSessionUpdater } from './sessionManagerUtils';\nimport type { FaroUserSession } from './types';\n\nfunction createMmkvInstance(): MMKV {\n try {\n const { MMKV } = require('react-native-mmkv');\n return new MMKV({ id: 'grafana-faro-react-native-session' });\n } catch {\n throw new Error(\n 'sessionTracking.persistent is true but react-native-mmkv could not be loaded. Install it: yarn add react-native-mmkv, then rebuild native projects.'\n );\n }\n}\n\nlet mmkvSingleton: MMKV | undefined;\n\nfunction getMmkv(): MMKV {\n if (mmkvSingleton == null) {\n mmkvSingleton = createMmkvInstance();\n }\n return mmkvSingleton;\n}\n\n/** @internal */\nexport function resetMmkvSingletonForTests(): void {\n mmkvSingleton = undefined;\n}\n\n/**\n * Persistent session storage backed by MMKV (synchronous reads/writes).\n * Used when `sessionTracking.persistent` is true.\n */\nexport class MmkvPersistentSessionsManager {\n private updateUserSession: ReturnType<typeof getUserSessionUpdater>;\n private appStateSubscription: ReturnType<typeof AppState.addEventListener> | null = null;\n private metaUnsubscribe: (() => void) | null = null;\n\n constructor() {\n this.updateUserSession = getUserSessionUpdater({\n fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,\n storeUserSession: MmkvPersistentSessionsManager.storeUserSession,\n });\n\n this.init();\n }\n\n static removeUserSession(): void {\n try {\n getMmkv().remove(STORAGE_KEY);\n } catch (error) {\n faro.unpatchedConsole?.warn?.('Failed to remove session from MMKV:', error);\n }\n }\n\n static storeUserSession(session: FaroUserSession): void {\n try {\n getMmkv().set(STORAGE_KEY, stringifyExternalJson(session));\n } catch (error) {\n faro.unpatchedConsole?.warn?.('Failed to store session in MMKV:', error);\n }\n }\n\n static fetchUserSession(): FaroUserSession | null {\n try {\n const storedSession = getMmkv().getString(STORAGE_KEY);\n if (storedSession) {\n return JSON.parse(storedSession) as FaroUserSession;\n }\n return null;\n } catch (error) {\n faro.unpatchedConsole?.warn?.('Failed to fetch session from MMKV:', error);\n return null;\n }\n }\n\n updateSession = throttle(() => this.updateUserSession(), STORAGE_UPDATE_DELAY);\n\n private handleAppStateChange = (nextAppState: AppStateStatus) => {\n if (nextAppState === 'active') {\n this.updateSession();\n }\n };\n\n private init(): void {\n this.appStateSubscription = AppState.addEventListener('change', this.handleAppStateChange);\n\n const unsubscribe = faro.metas.addListener(\n getSessionMetaUpdateHandler({\n fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,\n storeUserSession: MmkvPersistentSessionsManager.storeUserSession,\n })\n );\n this.metaUnsubscribe = typeof unsubscribe === 'function' ? unsubscribe : null;\n }\n\n unpatch(): void {\n if (this.appStateSubscription) {\n this.appStateSubscription.remove();\n this.appStateSubscription = null;\n }\n\n if (this.metaUnsubscribe) {\n this.metaUnsubscribe();\n this.metaUnsubscribe = null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"MmkvPersistentSessionsManager.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppState, type AppStateStatus, Platform } from 'react-native';\nimport type { MMKV } from 'react-native-mmkv';\n\nimport { dateNow, faro } from '@grafana/faro-core';\nimport type { Metas } from '@grafana/faro-core';\n\nimport { SessionActivityKind } from '../sessionActivity';\nimport {\n claimSessionPersistenceStorageId,\n getSessionProcessInfo,\n releaseSessionPersistenceOwnership,\n} from '../sessionProcess';\n\nimport { parsePersistentSession, serializePersistentSession } from './persistentSessionRecord';\nimport { STORAGE_KEY, STORAGE_UPDATE_DELAY } from './sessionConstants';\nimport {\n getSessionMetaUpdateHandler,\n getUserSessionResetter,\n getUserSessionUpdater,\n toStorableSessionMeta,\n} from './sessionManagerUtils';\nimport type { FaroUserSession } from './types';\n\ntype MmkvConfiguration = {\n id: string;\n mode?: number | 'multi-process';\n};\n\ntype MmkvModule = {\n createMMKV?: (configuration: MmkvConfiguration) => MMKV;\n MMKV?: new (configuration: MmkvConfiguration) => MMKV;\n Mode?: { MULTI_PROCESS?: number };\n};\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction loadMmkvModule(): MmkvModule {\n try {\n return require('react-native-mmkv') as MmkvModule;\n } catch (error) {\n throw new Error(\n `react-native-mmkv could not be loaded. Install it and rebuild the native project. ${errorMessage(error)}`\n );\n }\n}\n\nfunction mmkvConfiguration(mmkv: MmkvModule, storageId: string, isIosExtension: boolean): MmkvConfiguration {\n if (!isIosExtension) {\n return { id: storageId };\n }\n\n if (typeof mmkv.createMMKV === 'function') {\n return { id: storageId, mode: 'multi-process' };\n }\n\n const legacyMultiProcessMode = mmkv.Mode?.MULTI_PROCESS;\n if (typeof legacyMultiProcessMode !== 'number') {\n throw new Error('Persisting sessions in an iOS extension requires react-native-mmkv v3 or newer.');\n }\n\n return { id: storageId, mode: legacyMultiProcessMode };\n}\n\nfunction createMmkvInstance(): MMKV {\n // Load MMKV before taking native ownership so a missing dependency cannot\n // leave the process-wide claim occupied.\n const mmkv = loadMmkvModule();\n const processInfo = getSessionProcessInfo();\n const storageId = claimSessionPersistenceStorageId();\n if (storageId == null || processInfo == null) {\n throw new Error(\n 'Native session-storage coordination is unavailable or already owned by another runtime. Rebuild the native app after upgrading Faro, or use sessionTracking.persistent=false in runtimes that cannot own storage.'\n );\n }\n\n try {\n const configuration = mmkvConfiguration(mmkv, storageId, Platform.OS === 'ios' && !processInfo.isMain);\n // react-native-mmkv v4 was rewritten to Nitro and removed the `new MMKV()`\n // class constructor in favor of a `createMMKV()` factory (see the v4 upgrade\n // guide). Support both so v2/v3 (class) and v4+ (factory) work.\n if (typeof mmkv.createMMKV === 'function') {\n return mmkv.createMMKV(configuration);\n }\n if (typeof mmkv.MMKV !== 'function') {\n throw new Error('The installed react-native-mmkv package does not expose a supported storage API.');\n }\n return new mmkv.MMKV(configuration);\n } catch (error) {\n releaseSessionPersistenceOwnership();\n throw new Error(`Session persistence could not be initialized. ${errorMessage(error)}`);\n }\n}\n\n// undefined means MMKV has not been resolved; null means it is unavailable.\nlet mmkvSingleton: MMKV | null | undefined;\n// undefined means storage has not been read, null means no persisted state is\n// available, and a session is the live value for this JavaScript runtime.\nlet runtimeSession: FaroUserSession | null | undefined;\n\nfunction tryGetMmkv(): MMKV | null {\n if (mmkvSingleton !== undefined) {\n return mmkvSingleton;\n }\n\n try {\n mmkvSingleton = createMmkvInstance();\n } catch (error) {\n mmkvSingleton = null;\n faro.unpatchedConsole?.warn?.('Session persistence is unavailable; using an in-memory session:', error);\n }\n\n return mmkvSingleton;\n}\n\nfunction removeMmkvValue(mmkv: MMKV, key: string): void {\n const compatibleMmkv = mmkv as MMKV & {\n delete?: (storageKey: string) => void;\n remove?: (storageKey: string) => void;\n };\n\n if (typeof compatibleMmkv.remove === 'function') {\n compatibleMmkv.remove(key);\n return;\n }\n if (typeof compatibleMmkv.delete === 'function') {\n compatibleMmkv.delete(key);\n return;\n }\n\n throw new Error('The installed react-native-mmkv version cannot remove stored values.');\n}\n\n/** @internal */\nexport function resetMmkvSingletonForTests(): void {\n mmkvSingleton = undefined;\n runtimeSession = undefined;\n}\n\n/**\n * Persistent session storage backed by MMKV (synchronous reads/writes).\n * Used when `sessionTracking.persistent` is true.\n */\nexport class MmkvPersistentSessionsManager {\n private resetUserSession: ReturnType<typeof getUserSessionResetter>;\n private updateUserSession: ReturnType<typeof getUserSessionUpdater>;\n private appStateSubscription: ReturnType<typeof AppState.addEventListener> | null = null;\n private activityWriteTimer: ReturnType<typeof setTimeout> | null = null;\n private hasPendingActivityWrite = false;\n private lastActivityWrite = 0;\n private wasBackgrounded = AppState.currentState === 'background';\n private metaUpdateHandler: ReturnType<typeof getSessionMetaUpdateHandler> | null = null;\n private readonly metas: Metas;\n\n constructor(metas: Metas = faro.metas) {\n this.metas = metas;\n this.updateUserSession = getUserSessionUpdater({\n fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,\n recordUserSessionActivity: this.recordUserSessionActivity,\n storeUserSession: MmkvPersistentSessionsManager.storeUserSession,\n });\n this.resetUserSession = getUserSessionResetter({\n fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,\n storeUserSession: MmkvPersistentSessionsManager.storeUserSession,\n });\n\n this.init();\n }\n\n static removeUserSession(): void {\n runtimeSession = null;\n const mmkv = tryGetMmkv();\n if (mmkv == null) {\n return;\n }\n try {\n removeMmkvValue(mmkv, STORAGE_KEY);\n } catch (error) {\n faro.unpatchedConsole?.warn?.('Failed to remove session from MMKV:', error);\n }\n }\n\n static storeUserSession(session: FaroUserSession): void {\n MmkvPersistentSessionsManager.setRuntimeSession(session);\n MmkvPersistentSessionsManager.persistSession(session);\n }\n\n private static setRuntimeSession(session: FaroUserSession): void {\n runtimeSession =\n session.sessionMeta == null\n ? session\n : {\n ...session,\n sessionMeta: toStorableSessionMeta(session.sessionMeta),\n };\n }\n\n private static persistSession(session: FaroUserSession): void {\n const mmkv = tryGetMmkv();\n if (mmkv == null) {\n return;\n }\n try {\n mmkv.set(STORAGE_KEY, serializePersistentSession(session));\n } catch (error) {\n faro.unpatchedConsole?.warn?.('Failed to store session in MMKV:', error);\n }\n }\n\n static fetchUserSession(): FaroUserSession | null {\n if (runtimeSession !== undefined) {\n return runtimeSession;\n }\n\n const mmkv = tryGetMmkv();\n if (mmkv == null) {\n runtimeSession = null;\n return null;\n }\n\n try {\n const storedSession = mmkv.getString(STORAGE_KEY);\n if (storedSession == null) {\n runtimeSession = null;\n return null;\n }\n\n runtimeSession = parsePersistentSession(storedSession);\n if (runtimeSession == null) {\n removeMmkvValue(mmkv, STORAGE_KEY);\n }\n return runtimeSession;\n } catch (error) {\n runtimeSession = null;\n faro.unpatchedConsole?.warn?.('Failed to fetch session from MMKV:', error);\n return null;\n }\n }\n\n checkSession(activity: SessionActivityKind, currentSession?: FaroUserSession | null): FaroUserSession {\n return this.updateUserSession(activity, currentSession);\n }\n\n resetSession(): FaroUserSession {\n if (this.activityWriteTimer != null) {\n clearTimeout(this.activityWriteTimer);\n this.activityWriteTimer = null;\n }\n this.hasPendingActivityWrite = false;\n\n const session = this.resetUserSession();\n this.lastActivityWrite = dateNow();\n return session;\n }\n\n private flushActivityWrite = (): void => {\n if (this.activityWriteTimer != null) {\n clearTimeout(this.activityWriteTimer);\n this.activityWriteTimer = null;\n }\n\n if (!this.hasPendingActivityWrite) {\n return;\n }\n\n const session = MmkvPersistentSessionsManager.fetchUserSession();\n this.hasPendingActivityWrite = false;\n if (session == null) {\n return;\n }\n\n MmkvPersistentSessionsManager.persistSession(session);\n this.lastActivityWrite = dateNow();\n };\n\n private recordUserSessionActivity = (session: FaroUserSession): void => {\n // Keep expiry checks exact in memory while limiting native storage writes.\n MmkvPersistentSessionsManager.setRuntimeSession(session);\n this.hasPendingActivityWrite = true;\n\n const elapsed = dateNow() - this.lastActivityWrite;\n if (this.lastActivityWrite === 0 || elapsed < 0 || elapsed >= STORAGE_UPDATE_DELAY) {\n this.flushActivityWrite();\n return;\n }\n\n if (this.activityWriteTimer == null) {\n this.activityWriteTimer = setTimeout(this.flushActivityWrite, STORAGE_UPDATE_DELAY - elapsed);\n }\n };\n\n private handleAppStateChange = (nextAppState: AppStateStatus) => {\n if (nextAppState === 'background') {\n this.wasBackgrounded = true;\n this.flushActivityWrite();\n return;\n }\n\n if (nextAppState === 'active' && this.wasBackgrounded) {\n this.wasBackgrounded = false;\n this.checkSession(SessionActivityKind.Meaningful);\n }\n };\n\n private init(): void {\n this.appStateSubscription = AppState.addEventListener('change', this.handleAppStateChange);\n\n const metaUpdateHandler = getSessionMetaUpdateHandler({\n fetchUserSession: MmkvPersistentSessionsManager.fetchUserSession,\n storeUserSession: MmkvPersistentSessionsManager.storeUserSession,\n });\n this.metas.addListener(metaUpdateHandler);\n this.metaUpdateHandler = metaUpdateHandler;\n }\n\n unpatch(): void {\n this.flushActivityWrite();\n\n if (this.appStateSubscription) {\n this.appStateSubscription.remove();\n this.appStateSubscription = null;\n }\n\n const metaUpdateHandler = this.metaUpdateHandler;\n this.metaUpdateHandler = null;\n if (metaUpdateHandler) {\n this.metas.removeListener(metaUpdateHandler);\n }\n }\n}\n"]}
@@ -3,24 +3,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VolatileSessionsManager = void 0;
4
4
  var react_native_1 = require("react-native");
5
5
  var faro_core_1 = require("@grafana/faro-core");
6
- var throttle_1 = require("../../../utils/throttle");
7
- var sessionConstants_1 = require("./sessionConstants");
6
+ var sessionActivity_1 = require("../sessionActivity");
8
7
  var sessionManagerUtils_1 = require("./sessionManagerUtils");
9
8
  var VolatileSessionsManager = /** @class */ (function () {
10
- function VolatileSessionsManager() {
9
+ function VolatileSessionsManager(metas) {
10
+ if (metas === void 0) { metas = faro_core_1.faro.metas; }
11
11
  var _this = this;
12
12
  this.appStateSubscription = null;
13
- this.metaUnsubscribe = null;
14
- this.updateSession = (0, throttle_1.throttle)(function () { return _this.updateUserSession(); }, sessionConstants_1.STORAGE_UPDATE_DELAY);
13
+ this.wasBackgrounded = react_native_1.AppState.currentState === 'background';
14
+ this.metaUpdateHandler = null;
15
15
  this.handleAppStateChange = function (nextAppState) {
16
- if (nextAppState === 'active') {
17
- _this.updateSession();
16
+ if (nextAppState === 'background') {
17
+ _this.wasBackgrounded = true;
18
+ return;
19
+ }
20
+ if (nextAppState === 'active' && _this.wasBackgrounded) {
21
+ _this.wasBackgrounded = false;
22
+ _this.checkSession(sessionActivity_1.SessionActivityKind.Meaningful);
18
23
  }
19
24
  };
25
+ this.metas = metas;
20
26
  this.updateUserSession = (0, sessionManagerUtils_1.getUserSessionUpdater)({
21
27
  fetchUserSession: VolatileSessionsManager.fetchUserSession,
22
28
  storeUserSession: VolatileSessionsManager.storeUserSession,
23
29
  });
30
+ this.resetUserSession = (0, sessionManagerUtils_1.getUserSessionResetter)({
31
+ fetchUserSession: VolatileSessionsManager.fetchUserSession,
32
+ storeUserSession: VolatileSessionsManager.storeUserSession,
33
+ });
24
34
  this.init();
25
35
  }
26
36
  VolatileSessionsManager.removeUserSession = function () {
@@ -32,15 +42,22 @@ var VolatileSessionsManager = /** @class */ (function () {
32
42
  VolatileSessionsManager.fetchUserSession = function () {
33
43
  return VolatileSessionsManager.volatileStorage;
34
44
  };
45
+ VolatileSessionsManager.prototype.checkSession = function (activity, currentSession) {
46
+ return this.updateUserSession(activity, currentSession);
47
+ };
48
+ VolatileSessionsManager.prototype.resetSession = function () {
49
+ return this.resetUserSession();
50
+ };
35
51
  VolatileSessionsManager.prototype.init = function () {
36
52
  // Listen to app state changes (equivalent to visibilitychange in web)
37
53
  this.appStateSubscription = react_native_1.AppState.addEventListener('change', this.handleAppStateChange);
38
54
  // Users can call the setSession() method, so we need to sync this with the in-memory session
39
- var unsubscribe = faro_core_1.faro.metas.addListener((0, sessionManagerUtils_1.getSessionMetaUpdateHandler)({
55
+ var metaUpdateHandler = (0, sessionManagerUtils_1.getSessionMetaUpdateHandler)({
40
56
  fetchUserSession: VolatileSessionsManager.fetchUserSession,
41
57
  storeUserSession: VolatileSessionsManager.storeUserSession,
42
- }));
43
- this.metaUnsubscribe = typeof unsubscribe === 'function' ? unsubscribe : null;
58
+ });
59
+ this.metas.addListener(metaUpdateHandler);
60
+ this.metaUpdateHandler = metaUpdateHandler;
44
61
  };
45
62
  /**
46
63
  * Clean up listeners when the instrumentation is unpatched
@@ -50,9 +67,10 @@ var VolatileSessionsManager = /** @class */ (function () {
50
67
  this.appStateSubscription.remove();
51
68
  this.appStateSubscription = null;
52
69
  }
53
- if (this.metaUnsubscribe) {
54
- this.metaUnsubscribe();
55
- this.metaUnsubscribe = null;
70
+ var metaUpdateHandler = this.metaUpdateHandler;
71
+ this.metaUpdateHandler = null;
72
+ if (metaUpdateHandler) {
73
+ this.metas.removeListener(metaUpdateHandler);
56
74
  }
57
75
  };
58
76
  VolatileSessionsManager.volatileStorage = null;
@@ -1 +1 @@
1
- {"version":3,"file":"VolatileSessionManager.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/VolatileSessionManager.ts"],"names":[],"mappings":";;;AAAA,6CAA6D;AAE7D,gDAA0C;AAE1C,oDAAmD;AAEnD,uDAA0D;AAC1D,6DAA2F;AAG3F;IAME;QAAA,iBAOC;QAVO,yBAAoB,GAAwD,IAAI,CAAC;QACjF,oBAAe,GAAwB,IAAI,CAAC;QAuBpD,kBAAa,GAAG,IAAA,mBAAQ,EAAC,cAAM,OAAA,KAAI,CAAC,iBAAiB,EAAE,EAAxB,CAAwB,EAAE,uCAAoB,CAAC,CAAC;QAEvE,yBAAoB,GAAG,UAAC,YAA4B;YAC1D,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;gBAC9B,KAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC;QACH,CAAC,CAAC;QA1BA,IAAI,CAAC,iBAAiB,GAAG,IAAA,2CAAqB,EAAC;YAC7C,gBAAgB,EAAE,uBAAuB,CAAC,gBAAgB;YAC1D,gBAAgB,EAAE,uBAAuB,CAAC,gBAAgB;SAC3D,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAEM,yCAAiB,GAAxB;QACE,uBAAuB,CAAC,eAAe,GAAG,IAAI,CAAC;IACjD,CAAC;IAEM,wCAAgB,GAAvB,UAAwB,OAAwB;QAC9C,uBAAuB,CAAC,eAAe,GAAG,OAAO,CAAC;IACpD,CAAC;IAEM,wCAAgB,GAAvB;QACE,OAAO,uBAAuB,CAAC,eAAe,CAAC;IACjD,CAAC;IAUO,sCAAI,GAAZ;QACE,sEAAsE;QACtE,IAAI,CAAC,oBAAoB,GAAG,uBAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE3F,6FAA6F;QAC7F,IAAM,WAAW,GAAG,gBAAI,CAAC,KAAK,CAAC,WAAW,CACxC,IAAA,iDAA2B,EAAC;YAC1B,gBAAgB,EAAE,uBAAuB,CAAC,gBAAgB;YAC1D,gBAAgB,EAAE,uBAAuB,CAAC,gBAAgB;SAC3D,CAAC,CACH,CAAC;QACF,IAAI,CAAC,eAAe,GAAG,OAAO,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;IAChF,CAAC;IAED;;OAEG;IACH,yCAAO,GAAP;QACE,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC9B,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,CAAC;YACnC,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;QACnC,CAAC;QAED,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC;IA7Dc,uCAAe,GAA2B,IAAI,AAA/B,CAAgC;IA8DhE,8BAAC;CAAA,AA/DD,IA+DC;AA/DY,0DAAuB","sourcesContent":["import { AppState, type AppStateStatus } from 'react-native';\n\nimport { faro } from '@grafana/faro-core';\n\nimport { throttle } from '../../../utils/throttle';\n\nimport { STORAGE_UPDATE_DELAY } from './sessionConstants';\nimport { getSessionMetaUpdateHandler, getUserSessionUpdater } from './sessionManagerUtils';\nimport type { FaroUserSession } from './types';\n\nexport class VolatileSessionsManager {\n private static volatileStorage: FaroUserSession | null = null;\n private updateUserSession: ReturnType<typeof getUserSessionUpdater>;\n private appStateSubscription: ReturnType<typeof AppState.addEventListener> | null = null;\n private metaUnsubscribe: (() => void) | null = null;\n\n constructor() {\n this.updateUserSession = getUserSessionUpdater({\n fetchUserSession: VolatileSessionsManager.fetchUserSession,\n storeUserSession: VolatileSessionsManager.storeUserSession,\n });\n\n this.init();\n }\n\n static removeUserSession(): void {\n VolatileSessionsManager.volatileStorage = null;\n }\n\n static storeUserSession(session: FaroUserSession): void {\n VolatileSessionsManager.volatileStorage = session;\n }\n\n static fetchUserSession(): FaroUserSession | null {\n return VolatileSessionsManager.volatileStorage;\n }\n\n updateSession = throttle(() => this.updateUserSession(), STORAGE_UPDATE_DELAY);\n\n private handleAppStateChange = (nextAppState: AppStateStatus) => {\n if (nextAppState === 'active') {\n this.updateSession();\n }\n };\n\n private init(): void {\n // Listen to app state changes (equivalent to visibilitychange in web)\n this.appStateSubscription = AppState.addEventListener('change', this.handleAppStateChange);\n\n // Users can call the setSession() method, so we need to sync this with the in-memory session\n const unsubscribe = faro.metas.addListener(\n getSessionMetaUpdateHandler({\n fetchUserSession: VolatileSessionsManager.fetchUserSession,\n storeUserSession: VolatileSessionsManager.storeUserSession,\n })\n );\n this.metaUnsubscribe = typeof unsubscribe === 'function' ? unsubscribe : null;\n }\n\n /**\n * Clean up listeners when the instrumentation is unpatched\n */\n unpatch(): void {\n if (this.appStateSubscription) {\n this.appStateSubscription.remove();\n this.appStateSubscription = null;\n }\n\n if (this.metaUnsubscribe) {\n this.metaUnsubscribe();\n this.metaUnsubscribe = null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"VolatileSessionManager.js","sourceRoot":"","sources":["../../../../../src/instrumentations/session/sessionManager/VolatileSessionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppState, type AppStateStatus } from 'react-native';\n\nimport { faro } from '@grafana/faro-core';\nimport type { Metas } from '@grafana/faro-core';\n\nimport { SessionActivityKind } from '../sessionActivity';\n\nimport { getSessionMetaUpdateHandler, getUserSessionResetter, getUserSessionUpdater } from './sessionManagerUtils';\nimport type { FaroUserSession } from './types';\n\nexport class VolatileSessionsManager {\n private static volatileStorage: FaroUserSession | null = null;\n private resetUserSession: ReturnType<typeof getUserSessionResetter>;\n private updateUserSession: ReturnType<typeof getUserSessionUpdater>;\n private appStateSubscription: ReturnType<typeof AppState.addEventListener> | null = null;\n private wasBackgrounded = AppState.currentState === 'background';\n private metaUpdateHandler: ReturnType<typeof getSessionMetaUpdateHandler> | null = null;\n private readonly metas: Metas;\n\n constructor(metas: Metas = faro.metas) {\n this.metas = metas;\n this.updateUserSession = getUserSessionUpdater({\n fetchUserSession: VolatileSessionsManager.fetchUserSession,\n storeUserSession: VolatileSessionsManager.storeUserSession,\n });\n this.resetUserSession = getUserSessionResetter({\n fetchUserSession: VolatileSessionsManager.fetchUserSession,\n storeUserSession: VolatileSessionsManager.storeUserSession,\n });\n\n this.init();\n }\n\n static removeUserSession(): void {\n VolatileSessionsManager.volatileStorage = null;\n }\n\n static storeUserSession(session: FaroUserSession): void {\n VolatileSessionsManager.volatileStorage = session;\n }\n\n static fetchUserSession(): FaroUserSession | null {\n return VolatileSessionsManager.volatileStorage;\n }\n\n checkSession(activity: SessionActivityKind, currentSession?: FaroUserSession | null): FaroUserSession {\n return this.updateUserSession(activity, currentSession);\n }\n\n resetSession(): FaroUserSession {\n return this.resetUserSession();\n }\n\n private handleAppStateChange = (nextAppState: AppStateStatus) => {\n if (nextAppState === 'background') {\n this.wasBackgrounded = true;\n return;\n }\n\n if (nextAppState === 'active' && this.wasBackgrounded) {\n this.wasBackgrounded = false;\n this.checkSession(SessionActivityKind.Meaningful);\n }\n };\n\n private init(): void {\n // Listen to app state changes (equivalent to visibilitychange in web)\n this.appStateSubscription = AppState.addEventListener('change', this.handleAppStateChange);\n\n // Users can call the setSession() method, so we need to sync this with the in-memory session\n const metaUpdateHandler = getSessionMetaUpdateHandler({\n fetchUserSession: VolatileSessionsManager.fetchUserSession,\n storeUserSession: VolatileSessionsManager.storeUserSession,\n });\n this.metas.addListener(metaUpdateHandler);\n this.metaUpdateHandler = metaUpdateHandler;\n }\n\n /**\n * Clean up listeners when the instrumentation is unpatched\n */\n unpatch(): void {\n if (this.appStateSubscription) {\n this.appStateSubscription.remove();\n this.appStateSubscription = null;\n }\n\n const metaUpdateHandler = this.metaUpdateHandler;\n this.metaUpdateHandler = null;\n if (metaUpdateHandler) {\n this.metas.removeListener(metaUpdateHandler);\n }\n }\n}\n"]}
@@ -0,0 +1,72 @@
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
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.PERSISTED_SESSION_SCHEMA_VERSION = void 0;
15
+ exports.serializePersistentSession = serializePersistentSession;
16
+ exports.parsePersistentSession = parsePersistentSession;
17
+ exports.PERSISTED_SESSION_SCHEMA_VERSION = 1;
18
+ function isRecord(value) {
19
+ return typeof value === 'object' && value != null && !Array.isArray(value);
20
+ }
21
+ function isNonEmptyString(value) {
22
+ return typeof value === 'string' && value.length > 0;
23
+ }
24
+ function isValidTimestamp(value) {
25
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0;
26
+ }
27
+ function serializePersistentSession(session) {
28
+ var _a, _b;
29
+ var previousSession = (_b = (_a = session.sessionMeta) === null || _a === void 0 ? void 0 : _a.attributes) === null || _b === void 0 ? void 0 : _b['previousSession'];
30
+ var record = {
31
+ schemaVersion: exports.PERSISTED_SESSION_SCHEMA_VERSION,
32
+ currentSessionId: session.sessionId,
33
+ previousSessionId: isNonEmptyString(previousSession) ? previousSession : null,
34
+ startedAt: session.started,
35
+ // Preserve the record invariant if the device clock moves backwards after
36
+ // the session starts.
37
+ lastActivityAt: Math.max(session.started, session.lastActivity),
38
+ isSampled: session.isSampled,
39
+ };
40
+ return JSON.stringify(record);
41
+ }
42
+ function parsePersistentSession(serialized) {
43
+ var value;
44
+ try {
45
+ value = JSON.parse(serialized);
46
+ }
47
+ catch (_a) {
48
+ return null;
49
+ }
50
+ if (!isRecord(value) ||
51
+ value['schemaVersion'] !== exports.PERSISTED_SESSION_SCHEMA_VERSION ||
52
+ !isNonEmptyString(value['currentSessionId']) ||
53
+ !(value['previousSessionId'] === null || isNonEmptyString(value['previousSessionId'])) ||
54
+ !isValidTimestamp(value['startedAt']) ||
55
+ !isValidTimestamp(value['lastActivityAt']) ||
56
+ value['lastActivityAt'] < value['startedAt'] ||
57
+ typeof value['isSampled'] !== 'boolean') {
58
+ return null;
59
+ }
60
+ var previousSessionId = value['previousSessionId'];
61
+ return {
62
+ sessionId: value['currentSessionId'],
63
+ started: value['startedAt'],
64
+ lastActivity: value['lastActivityAt'],
65
+ isSampled: value['isSampled'],
66
+ sessionMeta: {
67
+ id: value['currentSessionId'],
68
+ attributes: __assign({ isSampled: value['isSampled'].toString() }, (previousSessionId == null ? {} : { previousSession: previousSessionId })),
69
+ },
70
+ };
71
+ }
72
+ //# sourceMappingURL=persistentSessionRecord.js.map