@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":"UserPersistence.js","sourceRoot":"","sources":["../../../src/userPersistence/UserPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import AsyncStorage from '@react-native-async-storage/async-storage';\n\nimport type { MetaUser } from '@grafana/faro-core';\n\nimport type { UserPersistence, UserPersistenceOptions } from './types';\n\n/**\n * Default storage key for user data.\n */\nconst DEFAULT_STORAGE_KEY = 'faro_persisted_user';\n\n/**\n * UserPersistence implementation using AsyncStorage.\n *\n * Stores user information persistently so it can be restored on app restart.\n * This ensures early telemetry events include user identification.\n *\n * Implementation follows Flutter SDK's UserPersistence pattern:\n * - Uses AsyncStorage for persistence (matching Flutter's SharedPreferences)\n * - Stores user as JSON\n * - Handles null/cleared users\n *\n * @example\n * ```typescript\n * import { createUserPersistence } from '@grafana/faro-react-native';\n *\n * // Load user on app start\n * const persistence = createUserPersistence();\n * const user = await persistence.loadUser();\n *\n * if (user) {\n * faro.api.setUser(user);\n * }\n *\n * // Save user when logged in\n * const loggedInUser = { id: '123', email: 'user@example.com' };\n * await persistence.saveUser(loggedInUser);\n *\n * // Clear on logout\n * await persistence.clearUser();\n * ```\n */\nexport class AsyncStorageUserPersistence implements UserPersistence {\n private readonly storageKey: string;\n\n constructor(options: UserPersistenceOptions = {}) {\n this.storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n }\n\n async loadUser(): Promise<MetaUser | null> {\n try {\n const userJson = await AsyncStorage.getItem(this.storageKey);\n if (userJson === null) {\n return null;\n }\n\n const userData = JSON.parse(userJson);\n if (!this.isValidMetaUser(userData)) {\n return null;\n }\n\n return userData;\n } catch {\n return null;\n }\n }\n\n async saveUser(user: MetaUser | null): Promise<void> {\n try {\n if (user === null || this.isCleared(user)) {\n await this.clearUser();\n return;\n }\n\n const userJson = JSON.stringify(user);\n await AsyncStorage.setItem(this.storageKey, userJson);\n } catch {\n // Log failure but don't throw\n }\n }\n\n async clearUser(): Promise<void> {\n try {\n await AsyncStorage.removeItem(this.storageKey);\n } catch {\n // Log failure but don't throw\n }\n }\n\n async hasPersistedUser(): Promise<boolean> {\n try {\n const userJson = await AsyncStorage.getItem(this.storageKey);\n return userJson !== null;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if user is cleared (all fields empty/undefined).\n */\n private isCleared(user: MetaUser): boolean {\n return !user.id && !user.email && !user.username && !user.fullName && !user.roles;\n }\n\n /**\n * Validate that the parsed object is a valid MetaUser.\n */\n private isValidMetaUser(obj: unknown): obj is MetaUser {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n\n // MetaUser has optional string fields, so any object is technically valid\n // We just need to make sure it's an object\n return true;\n }\n}\n\n/**\n * Factory function to create a UserPersistence instance.\n */\nexport function createUserPersistence(options: UserPersistenceOptions = {}): UserPersistence {\n return new AsyncStorageUserPersistence(options);\n}\n\n/**\n * Global user persistence instance.\n */\nlet globalUserPersistence: UserPersistence | null = null;\n\n/**\n * Initialize the global user persistence.\n */\nexport function initializeUserPersistence(options: UserPersistenceOptions = {}): UserPersistence {\n globalUserPersistence = createUserPersistence(options);\n return globalUserPersistence;\n}\n\n/**\n * Get the global user persistence instance.\n */\nexport function getUserPersistence(): UserPersistence | null {\n return globalUserPersistence;\n}\n\n/**\n * Set a custom user persistence instance.\n */\nexport function setUserPersistence(persistence: UserPersistence | null): void {\n globalUserPersistence = persistence;\n}\n"]}
1
+ {"version":3,"file":"UserPersistence.js","sourceRoot":"","sources":["../../../src/userPersistence/UserPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import AsyncStorage from '@react-native-async-storage/async-storage';\n\nimport type { MetaUser } from '@grafana/faro-core';\n\nimport type { UserPersistence, UserPersistenceOptions } from './types';\n\n/**\n * Default storage key for user data.\n */\nconst DEFAULT_STORAGE_KEY = 'faro_persisted_user';\n\n/**\n * UserPersistence implementation using AsyncStorage.\n *\n * Stores user information persistently so it can be restored on app restart.\n * This ensures early telemetry events include user identification.\n *\n * Uses AsyncStorage for persistent user data across app sessions.\n * - Stores user as JSON\n * - Handles null/cleared users\n *\n * @example\n * ```typescript\n * import { createUserPersistence } from '@grafana/faro-react-native';\n *\n * // Load user on app start\n * const persistence = createUserPersistence();\n * const user = await persistence.loadUser();\n *\n * if (user) {\n * faro.api.setUser(user);\n * }\n *\n * // Save user when logged in\n * const loggedInUser = { id: '123', email: 'user@example.com' };\n * await persistence.saveUser(loggedInUser);\n *\n * // Clear on logout\n * await persistence.clearUser();\n * ```\n */\nexport class AsyncStorageUserPersistence implements UserPersistence {\n private readonly storageKey: string;\n\n constructor(options: UserPersistenceOptions = {}) {\n this.storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n }\n\n async loadUser(): Promise<MetaUser | null> {\n try {\n const userJson = await AsyncStorage.getItem(this.storageKey);\n if (userJson === null) {\n return null;\n }\n\n const userData = JSON.parse(userJson);\n if (!this.isValidMetaUser(userData)) {\n return null;\n }\n\n return userData;\n } catch {\n return null;\n }\n }\n\n async saveUser(user: MetaUser | null): Promise<void> {\n try {\n if (user === null || this.isCleared(user)) {\n await this.clearUser();\n return;\n }\n\n const userJson = JSON.stringify(user);\n await AsyncStorage.setItem(this.storageKey, userJson);\n } catch {\n // Log failure but don't throw\n }\n }\n\n async clearUser(): Promise<void> {\n try {\n await AsyncStorage.removeItem(this.storageKey);\n } catch {\n // Log failure but don't throw\n }\n }\n\n async hasPersistedUser(): Promise<boolean> {\n try {\n const userJson = await AsyncStorage.getItem(this.storageKey);\n return userJson !== null;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if user is cleared (all fields empty/undefined).\n */\n private isCleared(user: MetaUser): boolean {\n return !user.id && !user.email && !user.username && !user.fullName && !user.roles;\n }\n\n /**\n * Validate that the parsed object is a valid MetaUser.\n */\n private isValidMetaUser(obj: unknown): obj is MetaUser {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n\n // MetaUser has optional string fields, so any object is technically valid\n // We just need to make sure it's an object\n return true;\n }\n}\n\n/**\n * Factory function to create a UserPersistence instance.\n */\nexport function createUserPersistence(options: UserPersistenceOptions = {}): UserPersistence {\n return new AsyncStorageUserPersistence(options);\n}\n\n/**\n * Global user persistence instance.\n */\nlet globalUserPersistence: UserPersistence | null = null;\n\n/**\n * Initialize the global user persistence.\n */\nexport function initializeUserPersistence(options: UserPersistenceOptions = {}): UserPersistence {\n globalUserPersistence = createUserPersistence(options);\n return globalUserPersistence;\n}\n\n/**\n * Get the global user persistence instance.\n */\nexport function getUserPersistence(): UserPersistence | null {\n return globalUserPersistence;\n}\n\n/**\n * Set a custom user persistence instance.\n */\nexport function setUserPersistence(persistence: UserPersistence | null): void {\n globalUserPersistence = persistence;\n}\n"]}
@@ -3,8 +3,7 @@ import type { ReactNativeConfig } from './types';
3
3
  /**
4
4
  * Returns the default set of instrumentations for React Native.
5
5
  *
6
- * Reads all options from the Faro config (single source of truth).
7
- * Property names are aligned with Flutter SDK FaroConfig:
6
+ * Reads all options from the Faro config (single source of truth):
8
7
  * - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals
9
8
  * - enableCrashReporting, enableErrorReporting
10
9
  * - fetchVitalsInterval, ignoreUrls
@@ -6,9 +6,6 @@ import type { Meta } from '@grafana/faro-core';
6
6
  * allowing sampling decisions based on session attributes, user info, app
7
7
  * environment, and other metadata.
8
8
  *
9
- * This aligns with the Faro Flutter SDK's `SamplingContext` which provides
10
- * `meta` to the sampler.
11
- *
12
9
  * @example
13
10
  * ```ts
14
11
  * sampling: SamplingFunction((context) => {
@@ -5,11 +5,13 @@ import type { PreloadedMobileMeta, SessionAttributes } from '../instrumentations
5
5
  import type { Sampling } from './sampling';
6
6
  /**
7
7
  * React Native session tracking config.
8
- * Extends Config['sessionTracking'] with sampling (Flutter-style) and RN-specific props.
8
+ * Extends Config['sessionTracking'] with sampling and RN-specific props.
9
9
  * Excludes samplingRate and sampler in favor of sampling.
10
10
  *
11
- * When `persistent` is true, sessions are stored with [react-native-mmkv](https://github.com/mrousavy/react-native-mmkv)
12
- * (synchronous). Add `react-native-mmkv` to your app and rebuild native projects.
11
+ * Persistence defaults to true and stores a minimal, versioned record with
12
+ * [react-native-mmkv](https://github.com/mrousavy/react-native-mmkv) (synchronous).
13
+ * Add `react-native-mmkv` to your app and rebuild native projects, or set
14
+ * `persistent` to false to use in-memory sessions.
13
15
  */
14
16
  export type ReactNativeSessionTrackingConfig = Omit<NonNullable<Config['sessionTracking']>, 'samplingRate' | 'sampler'> & {
15
17
  /**
@@ -5,8 +5,7 @@ import type { DataCollectionPolicy, DataCollectionPolicyOptions } from './types'
5
5
  * Controls whether telemetry data is collected and sent.
6
6
  * The setting is persisted to AsyncStorage so it survives app restarts.
7
7
  *
8
- * Implementation follows Flutter SDK's DataCollectionPolicy pattern:
9
- * - Uses AsyncStorage for persistence (matching Flutter's SharedPreferences)
8
+ * Uses AsyncStorage for persisting data collection policy state.
10
9
  * - Provides enable/disable methods
11
10
  * - Initializes from persisted value or default
12
11
  *
@@ -2,4 +2,4 @@
2
2
  * NPM package identity for this build. Generated by scripts/sync-faro-rn-package-meta.mjs - do not edit.
3
3
  */
4
4
  export declare const FARO_REACT_NATIVE_NPM_NAME: "@grafana/faro-react-native";
5
- export declare const FARO_REACT_NATIVE_NPM_VERSION: "1.3.1";
5
+ export declare const FARO_REACT_NATIVE_NPM_VERSION: "1.4.0";
@@ -6,7 +6,9 @@ export { getRNInstrumentations } from './config/getRNInstrumentations';
6
6
  export { ErrorMechanism, ErrorsInstrumentation } from './instrumentations/errors';
7
7
  export type { ErrorMechanismType, ErrorsInstrumentationOptions } from './instrumentations/errors';
8
8
  export { ConsoleInstrumentation } from './instrumentations/console';
9
- export { SessionInstrumentation } from './instrumentations/session';
9
+ export { startNewSession, SessionInstrumentation } from './instrumentations/session';
10
+ export { FaroSessionActivityBoundary, type FaroSessionActivityBoundaryProps, } from './instrumentations/session/FaroSessionActivityBoundary';
11
+ export { notifySessionActivity } from './instrumentations/session/directSessionActivity';
10
12
  export { getSessionAttributes, loadMobileMetaForInit, loadSessionDeviceAttributesForInit, minimalSessionDeviceAttributes, } from './instrumentations/session/sessionAttributes';
11
13
  export type { PreloadedMobileMeta, SessionAttributes } from './instrumentations/session/sessionAttributes';
12
14
  export { ViewInstrumentation } from './instrumentations/view';
@@ -35,6 +37,7 @@ export { getPageMeta } from './metas/page';
35
37
  export { getScreenMeta } from './metas/screen';
36
38
  export { getSdkMeta } from './metas/sdk';
37
39
  export { FetchTransport } from './transports/fetch';
40
+ export type { FetchTransportSendOutcome, FetchTransportSendResult } from './transports/fetch';
38
41
  export { ConsoleTransport } from './transports/console';
39
42
  export type { ConsoleTransportOptions } from './transports/console';
40
43
  export { OfflineTransport } from './transports/offline';
@@ -1,5 +1,12 @@
1
+ import { NativeModules } from 'react-native';
1
2
  import { BaseInstrumentation } from '@grafana/faro-core';
3
+ import type { ExceptionStackFrame } from '@grafana/faro-core';
2
4
  import type { CrashReport, CrashReportingOptions } from './types';
5
+ interface CrashReportDetails {
6
+ context: Record<string, string>;
7
+ errorMessage: string;
8
+ stackFrames: ExceptionStackFrame[];
9
+ }
3
10
  /**
4
11
  * Abstract base class for platform-specific crash reporting implementations.
5
12
  *
@@ -44,13 +51,16 @@ export declare abstract class BaseCrashReportingInstrumentation extends BaseInst
44
51
  * Platform-specific: Get warning message when trace is unavailable.
45
52
  */
46
53
  protected abstract getTraceUnavailableWarning(): string;
47
- private waitForSessionAttributes;
48
- private getNativeModule;
49
- private processCrashReports;
50
- private sendCrashReport;
54
+ protected prepareCrashReporting(_nativeModule: typeof NativeModules.FaroReactNativeModule): void | Promise<void>;
55
+ protected waitForSessionAttributes(maxWaitMs?: number): Promise<void>;
56
+ protected getNativeModule(): typeof NativeModules.FaroReactNativeModule | null;
57
+ protected processCrashReports(nativeModule: typeof NativeModules.FaroReactNativeModule): Promise<void>;
58
+ protected buildCrashReportDetails(crash: CrashReport): CrashReportDetails;
59
+ protected sendCrashReport(crash: CrashReport): void;
51
60
  logDebug(message: string, ...args: any[]): void;
52
61
  logInfo(message: string, ...args: any[]): void;
53
62
  logWarn(message: string, ...args: any[]): void;
54
63
  logError(message: string, ...args: any[]): void;
55
64
  unpatch(): void;
56
65
  }
66
+ export {};
@@ -0,0 +1,27 @@
1
+ import { NativeModules } from 'react-native';
2
+ import { BaseCrashReportingInstrumentation } from './BaseCrashReportingInstrumentation';
3
+ /**
4
+ * Shared recovered-crash delivery contract for native platforms.
5
+ *
6
+ * Native code owns crash-time persistence. JavaScript owns validation, transport
7
+ * acceptance, and acknowledgement so retryable failures never delete a report.
8
+ */
9
+ export declare abstract class RecoveredCrashReportingInstrumentation extends BaseCrashReportingInstrumentation {
10
+ private nativeModule;
11
+ private supportsSessionReplay;
12
+ private metasListenerRegistered;
13
+ private lastRecordedSessionSignature;
14
+ private activeSessionId;
15
+ private activeSessionActivatedAtMs;
16
+ private activeSessionIsSampled;
17
+ private readonly recordSessionContextListener;
18
+ protected prepareCrashReporting(nativeModule: typeof NativeModules.FaroReactNativeModule): void;
19
+ protected processCrashReports(nativeModule: typeof NativeModules.FaroReactNativeModule): Promise<void>;
20
+ private recordSessionContext;
21
+ private replayCrashReport;
22
+ private buildRecoveredCrashItem;
23
+ private acknowledgeCrashReport;
24
+ private hasValidTimestamp;
25
+ private isWithinReplayWindow;
26
+ unpatch(): void;
27
+ }
@@ -1,4 +1,4 @@
1
- import { BaseCrashReportingInstrumentation } from '../BaseCrashReportingInstrumentation';
1
+ import { RecoveredCrashReportingInstrumentation } from '../RecoveredCrashReportingInstrumentation';
2
2
  import type { CrashReport } from '../types';
3
3
  import { type ParsedAndroidCrashTrace } from './parseAndroidCrashTrace';
4
4
  /**
@@ -13,7 +13,7 @@ import { type ParsedAndroidCrashTrace } from './parseAndroidCrashTrace';
13
13
  *
14
14
  * ANRs are reported separately by ANRInstrumentation, not via ApplicationExitInfo replay.
15
15
  */
16
- export declare class AndroidCrashReportingInstrumentation extends BaseCrashReportingInstrumentation {
16
+ export declare class AndroidCrashReportingInstrumentation extends RecoveredCrashReportingInstrumentation {
17
17
  readonly name = "@grafana/faro-react-native:instrumentation-crash-android";
18
18
  readonly version = "2.8.2";
19
19
  protected parseCrashTrace(trace: string): ParsedAndroidCrashTrace | null;
@@ -1,4 +1,4 @@
1
- import { BaseCrashReportingInstrumentation } from '../BaseCrashReportingInstrumentation';
1
+ import { RecoveredCrashReportingInstrumentation } from '../RecoveredCrashReportingInstrumentation';
2
2
  import type { CrashReport } from '../types';
3
3
  import { type ParsedIosCrashTrace } from './parseIosCrashTrace';
4
4
  /**
@@ -15,7 +15,7 @@ import { type ParsedIosCrashTrace } from './parseIosCrashTrace';
15
15
  *
16
16
  * Stack frames are symbolicated on the native side before being surfaced.
17
17
  */
18
- export declare class IosCrashReportingInstrumentation extends BaseCrashReportingInstrumentation {
18
+ export declare class IosCrashReportingInstrumentation extends RecoveredCrashReportingInstrumentation {
19
19
  readonly name = "@grafana/faro-react-native:instrumentation-crash-ios";
20
20
  readonly version = "2.8.2";
21
21
  protected parseCrashTrace(trace: string): ParsedIosCrashTrace | null;
@@ -2,6 +2,7 @@
2
2
  * Crash report data structure returned from native module.
3
3
  */
4
4
  export interface CrashReport {
5
+ reportId?: string;
5
6
  trace?: string;
6
7
  signal?: string;
7
8
  timestamp?: number;
@@ -11,6 +12,11 @@ export interface CrashReport {
11
12
  importance?: number;
12
13
  reason?: string;
13
14
  status?: number;
15
+ sessionId?: string;
16
+ isSampled?: boolean;
17
+ appVersion?: string;
18
+ appRelease?: string;
19
+ appBundleId?: string;
14
20
  }
15
21
  /**
16
22
  * Configuration options for crash reporting instrumentation.
@@ -14,7 +14,7 @@ import type { FrameMonitoringOptions } from './types';
14
14
  * - Reports meaningful performance degradation that affects user experience
15
15
  *
16
16
  * ## Frozen Frame Detection
17
- * Frozen frames are individual frames exceeding `frozenFrameThresholdMs` (default 100ms).
17
+ * Frozen frames are individual frames exceeding `frozenFrameThresholdMs` (default 700ms).
18
18
  * These represent severe jank where the app appears unresponsive.
19
19
  *
20
20
  * Sends measurements via Faro API:
@@ -31,7 +31,7 @@ import type { FrameMonitoringOptions } from './types';
31
31
  * instrumentations: [
32
32
  * new FrameMonitoringInstrumentation({
33
33
  * targetFps: 60,
34
- * frozenFrameThresholdMs: 100,
34
+ * frozenFrameThresholdMs: 700,
35
35
  * refreshRatePollingInterval: 30000,
36
36
  * }),
37
37
  * ],
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * Configuration options for Frame Monitoring instrumentation.
3
3
  *
4
- * These are React Native-specific advanced options. The Flutter SDK uses fixed values
5
- * for these parameters (not configurable). Defaults here match Flutter's hardcoded values
6
- * for cross-platform consistency.
4
+ * Frozen frame threshold (700ms).
7
5
  *
8
6
  * Note: To enable frame monitoring, set `refreshRateVitals: true` in ReactNativeConfig.
9
7
  */
@@ -11,13 +9,13 @@ export interface FrameMonitoringOptions {
11
9
  /**
12
10
  * Target frames per second for slow frame detection.
13
11
  * Frames rendering below this threshold are considered "slow".
14
- * Default: 60 (Flutter SDK hardcoded value)
12
+ * Default: 60
15
13
  */
16
14
  targetFps?: number;
17
15
  /**
18
16
  * Threshold in milliseconds for detecting frozen frames.
19
17
  * Frames taking longer than this are considered "frozen".
20
- * Default: 100ms (Flutter SDK uses 100_000_000 nanoseconds)
18
+ * Default: 700ms (Android Vitals and OpenTelemetry Android slow rendering instrumentation)
21
19
  */
22
20
  frozenFrameThresholdMs?: number;
23
21
  /**
@@ -28,7 +26,7 @@ export interface FrameMonitoringOptions {
28
26
  /**
29
27
  * Normalized refresh rate for ProMotion displays (120Hz, etc.).
30
28
  * Used to normalize frame rates for high-refresh-rate displays to a standard baseline.
31
- * Default: 60 (Flutter SDK's backendSupportedFrameRate)
29
+ * Default: 60
32
30
  */
33
31
  normalizedRefreshRate?: number;
34
32
  }
@@ -7,8 +7,6 @@ import type { PerformanceInstrumentationOptions } from './types';
7
7
  * - iOS: task_info() for memory, host_statistics() for CPU
8
8
  * - Android: /proc/[pid]/status for memory, /proc/[pid]/stat for CPU
9
9
  *
10
- * Implementation ported from Faro Flutter SDK with feature parity.
11
- *
12
10
  * **Key Features**:
13
11
  * - ✅ NO manual setup required - OS tracks metrics automatically!
14
12
  * - ✅ Periodic collection (default: every 30 seconds)
@@ -0,0 +1,8 @@
1
+ import { type PropsWithChildren } from 'react';
2
+ import { type ViewProps } from 'react-native';
3
+ export type FaroSessionActivityBoundaryProps = PropsWithChildren<ViewProps>;
4
+ /**
5
+ * Records touch activity for the React Native subtree without emitting a user
6
+ * action or taking ownership of the responder.
7
+ */
8
+ export declare function FaroSessionActivityBoundary({ children, onStartShouldSetResponderCapture, style, ...viewProps }: FaroSessionActivityBoundaryProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ type DirectSessionActivityHandler = () => void;
2
+ /** Clears a handler left by a previous SDK initialization. */
3
+ export declare function clearDirectSessionActivityHandler(): void;
4
+ /** Registers the active session manager as the direct-activity consumer. */
5
+ export declare function registerDirectSessionActivityHandler(handler: DirectSessionActivityHandler): () => void;
6
+ /**
7
+ * Refreshes session inactivity without emitting telemetry.
8
+ *
9
+ * This is a no-op until session tracking has initialized. Use it for direct
10
+ * interactions that do not pass through `FaroSessionActivityBoundary`.
11
+ */
12
+ export declare function notifySessionActivity(): void;
13
+ export {};
@@ -1,4 +1,13 @@
1
1
  import { BaseInstrumentation } from '@grafana/faro-core';
2
+ /**
3
+ * Starts a new linked session at an application-defined boundary.
4
+ *
5
+ * Call this after changing or clearing the current user for logout, account
6
+ * changes, or another boundary that must not share a session. Calls made
7
+ * before Faro initializes, after teardown, or while session tracking is
8
+ * disabled have no effect.
9
+ */
10
+ export declare function startNewSession(): void;
2
11
  /**
3
12
  * Session instrumentation for React Native
4
13
  * Manages persistent or volatile sessions with expiration and inactivity tracking
@@ -8,13 +17,23 @@ export declare class SessionInstrumentation extends BaseInstrumentation {
8
17
  readonly version = "2.8.2";
9
18
  private notifiedSession;
10
19
  private sessionManagerInstance;
20
+ private isResettingSession;
21
+ private unregisterDirectSessionActivity;
22
+ private sessionMetaListenerMetas;
23
+ private beforeSendHookApi;
24
+ private beforeSendHook;
25
+ private beforeSendHookTransports;
11
26
  private getDefaultSessionDeviceAttributes;
12
- private sendSessionStartEvent;
27
+ private readonly sendSessionStartEvent;
28
+ private registerSessionMetaListener;
13
29
  private createInitialSession;
14
30
  private registerBeforeSendHook;
15
31
  initialize(): void;
32
+ /** Starts a new linked session immediately. */
33
+ startNewSession(): void;
16
34
  /**
17
35
  * Clean up session manager listeners
18
36
  */
19
37
  unpatch(): void;
38
+ destroy(): void;
20
39
  }
@@ -0,0 +1,9 @@
1
+ import type { TransportItem } from '@grafana/faro-core';
2
+ export declare enum SessionActivityKind {
3
+ Meaningful = "meaningful",
4
+ Passive = "passive"
5
+ }
6
+ /** Classifies how a transport item affects the session inactivity window. */
7
+ export declare function classifySessionActivity(item: TransportItem): SessionActivityKind;
8
+ /** Recovered crashes keep the session captured by the previous process. */
9
+ export declare function isRecoveredCrashItem(item: TransportItem, currentSessionId: string | undefined): boolean;
@@ -3,8 +3,8 @@ import type { Meta } from '@grafana/faro-core';
3
3
  * Session attributes for React Native
4
4
  * These attributes are automatically included with every telemetry event
5
5
  *
6
- * Core attributes match Flutter SDK format, with additional mobile-specific
7
- * monitoring fields (memory, device type, battery, etc.)
6
+ * Core mobile session attributes, with additional monitoring fields
7
+ * (memory, device type, battery, etc.)
8
8
  *
9
9
  * SDK name, core version, and npm adapter are on Faro meta `sdk` (`getSdkMeta` in `metas/sdk.ts`).
10
10
  *
@@ -13,6 +13,8 @@ import type { Meta } from '@grafana/faro-core';
13
13
  export interface SessionAttributes {
14
14
  /** Host app's React Native framework version (e.g. "0.75.1") from `Platform.constants`. */
15
15
  react_native_version: string;
16
+ /** Stable Android process name or Apple bundle identifier for this runtime. */
17
+ process_name?: string;
16
18
  /** Operating system ("iOS" or "Android") */
17
19
  device_os?: string;
18
20
  /** OS version (e.g., "17.0" for iOS, "15" for Android) */
@@ -59,8 +61,9 @@ export declare function minimalSessionDeviceAttributes(): SessionAttributes;
59
61
  * Get all session attributes
60
62
  * These attributes are automatically included with every telemetry event
61
63
  *
62
- * Core attributes matching Flutter SDK:
64
+ * Core session attributes:
63
65
  * - react_native_version (RN framework in the host app)
66
+ * - process_name (Android process name or iOS bundle identifier)
64
67
  * - device_os, device_os_version, device_os_detail
65
68
  * - device_manufacturer, device_model, device_model_name
66
69
  * - device_brand, device_is_physical, device_id
@@ -1,3 +1,5 @@
1
+ import type { Metas } from '@grafana/faro-core';
2
+ import { SessionActivityKind } from '../sessionActivity';
1
3
  import type { FaroUserSession } from './types';
2
4
  /** @internal */
3
5
  export declare function resetMmkvSingletonForTests(): void;
@@ -6,14 +8,25 @@ export declare function resetMmkvSingletonForTests(): void;
6
8
  * Used when `sessionTracking.persistent` is true.
7
9
  */
8
10
  export declare class MmkvPersistentSessionsManager {
11
+ private resetUserSession;
9
12
  private updateUserSession;
10
13
  private appStateSubscription;
11
- private metaUnsubscribe;
12
- constructor();
14
+ private activityWriteTimer;
15
+ private hasPendingActivityWrite;
16
+ private lastActivityWrite;
17
+ private wasBackgrounded;
18
+ private metaUpdateHandler;
19
+ private readonly metas;
20
+ constructor(metas?: Metas);
13
21
  static removeUserSession(): void;
14
22
  static storeUserSession(session: FaroUserSession): void;
23
+ private static setRuntimeSession;
24
+ private static persistSession;
15
25
  static fetchUserSession(): FaroUserSession | null;
16
- updateSession: () => Promise<void>;
26
+ checkSession(activity: SessionActivityKind, currentSession?: FaroUserSession | null): FaroUserSession;
27
+ resetSession(): FaroUserSession;
28
+ private flushActivityWrite;
29
+ private recordUserSessionActivity;
17
30
  private handleAppStateChange;
18
31
  private init;
19
32
  unpatch(): void;
@@ -1,14 +1,20 @@
1
+ import type { Metas } from '@grafana/faro-core';
2
+ import { SessionActivityKind } from '../sessionActivity';
1
3
  import type { FaroUserSession } from './types';
2
4
  export declare class VolatileSessionsManager {
3
5
  private static volatileStorage;
6
+ private resetUserSession;
4
7
  private updateUserSession;
5
8
  private appStateSubscription;
6
- private metaUnsubscribe;
7
- constructor();
9
+ private wasBackgrounded;
10
+ private metaUpdateHandler;
11
+ private readonly metas;
12
+ constructor(metas?: Metas);
8
13
  static removeUserSession(): void;
9
14
  static storeUserSession(session: FaroUserSession): void;
10
15
  static fetchUserSession(): FaroUserSession | null;
11
- updateSession: () => Promise<void>;
16
+ checkSession(activity: SessionActivityKind, currentSession?: FaroUserSession | null): FaroUserSession;
17
+ resetSession(): FaroUserSession;
12
18
  private handleAppStateChange;
13
19
  private init;
14
20
  /**
@@ -0,0 +1,4 @@
1
+ import type { FaroUserSession } from './types';
2
+ export declare const PERSISTED_SESSION_SCHEMA_VERSION = 1;
3
+ export declare function serializePersistentSession(session: FaroUserSession): string;
4
+ export declare function parsePersistentSession(serialized: string): FaroUserSession | null;
@@ -1,4 +1,5 @@
1
- import type { Meta } from '@grafana/faro-core';
1
+ import type { Meta, MetaSession } from '@grafana/faro-core';
2
+ import { SessionActivityKind } from '../sessionActivity';
2
3
  import type { FaroUserSession } from './types';
3
4
  type CreateUserSessionObjectParams = {
4
5
  sessionId?: string;
@@ -9,14 +10,25 @@ type CreateUserSessionObjectParams = {
9
10
  export declare function createUserSessionObject({ sessionId, started, lastActivity, isSampled: sampledValue, }?: CreateUserSessionObjectParams): FaroUserSession;
10
11
  export declare function isUserSessionValid(session: FaroUserSession | null): boolean;
11
12
  type GetUserSessionUpdaterParams = {
12
- storeUserSession: (session: FaroUserSession) => void | Promise<void>;
13
- fetchUserSession: () => FaroUserSession | null | Promise<FaroUserSession | null>;
13
+ storeUserSession: (session: FaroUserSession) => void;
14
+ fetchUserSession: () => FaroUserSession | null;
15
+ recordUserSessionActivity?: (session: FaroUserSession) => void;
14
16
  };
15
- export declare function getUserSessionUpdater({ fetchUserSession, storeUserSession, }: GetUserSessionUpdaterParams): () => Promise<void>;
17
+ type GetUserSessionResetterParams = Pick<GetUserSessionUpdaterParams, 'fetchUserSession' | 'storeUserSession'>;
18
+ export declare function getUserSessionResetter({ fetchUserSession, storeUserSession, }: GetUserSessionResetterParams): () => FaroUserSession;
19
+ export declare function getUserSessionUpdater({ fetchUserSession, recordUserSessionActivity, storeUserSession, }: GetUserSessionUpdaterParams): (activity: SessionActivityKind, currentSession?: FaroUserSession | null) => FaroUserSession;
20
+ /**
21
+ * Persistent storage serializes sessions with `stringifyExternalJson`, which
22
+ * drops keys whose value is `undefined`. A session meta carrying such a key
23
+ * never compares `deepEqual` to its own stored copy, so the sync handler would
24
+ * rewrite the session on every meta notification. Applying the same round-trip
25
+ * in memory keeps the two sides comparable, for attributes and overrides alike.
26
+ */
27
+ export declare function toStorableSessionMeta(sessionMeta: MetaSession): MetaSession;
16
28
  export declare function addSessionMetadataToNextSession(newSession: FaroUserSession, previousSession: FaroUserSession | null): Required<FaroUserSession>;
17
29
  type GetUserSessionMetaUpdateHandlerParams = {
18
- storeUserSession: (session: FaroUserSession) => void | Promise<void>;
19
- fetchUserSession: () => FaroUserSession | null | Promise<FaroUserSession | null>;
30
+ storeUserSession: (session: FaroUserSession) => void;
31
+ fetchUserSession: () => FaroUserSession | null;
20
32
  };
21
- export declare function getSessionMetaUpdateHandler({ fetchUserSession, storeUserSession, }: GetUserSessionMetaUpdateHandlerParams): (meta: Meta) => Promise<void>;
33
+ export declare function getSessionMetaUpdateHandler({ fetchUserSession, storeUserSession, }: GetUserSessionMetaUpdateHandlerParams): (meta: Meta) => void;
22
34
  export {};
@@ -1,4 +1,5 @@
1
1
  import type { MetaSession } from '@grafana/faro-core';
2
+ import type { SessionActivityKind } from '../sessionActivity';
2
3
  import type { MmkvPersistentSessionsManager } from './MmkvPersistentSessionsManager';
3
4
  import type { VolatileSessionsManager } from './VolatileSessionManager';
4
5
  export interface FaroUserSession {
@@ -9,3 +10,8 @@ export interface FaroUserSession {
9
10
  sessionMeta?: MetaSession;
10
11
  }
11
12
  export type SessionManager = typeof VolatileSessionsManager | typeof MmkvPersistentSessionsManager;
13
+ export interface SessionManagerInstance {
14
+ checkSession(activity: SessionActivityKind, currentSession?: FaroUserSession | null): FaroUserSession;
15
+ resetSession(): FaroUserSession;
16
+ unpatch(): void;
17
+ }
@@ -0,0 +1,17 @@
1
+ export declare const MAIN_PROCESS_SESSION_STORAGE_ID = "grafana-faro-react-native-session";
2
+ export interface SessionProcessInfo {
3
+ identifier: string;
4
+ isMain: boolean;
5
+ }
6
+ /** Stable native process identity used to isolate session chains. */
7
+ export declare function getSessionProcessInfo(): SessionProcessInfo | null;
8
+ /**
9
+ * Returns the MMKV instance ID owned by this runtime, or null when exclusive
10
+ * ownership cannot be established. The main process retains the legacy ID so
11
+ * upgrades keep their existing previous-session link.
12
+ */
13
+ export declare function claimSessionPersistenceStorageId(): string | null;
14
+ /** Releases storage ownership after MMKV initialization fails. */
15
+ export declare function releaseSessionPersistenceOwnership(): boolean;
16
+ /** @internal */
17
+ export declare function resetSessionProcessForTests(): void;
@@ -7,15 +7,12 @@ import type { StartupInstrumentationOptions } from './types';
7
7
  * - iOS: sysctl() to query kernel for process start time
8
8
  * - Android: Process.getStartElapsedRealtime() from Android OS (API 24+)
9
9
  *
10
- * Implementation aligned with Faro Flutter SDK:
11
- * https://github.com/grafana/faro-flutter-sdk
12
- *
13
10
  * **Key Features**:
14
11
  * - ✅ NO AppDelegate/MainActivity setup required - OS tracks process start automatically!
15
12
  * - ✅ Cold start: appStartDuration from native, coldStart: 1
16
13
  * - ✅ Warm start: appStartDuration (time to first frame after resume), coldStart: 0
17
14
  *
18
- * **Metrics Captured** (matches Flutter SDK format):
15
+ * **Metrics Captured**:
19
16
  * - Cold start: `appStartDuration`, `coldStart: 1`
20
17
  * - Warm start: `appStartDuration`, `coldStart: 0`
21
18
  *
@@ -45,12 +42,11 @@ export declare class StartupInstrumentation extends BaseInstrumentation {
45
42
  initialize(): void;
46
43
  /**
47
44
  * Captures cold start duration from native (process start to Faro init).
48
- * Matches Flutter SDK: appStartDuration + coldStart: 1
45
+ * Sends appStartDuration with coldStart: 1.
49
46
  */
50
47
  private captureColdStartMetrics;
51
48
  /**
52
49
  * Tracks warm start: when app resumes from background, measures time to first frame.
53
- * Matches Flutter SDK: setWarmStart on resume, getWarmStart after postFrameCallback.
54
50
  */
55
51
  private setupWarmStartTracking;
56
52
  unpatch(): void;
@@ -1,4 +1,5 @@
1
1
  import type { NavigationState, PartialState, Route } from '@react-navigation/native';
2
+ export declare const EVENT_NAVIGATION = "navigation";
2
3
  /**
3
4
  * Gets the currently active route from navigation state
4
5
  */
@@ -1,2 +1,2 @@
1
1
  export { FetchTransport } from './transport';
2
- export type { FetchTransportOptions, FetchTransportRequestOptions } from './types';
2
+ export type { FetchTransportOptions, FetchTransportRequestOptions, FetchTransportSendOutcome, FetchTransportSendResult, } from './types';
@@ -1,6 +1,6 @@
1
1
  import { BaseTransport } from '@grafana/faro-core';
2
2
  import type { Patterns, PromiseBuffer, TransportItem } from '@grafana/faro-core';
3
- import type { FetchTransportOptions } from './types';
3
+ import type { FetchTransportOptions, FetchTransportSendResult } from './types';
4
4
  export declare class FetchTransport extends BaseTransport {
5
5
  private options;
6
6
  readonly name = "@grafana/faro-react-native:transport-fetch";
@@ -28,6 +28,13 @@ export declare class FetchTransport extends BaseTransport {
28
28
  */
29
29
  private waitForSession;
30
30
  send(items: TransportItem[]): Promise<void>;
31
+ /**
32
+ * Sends a batch and reports whether the collector accepted it.
33
+ * The request header uses the live session for collector accounting. Payload
34
+ * metadata remains independent so delayed signals can retain their original
35
+ * session.
36
+ */
37
+ sendWithResult(items: TransportItem[]): Promise<FetchTransportSendResult>;
31
38
  getIgnoreUrls(): Patterns;
32
39
  isBatched(): boolean;
33
40
  private getRetryAfterDate;
@@ -11,3 +11,8 @@ export interface FetchTransportOptions {
11
11
  requestOptions?: FetchTransportRequestOptions;
12
12
  }
13
13
  export type ClockFn = () => number;
14
+ export type FetchTransportSendOutcome = 'accepted' | 'rejected' | 'failed' | 'skipped';
15
+ export interface FetchTransportSendResult {
16
+ outcome: FetchTransportSendOutcome;
17
+ status?: number;
18
+ }
@@ -5,7 +5,7 @@ import type { ConnectivityService } from './types';
5
5
  * Uses @react-native-community/netinfo when available, otherwise falls back
6
6
  * to basic fetch-based connectivity detection.
7
7
  *
8
- * Implementation follows Flutter SDK's InternetConnectivityService pattern.
8
+ * Monitors network connectivity for offline transport flush behavior.
9
9
  */
10
10
  export declare class DefaultConnectivityService implements ConnectivityService {
11
11
  private _isOnline;